
At WWDC'17, Apple showed an updated App Store interface and introduced a number of innovations. Among them were promoted in-app purchases, which with the release of iOS 11 will be displayed directly in the search and editorial selection along with applications.
In our case, this is a particularly relevant thing, since in the current War Robots project we use in-app purchases, which for us have become the most optimal way to monetize. Therefore, in several new games that are currently in development, we are also going to use them.
One of the main differences is that the user can now make an in-app purchase right in the store, after which the application will be installed and the purchase information will be communicated at launch. To do this, the delegate SKPaymentTransactionObserver must implement a special method:
')
- (BOOL)paymentQueue:(SKPaymentQueue *)queue shouldAddStorePayment:(SKPayment *)payment forProduct:(SKProduct *)product;
Until this method is implemented in the application, promoted inline purchases cannot be purchased from the App Store. But they will be displayed in a special section on the application page.
To make a built-in purchase promoted, you need to fill in the special metadata that has recently appeared in iTunes Connect: an advertising image, a title and a brief description. After reviewing the changes, the purchase will appear in the new section “Promotion in the App Store”, where you can change the default visibility values for all users and their order on the App Store page at any time. So you can promote up to 20 built-in purchases at the same time and keep an unlimited number of purchases in the ready mode for inclusion.


All these visibility and order values will be used for users who have not yet installed the application.
The most important component of innovation is the ability to programmatically change the order and visibility of promoted in-line purchases. Now we can adapt to each user of the application: display a handful of crystals in the top to the player who has them at zero; offer a premium account to the active user; or open a new level to the player who has passed all the main content. Or, in general, to make a special, very advantageous offer of buying premium currency visible to the player only at that moment when he was faced with an acute shortage of resources, but at the same time did not take advantage of the basic offer to purchase it. You can do A / B testing to find the optimal order.
More specifically?
Consider the new API methods provided by Apple to perform these manipulations.
Let's promote two in-app purchases. Before installation and after launch, if you do nothing, they will be displayed to the user in accordance with the settings from iTunes Connect:

To change the order and visibility of these purchases, we need to get the objects of purchases by their sku through SKProductsRequest:
- (void)requestProducts { SKProductsRequest* productRequest = [[SKProductsRequest alloc] initWithProductIdentifiers:[NSSet setWithObject:@"gold.iap.example.com"]]; productRequest.delegate = self; [productRequest start]; } - (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response { NSArray<SKProduct *>* products = response.products;
Actions with promoted purchases are done via SKProductStorePromotionController, which will be implemented in iOS 11. Therefore, we wrap further calls with a check on the availability of this version. There are only four methods, you can perform them at any time when the application is running. Consider each one of them.
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response { if (@available(iOS 11.0, *)) { NSArray<SKProduct *>* products = response.products; [[SKProductStorePromotionController defaultController] updateStorePromotionOrder:products completionHandler:^(NSError * _Nullable error) { if(error != nil) { NSLog(@"Update store promotion order failed with error: %@", [error description]); } else { NSLog(@"Success"); } }]; } else {
After the execution, close and reopen the application page in the store, and take a look at the in-app purchases section:

The order has changed. With this challenge, we set the priority for the gold.iap.example.com product. Now it is shown first.
If we transferred several goods, they would be displayed in the order in which we transferred them. Next come the rest of the products in their default order (that is, specified in iTunes Connect). If you pass nil as a list of products, the override will be reset and all products will return to their original position. You can get the current order by calling:
- (void)fetchPromotionOrder { if (@available(iOS 11.0, *)) { [[SKProductStorePromotionController defaultController] fetchStorePromotionOrderWithCompletionHandler:^(NSArray<SKProduct *> * _Nonnull storePromotionOrder, NSError * _Nullable error) { if(error != nil) { NSLog(@"Fetch store promotion order failed with error: %@", [error description]); } else { NSMutableString* productIds = [NSMutableString string]; for (SKProduct* product in storePromotionOrder) { [productIds appendString:product.productIdentifier]; [productIds appendString:@"; "]; } NSLog(@"Got promotion order: %@", productIds); } }]; } else {
The method will return only those products whose order has been redefined, in the order of their redefinition.
Another available pair of methods interacts with the visibility of goods. By executing the following code, we will override the visibility of the transferred product gold.iap.example.com (in these methods only one product is transmitted):
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response { if (@available(iOS 11.0, *)) { SKProduct* product = [response.products objectAtIndex:0]; [[SKProductStorePromotionController defaultController] updateStorePromotionVisibility:SKProductStorePromotionVisibilityHide forProduct:product completionHandler:^(NSError * _Nullable error) { if(error != nil) { NSLog(@"Update store promotion visibility failed with error: %@", [error description]); } else { NSLog(@"Success"); } }]; } else {
Our priority product disappeared from the list on the store page.

Another method is to get the current installed product visibility:
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response { if (@available(iOS 11.0, *)) { SKProduct* product = [response.products objectAtIndex:0]; [[SKProductStorePromotionController defaultController] fetchStorePromotionVisibilityForProduct:product completionHandler:^(SKProductStorePromotionVisibility storePromotionVisibility, NSError * _Nullable error) { if(error != nil) { NSLog(@"Fetch store promotion visibility failed with error: %@", [error description]); } else { NSLog(@"Promotion visibility %ld", (long)storePromotionVisibility); } }]; } else {
Enum SKProductStorePromotionVisibility has the following available values: Show (product visible), Hide (product hidden), Default (visibility value is taken from iTunes Connect).
Thus, the list of built-in purchases can be customized for each specific user as you like. The tool is in the hands of the developer, the most important thing remains: to think about the rules of the show, because it is on them that the success of sales of certain embedded purchases and the income from the application as a whole depends. All this demonstrates Apple's desire to make the App Store a real place to shop, and not a trivial service for storing and searching for applications.
Link to Apple's documentation:
developer.apple.com/app-store/promoting-in-app-purchases