`Programming Guide
`
`Smartflash - Exhibit 2026
`Apple v. Smartflash
`CBM2014-00106
`
`
`
`Contents
`
`About In-App Purchase 5
`At a Glance 6
`You Create and Configure Products in iTunes Connect 6
`Your App Interacts with the App Store to Sell Products 6
`Subscriptions Require Additional Application Logic 7
`Users Can Restore Purchases 7
`Apps and Products Are Submitted for Review 7
`See Also 7
`
`Designing Your App’s Products 8
`Understanding What You Can Sell Using In-App Purchase 8
`Creating Products in iTunes Connect 9
`Product Types 9
`Differences Between Product Types 10
`
`Retrieving Product Information 12
`Getting a List of Product Identifiers 12
`Embedding Product IDs in the App Bundle 13
`Fetching Product IDs from Your Server 13
`Retrieving Product Information 15
`Presenting Your App’s Store UI 16
`Suggested Testing Steps 17
`Sign In to the App Store with Your Test Account 18
`Test Fetching the List of Product Identifiers 18
`Test Handling of Invalid Product Identifiers 18
`Test a Products Request 19
`
`Requesting Payment 20
`Creating a Payment Request 20
`Detecting Irregular Activity 21
`Submitting a Payment Request 22
`
`Delivering Products 23
`Waiting for the App Store to Process Transactions 23
`
`2013-10-22 | Copyright © 2013 Apple Inc. All Rights Reserved.
`
`2
`
`
`
`Contents
`
`Persisting the Purchase 26
`Persisting Using the App Receipt 27
`Persisting a Value in User Defaults or iCloud 27
`Persisting a Receipt in User Defaults or iCloud 27
`Persisting Using Your Own Server 28
`Unlocking App Functionality 28
`Delivering Associated Content 29
`Loading Local Content 30
`Downloading Hosted Content from Apple’s Server 30
`Downloading Content from Your Own Server 31
`Finishing the Transaction 32
`Suggested Testing Steps 33
`Test a Payment Request 33
`Verify Your Observer Code 33
`Test a Successful Transaction 33
`Test an Interrupted Transaction 34
`Verify That Transactions Are Finished 34
`
`Working with Subscriptions 35
`Calculating a Subscription’s Active Period 35
`Expiration and Renewal 37
`Cancellation 38
`Cross-Platform Considerations 38
`Letting Users Manage Subscriptions 38
`The Test Environment 38
`
`Restoring Purchased Products 40
`Refreshing the App Receipt 41
`Restoring Completed Transactions 41
`
`Preparing for App Review 43
`Submitting Products for Review 43
`Receipts in the Test Environment 43
`Implementation Checklist 44
`
`Document Revision History 46
`
`2013-10-22 | Copyright © 2013 Apple Inc. All Rights Reserved.
`
`3
`
`
`
`Figures, Tables, and Listings
`
`About In-App Purchase 5
`Figure I-1
`Stages of the purchase process 6
`
`Designing Your App’s Products 8
`Table 1-1
`Comparison of product types 10
`Table 1-2
`Comparison of subscription types 10
`
`Retrieving Product Information 12
`Figure 2-1
`Stages of the purchase process—displaying store UI 12
`Table 2-1
`Comparison of approaches for obtaining product identifiers 12
`Listing 2-1
`Fetching product identifiers from your server 14
`Listing 2-2
`Retrieving product information 15
`Listing 2-3
`Formatting a product’s price 17
`
`Requesting Payment 20
`Figure 3-1
`Stages of the purchase process—requesting payment 20
`Listing 3-1
`Creating a payment request 20
`Listing 3-2
`Providing an application username 21
`
`Delivering Products 23
`Figure 4-1
`Stages of the purchase process—delivering products 23
`Table 4-1
`Transaction statuses and corresponding actions 24
`Listing 4-1
`Registering the transaction queue observer 24
`Listing 4-2
`Responding to transaction statuses 25
`Listing 4-3
`Excluding downloaded content from backups 31
`
`Working with Subscriptions 35
`Figure 5-1
`Example subscription timeline 35
`Table 5-1
`Timeline of a sample subscription 35
`
`Preparing for App Review 43
`Figure 7-1
`Development, review, and production environments 43
`
`2013-10-22 | Copyright © 2013 Apple Inc. All Rights Reserved.
`
`4
`
`
`
`About In-App Purchase
`
`In-App Purchase allows you to embed a store inside your app using the Store Kit framework. This framework
`connects to the App Store on your app’s behalf to securely process payments from users, prompting them to
`authorize payment. The framework then notifies your app, which provides the purchased items to users. Use
`In-App Purchase to collect payment for additional features and content.
`
`For example, using In-App Purchase, you can implement the following scenarios:
`
` ● A basic version of your app with additional premium features
`
` ● A magazine app that lets users purchase and download new issues
`
` ● A game that offers new levels to explore
`
` ● An online game that allows players to purchase virtual property
`
`2013-10-22 | Copyright © 2013 Apple Inc. All Rights Reserved.
`
`5
`
`
`
`About In-App Purchase
`At a Glance
`
`At a Glance
`At a high level, the interactions between the user, your app, and the App Store during the In-App Purchase
`process take place in three stages, as shown in Figure I-1. First, the user navigates to your app’s store and your
`app displays its products. Second, the user selects a product to buy and the app requests payment from the
`App Store. Third, the App Store processes the payment and your app delivers the purchased product.
`
`Figure I-1
`
`Stages of the purchase process
`
`You Create and Configure Products in iTunes Connect
`Understanding what kinds of products and behaviors are supported by In-App Purchase lets you design your
`app and in-app store to make the best use of this technology.
`
`Relevant Chapter: Designing Your App’s Products (page 8)
`
`Your App Interacts with the App Store to Sell Products
`All apps that use In-App Purchase need to implement the core functionality described in these chapters to let
`users make purchases and then deliver the purchased products.
`
`These development tasks need to be done in order. The relevant chapters introduce them in the order you
`implement them, and they’re listed in full in Implementation Checklist (page 44). To help plan your development,
`you may want to read the full checklist before you begin.
`
`2013-10-22 | Copyright © 2013 Apple Inc. All Rights Reserved.
`
`6
`
`
`
`About In-App Purchase
`See Also
`
`Relevant Chapters: Retrieving Product Information (page 12), Requesting Payment (page 20),
`Delivering Products (page 23)
`
`Subscriptions Require Additional Application Logic
`Apps that offer subscriptions need to keep track of when the user has an active subscription, respond to
`expiration and renewal, and determine what content the user has access to.
`
`Relevant Chapter: Working with Subscriptions (page 35)
`
`Users Can Restore Purchases
`Users can restore products that they previously purchased—for example, to bring content they’ve already paid
`for onto their new phone.
`
`Relevant Chapter: Restoring Purchased Products (page 40)
`
`Apps and Products Are Submitted for Review
`When you’re done developing and testing, you submit your app and your In-App Purchase products for review.
`
`Relevant Chapter: Preparing for App Review (page 43)
`
`See Also
`In-App Purchase Configuration Guide for iTunes Connect describes how to create and configure your app’s
`products in iTunes Connect.
`
` ●
`
` ●
`
` ●
`
`App Distribution Quick Start describes how to enable In-App purchase for your app.
`
`Receipt Validation Programming Guide describes how to work with receipts, in particular with the record
`of successful in-app purchases.
`
`2013-10-22 | Copyright © 2013 Apple Inc. All Rights Reserved.
`
`7
`
`
`
`Designing Your App’s Products
`
`A product is something you want to sell in your app’s store. You create and configure products in iTunes
`Connect, and your app interacts with products using the SKProduct and SKProductsRequest classes.
`
`Understanding What You Can Sell Using In-App Purchase
`You can use In-App Purchase to sell content, app functionality, and services.
`
` ●
`
`Content. Deliver digital content or assets, such as magazines, photos, and artwork. Content can also be
`used by the app itself—for example, additional characters and levels in a game, filters in a camera app,
`and stationery in a word processor.
`
` ● App functionality. Unlock behavior and expand features you’ve already delivered. Examples include a
`free game that offers multiplayer mode as an in-app purchase and a free weather app that lets users make
`a one-time purchase to remove ads.
`
` ●
`
`Services. Have users pay for one-time services such as voice transcription and for ongoing services such
`as access to a collection of data.
`
`You can’t use In-App Purchase to sell real-world goods and services or to sell unsuitable content.
`
` ●
`
`Real-world goods and services. You must deliver a digital good or service within your app when using
`In-App Purchase. Use a different payment mechanism to let your users buy real-world goods and services
`in your app, such as a credit card or payment service.
`
` ● Unsuitable content. Don’t use In-App Purchase to sell content that the isn’t allowed by the App Review
`Guidelines—for example, pornography, hate speech, or defamation.
`
`For detailed information about what you can offer using In-App Purchase, see your license agreement and the
`App Review Guidelines. Reviewing the guidelines carefully before you start coding helps you avoid delays and
`rejection during the review process. If the guidelines don’t address your case in sufficient detail, you can ask
`the App Review team specific questions using the online contact form.
`
`After you know what products you want to sell in your app and determine that In-App Purchase is the
`appropriate way to sell those products, you need to create the products in iTunes Connect.
`
`2013-10-22 | Copyright © 2013 Apple Inc. All Rights Reserved.
`
`8
`
`
`
`Designing Your App’s Products
`Creating Products in iTunes Connect
`
`Creating Products in iTunes Connect
`Before you start coding, you need to configure products in iTunes Connect for your app to interact with. As
`you develop your app, you can add and remove products and refine or reconfigure your existing products.
`
`Every product is associated with a specific app. Products created for use by one app are not available in other
`apps. Companion apps on a different platform are different apps—the products of the Mac app are not available
`in the iOS app and vice versa.
`
`Products are reviewed when you submit your app as part of the app review process. Before users can buy a
`product, it must be approved by the reviewer and you must mark it as “cleared for sale” in iTunes Connect.
`
`For step-be-step information about working with products in iTunes Connect, In-App Purchase Configuration
`Guide for iTunes Connect .
`
`Product Types
`Product types let you use In-App Purchase in a range of apps by providing several different product behaviors.
`In iTunes Connect, you select one of the following product types:
`
` ●
`
`Consumable products. Items that get used up over the course of running your app. Examples include
`minutes for a Voice over IP app and one-time services such as voice transcription.
`
` ● Non-consumable products. Items that remain available to the user indefinitely on all of the user’s devices.
`They’re made available to all of the user’s devices. Examples include content, such as books and game
`levels, and additional app functionality.
`
` ● Auto-renewable subscriptions. Episodic content. Like non-consumable products, auto-renewable
`subscriptions remain available to the user indefinitely on all of the user’s devices. Unlike non-consumable
`products, auto-renewable subscriptions have an expiration date. You deliver new content regularly, and
`users get access to content published during the time period their subscription is active. When an
`auto-renewable subscription is about to expire, the system automatically renews it on the user’s behalf.
`
` ● Non-renewable subscriptions. Subscriptions that don’t involve delivering episodic content. Examples
`include access to a database of historic photos or a collection of flight maps. It’s your app’s responsibility
`to make the subscription available on all of the user’s devices and to let users restore the purchase. This
`product type is often used when your users already have an account on your server that you can use to
`identify them when restoring content. Expiration and the duration of the subscription are also left to your
`app (or your server) to implement and enforce.
`
` ●
`
`Free subscriptions. A way to put free subscription content in Newsstand. After a user signs up for a free
`subscription, the content is available on all devices associated with the user’s Apple ID. Free subscriptions
`don’t expire and can be offered only in Newsstand-enabled apps.
`
`2013-10-22 | Copyright © 2013 Apple Inc. All Rights Reserved.
`
`9
`
`
`
`Designing Your App’s Products
`Differences Between Product Types
`
`Differences Between Product Types
`Each product type is designed for a particular use. The behavior of different product types varies in certain
`ways, as summarized in Table 1-1 and Table 1-2.
`
`Table 1-1
`
`Comparison of product types
`
`Product type
`
`Non-consumable
`
`Consumable
`
`Users can buy
`
`Once
`
`Multiple times
`
`Appears in the receipt
`
`Always
`
`Once
`
`Synced across devices
`
`By the system
`
`Not synced
`
`Restored
`
`By the system
`
`Not restored
`
`Table 1-2
`
`Comparison of subscription types
`
`Subscription type
`
`Auto-renewable
`
`Non-renewing
`
`Free
`
`Users can buy
`
`Multiple times
`
`Multiple times
`
`Once
`
`Appears in the receipt
`
`Always
`
`Once
`
`Always
`
`Synced across devices
`
`By the system
`
`By your app
`
`By the system
`
`Restored
`
`By the system
`
`By your app
`
`By the system
`
`Products that expire or get used up—consumable products, auto-renewable subscriptions, and non-renewing
`subscriptions—can be purchased multiple times to get the consumable item again or extend the subscription.
`Non-consumable products and free subscriptions unlock content that remains available to the user indefinitely,
`so these can only be purchased once.
`
`Consumable products and non-renewing subscriptions appear in the receipt after being purchased but are
`removed the next time the receipt is updated, as discussed in more detail in Persisting Using the App
`Receipt (page 27). All other types of products have an entry in the receipt that isn’t removed.
`
`Consumable products, by their nature, aren’t synced or restored. Users understand that, for example, buying
`ten more bubbles on their iPhone doesn’t also give them ten more bubbles on their iPad. All other types of
`products are made available across all of the user’s devices. They’re also restored so users can continue to
`access their purchased content even after buying a new device. Store Kit handles the syncing and restoring
`process for auto-renewable and free subscriptions and for non-consumable products.
`
`2013-10-22 | Copyright © 2013 Apple Inc. All Rights Reserved.
`
`10
`
`
`
`Designing Your App’s Products
`Differences Between Product Types
`
`Non-renewing subscriptions differ from auto-renewable subscriptions in a few key ways. These differences
`give your app the flexibility to implement the correct behavior for your needs, as follows:
`
` ●
`
` ●
`
` ●
`
`Your app is responsible for calculating the time period that the subscription is active and determining
`what content needs to be made available to the user.
`
`Your app is responsible for detecting that a subscription is approaching its expiration date and prompting
`the user to renew the subscription by purchasing the product again.
`
`Your app is responsible for making subscriptions available across all the user’s devices after they’re
`purchased and for letting users restore past purchases. For example, most subscriptions are provided by
`a server; your server would need some mechanism to identify users and associate subscription purchases
`with the user who purchased them.
`
`2013-10-22 | Copyright © 2013 Apple Inc. All Rights Reserved.
`
`11
`
`
`
`Retrieving Product Information
`
`In the first part of the purchase process, your app retrieves information about its products from the App Store,
`presents its store UI to the user, and then lets the user select a product, as shown in Figure 2-1.
`
`Figure 2-1
`
`Stages of the purchase process—displaying store UI
`
`Getting a List of Product Identifiers
`Every product you sell in your app has a unique product identifier. Your app uses these product identifiers to
`fetch information about products from the App Store, such as pricing, and to submit payment requests when
`users purchase those products. Your app can either read its list of product identifiers from a file in its app
`bundle or fetch them from your server. Table 2-1 summarizes the differences between the two approaches.
`
`Table 2-1
`
`Comparison of approaches for obtaining product identifiers
`
`Embedded in the app bundle
`
`Fetched from your server
`
`Used for purchases that
`
`Unlock functionality
`
`Deliver content
`
`List of products can change
`
`When the app is updated
`
`At any time
`
`Requires a server
`
`No
`
`Yes
`
`2013-10-22 | Copyright © 2013 Apple Inc. All Rights Reserved.
`
`12
`
`
`
`Retrieving Product Information
`Getting a List of Product Identifiers
`
`If your app has a fixed list of products, such as an in-app purchase to remove ads or enable functionality, embed
`the list in the app bundle. If the list of product identifiers can change without your app needing to be updated,
`such as a game that supports additional levels or characters, have your app fetch the list from your server.
`
`There’s no runtime mechanism to fetch a list of all products configured in iTunes Connect for a particular app.
`You’re responsible for managing your app’s list of products and providing that information to your app. If you
`need to manage a large number of products, consider using the bulk XML upload/download feature in iTunes
`Connect.
`
`Embedding Product IDs in the App Bundle
`Include a property list file in your app bundle containing an array of product identifiers, such as the following:
`
`<?xml version="1.0" encoding="UTF-8"?>
`<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
`"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
`<plist version="1.0">
`<array>
`<string>com.example.level1</string>
`<string>com.example.level2</string>
`<string>com.example.rocket_car</string>
`</array>
`</plist>
`
`To get product identifiers from the property list, locate the file in the app bundle and read it.
`
`NSURL *url = [[NSBundle mainBundle] URLForResource:@"product_ids"
`withExtension:@"plist"];
`NSArray *productIdentifiers = [NSArray arrayWithContentsOfURL:url];
`
`Fetching Product IDs from Your Server
`Host a JSON file on your server with the product identifiers. For example:
`
`[
`
`"com.example.level1",
`"com.example.level2",
`"com.example.rocket_car"
`
`2013-10-22 | Copyright © 2013 Apple Inc. All Rights Reserved.
`
`13
`
`
`
`Retrieving Product Information
`Getting a List of Product Identifiers
`
`]
`
`To get product identifiers from your server, fetch and read the JSON file as shown in Listing 2-1. Consider
`versioning the JSON file so that future versions of your app can change its structure without breaking older
`versions of your app. For example, you could name the file that uses the old structure products_v1.json
`and the file that uses a new structure products_v2.json. This is especially useful if your JSON file is more
`complex than the simple array in the example.
`
`Listing 2-1
`
`Fetching product identifiers from your server
`
`- (void)fetchProductIdentifiersFromURL:(NSURL *)url delegate:(id)delegate
`{
`
`dispatch_queue_t global_queue =
`dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
`dispatch_async(global_queue, ^{
`NSError *err;
`NSData *jsonData = [NSData dataWithContentsOfURL:url
`options:NULL
`error:&err];
`
`if (!jsonData) { /* Handle the error */ }
`
`NSArray *productIdentifiers = [NSJSONSerialization
`JSONObjectWithData:jsonData options:NULL error:&err];
`if (!productIdentifiers) { /* Handle the error */ }
`
`dispatch_queue_t main_queue = dispatch_get_main_queue();
`dispatch_async(main_queue, ^{
`[delegate displayProducts:productIdentifiers]; // Custom method
`});
`
`});
`
`}
`
`For information about downloading files using NSURLConnection, see Using NSURLConnection in URL Loading
`System Programming Guide .
`
`2013-10-22 | Copyright © 2013 Apple Inc. All Rights Reserved.
`
`14
`
`
`
`Retrieving Product Information
`Retrieving Product Information
`
`To ensure that your app remains responsive, use a background thread to download the JSON file and extract
`the list of product identifiers. To minimize the data transferred, use standard HTTP caching mechanisms, such
`as the Last-Modified and If-Modified-Since headers.
`
`Retrieving Product Information
`To make sure your users see only products that are actually available for purchase, query the App Store before
`displaying your app’s store UI.
`
`Use a products request object to query the App Store. First, create an instance of SKProductsRequest and
`initialize it with a list of product identifiers. The products request retrieves information about valid products,
`along with a list of the invalid product identifiers, and then calls its delegate to process the result. The delegate
`must implement the SKProductsRequestDelegate protocol to handle the response from the App Store.
`Listing 2-2 shows a simple implementation of both pieces of code.
`
`Listing 2-2
`
`Retrieving product information
`
`// Custom method
`- (void)validateProductIdentifiers:(NSArray *)productIdentifiers
`{
`
`SKProductsRequest *productsRequest = [[SKProductsRequest alloc]
`initWithProductIdentifiers:[NSSet setWithArray:productIdentifiers]];
`productsRequest.delegate = self;
`[productsRequest start];
`
`} /
`
`/ SKProductsRequestDelegate protocol method
`- (void)productsRequest:(SKProductsRequest *)request
`didReceiveResponse:(SKProductsResponse *)response
`
`{
`
`self.products = response.products;
`
`for (NSString *invalidIdentifier in response.invalidProductIdentifiers) {
`// Handle any invalid product identifiers.
`
`} [
`
`self displayStoreUI]; // Custom method
`
`2013-10-22 | Copyright © 2013 Apple Inc. All Rights Reserved.
`
`15
`
`
`
`Retrieving Product Information
`Presenting Your App’s Store UI
`
`}
`
`When the user purchases a product, you need the corresponding product object to create a payment request,
`so keep a reference to the array of product objects that’s returned to the delegate. If the list of products your
`app sells can change, you may want to create a custom class that encapsulates a reference to the product
`object as well as other information—for example, pictures or description text that you fetch from your server.
`Payment requests are discussed in Requesting Payment (page 20).
`
`Product identifiers being returned as invalid usually indicates an error in your app’s list of product identifiers,
`although it could mean the product hasn’t been properly configured in iTunes Connect. Good logging and a
`good UI help you resolve this type of issue more easily. In production builds, your app needs to fail
`gracefully—typically, this means displaying the rest of your app’s store UI and omitting the invalid product. In
`development builds, display an error to call attention to the issue. In both production and development builds,
`use NSLog to write a message to the console so you have a record of the invalid identifier. If your app fetched
`the list from your server, you could also define a logging mechanism to let your app send the list of invalid
`identifiers back to your server.
`
`Presenting Your App’s Store UI
`Because the design of your app’s store has an important impact on your in-app sales, it’s worth investing the
`time and effort to get it right. Design the user interface for your store UI so it integrates with the rest of your
`app. Store Kit can’t provide a store UI for you. Only you know your app and its content well enough to design
`your store UI in a way that showcases your products in their best light and fits seamlessly with the rest of your
`app.
`
`Consider the following guidelines as you design and implement your app’s store UI.
`
`Display a store only if the user can make payments. To determine whether the user can make payments,
`call the canMakePayments class method of the SKPaymentQueue class. If the user can’t make payments (for
`example, because of parental restrictions), either display UI indicating that that the store isn’t available or omit
`the store portion of your UI entirely.
`
`Present products naturally in the flow of your app. Find the best place in your UI to show your app’s store
`UI. Present products in context at the time when the user can use them—for example, let users unlock
`functionality when they try to use that premium feature. Pay special attention to the experience a user has
`when exploring your app for the first time.
`
`2013-10-22 | Copyright © 2013 Apple Inc. All Rights Reserved.
`
`16
`
`
`
`Retrieving Product Information
`Suggested Testing Steps
`
`Organize products so that exploration is easy and enjoyable. If your app has a small enough number of
`products, you can display everything on one screen; otherwise, group or categorize products to make them
`easy to navigate. Apps with a large number of products, such as comic book readers or magazines with many
`issues, benefit especially from an interface that makes it easy for users to discover new items they want to
`purchase. Make the differences between your products clear by giving them distinct names and visuals—if
`necessary, include explicit comparisons.
`
`Communicate the value of your products to your users. Users want to know exactly what they’re going to
`buy. Combine information from the App Store, such as product prices and descriptions, with additional data
`from your server or the app bundle, such as images or demos of your products. Let users interact with a product
`in a limited way before buying it. For example, a game that gives the user the option to buy new race cars can
`allow users to run a test lap with the new car. Likewise, a drawing app that lets the user buy additional brushes
`can give users the chance to draw with the new brush on a small scratch pad and see the difference between
`brushes. This kind of design provides users an opportunity to experience the product and be convinced they
`want to purchase it.
`
`Display prices clearly, using the locale and currency returned by the App Store. Ensure that the price of a
`product is easy to find and easy to read. Don’t try to convert the price to a different currency in your UI, even
`if the user’s locale and the price’s locale differ. Consider, for example, a user in the United States who prefers
`the United Kingdom locale for its units and date formatting. Your app displays its UI according to the United
`Kingdom locale, but it still needs to display product information in the locale specified by the App Store.
`Converting prices to British pounds sterling, in an attempt to match the United Kingdom locale of the rest of
`the interface, would be incorrect. The user has an App Store account in the United States and pays in U.S.
`dollars, so prices would be provided to your app in U.S. dollars. Likewise, your app would display its prices in
`U.S. dollars. Listing 2-3 shows how to correctly format a price by using the product’s locale information.
`
`Listing 2-3
`
`Formatting a product’s price
`
`NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init];
`[numberFormatter setFormatterBehavior:NSNumberFormatterBehavior10_4];
`[numberFormatter setNumberStyle:NSNumberFormatterCurrencyStyle];
`[numberFormatter setLocale:product.priceLocale];
`NSString *formattedPrice = [numberFormatter stringFromNumber:product.price];
`
`After a user selects a product to buy, your app connects to the App Store to request payment for the product.
`
`Suggested Testing Steps
`Test each part of your code to verify that you’ve implemented it correctly.
`
`2013-10-22 | Copyright © 2013 Apple Inc. All Rights Reserved.
`
`17
`
`
`
`Retrieving Product Information
`Suggested Testing Steps
`
`Sign In to the App Store with Your Test Account
`Create a test user account in iTunes Connect, as described in Creating Test User Accounts.
`
`On a development iOS device, sign out of the App Store in Settings. Then build and run your app from Xcode.
`
`On a development OS X device, sign out of the Mac App Store. Then build your app in Xcode and launch it
`from the Finder.
`
`Use your app to make an in-app purchase. When prompted to sign in to the App Store, use your test account.
`Note that the text “[Environment: Sandbox]” appears as part of the prompt, indicating that you’re connected
`to the test environment.
`
`If the text “[Environment: Sandbox]” doesn’t appear, you’re using the production environment. Make sure
`you’re running a development-signed build of your app. Production-signed builds use the production
`environment.
`
`Important: Don’t use your test user account to sign in to the production environment. If you do, the test
`user account becomes invalid and can no longer be used.
`
`Test Fetching the List of Product Identifiers
`If your product identifiers are embedded in your app, set a breakpoint in your code after they’re loaded and
`verify that the instance of NSArray contains the expected list of product identifiers.
`
`If your product identifiers are fetched from a server, manually fetch the JSON file—using a web browser such
`as Safari or a command-line utility such as curl—and verify that the data returned from your server contains
`the expected list of product identifiers. Also verify that your server correctly implements standard HTTP caching
`mechanisms.
`
`Test Handling of Invalid Product Identifiers
`Intentionally include an invalid identifier in your app’s list of product identifiers. (Make sure you remove it after
`testing.)
`
`In a production build, verify that the app displays the rest of its store UI and users can purchase other products.
`In a development build, verify that the app brings the issue to your attention.
`
`Check the console log and verify that you can correctly identify the invalid product identifier.
`
`2013-10-22 | Copyright © 2013 Apple Inc. All Rights Reserved.
`
`18
`
`
`
`Retrieving Product Information
`Suggested Testing Steps
`
`Test a Products Request
`Using the list of product identifiers that you tested, create and submit an instance of SKProductsRequest.
`Set a breakpoint in your code, and inspect the lists of valid and invalid product identifiers. If there are invalid
`product identifiers, review your products in iTunes Connect and correct your JSON file or property list.
`
`2013-10-22 | Copyright © 2013 Apple Inc. All Rights Reserved.
`
`19
`
`
`
`Requesting Payment
`
`In the second part of the purchase process, after the user has chosen to purchase a particular product, your
`app submits a payment request to the App Store, as shown in Figure 3-1.
`
`Figure 3-1
`
`Stages of the purchase process—requesting payment
`
`Creating a Payment Request
`When the user selects a product to buy, create a payment request using a product object, and set the quantity
`if needed, as shown in Listing 3-1. The product object comes from the array of products returned by your app’s
`products request, as discussed in Retrieving Product Information (page 15).
`
`Listing 3-1
`
`Creating a payment request
`
`SKProduct *product = <# Product returned by a products request #>;
`SKMutablePayment *payment = [SKMutablePayment paymentWithProduct:product];
`payment.quantity = 2;
`
`2013-10-22 | Copyright © 2013 Apple Inc. All Rights Reserved.
`
`20
`
`
`
`Requesting Payment
`Detecting Irregular Activity
`
`Detecting Irregular Activity
`The App Store uses an irregular activity detection engine to help combat fraud. Some apps can provide
`additional information to improve the engine’s ability to detect unusual transactions. If your users have an
`account with you, in addition to their App Store accounts, provide this additional piece of information when
`requesting payment.
`
`By way of illustration, consider the following two examples. In the normal case, many different users on your
`server each buy coins to use in your game, and each user pays for the purchase from a different App Store
`account. In contrast, it would be very unusual for a single user on your server to buy coins multiple times,
`paying for each purchase from a different App Store account. The App Store can’t detect this kind of irregular
`activity on its own—it needs information from your app about which account on your server is associated with
`the transaction.
`
`To provide this information, populate the applicationUsername property of the payment object with a
`one-way hash of the user’s account name on your server, such as in the example shown in Listing 3-2.
`
`Listing 3-2
`
`Providing an application username
`
`#import <CommonCrypto/CommonCrypto.h>
`
`// Custom method to calculate the SHA-256 hash using Common Crypto
`- (NSString *)hashedValueForAccountName:(NSString*)userAccountName
`{
`
`const int HASH_SIZE = 32;
`unsigned char hashedChars[HASH_SIZE];
`const char *accountName = [userAccountName UTF8String];
`size_t accountNameLen = strlen(accountName);
`
`// Confirm that the length of the user name is small enough
`// to be recast when calling the hash function.
`if (accountNameLen > UINT32_MAX) {
`NSLog(@"Account name too long to hash: