Additional features for working with payments in the iOS SDK🔗
Opening a Subscription Manager🔗
To open the subscription manager, that is, redirect the user to the store in the desired section (or open view in application on iOS 15+), it is enough to use the following function:
Support for promotional codes🔗
MRGS supports working with promotional codes for content creators - when using it, the creator receives a bonus. Systems will be added upon request.
To check for the presence of a promotional code entered by the user, you can use the following method:
[[MRGSBank sharedInstance] checkPromocode:@"PromoTest" completionHandler:^(BOOL valid, NSError* error) {
if (valid) {
// Apply for later purchases
}
}];
Then, when starting the payment, you need to add a promotional code to the payment parameters:
MRGSBankPurchaseRequest* request = [MRGSBankPurchaseRequest requestWithProductIdentifier:@"test.product.id"];
request.promocode = @"PromoTest";
After a successful purchase and payment verification, MRGS will report the use of the promotional code to the service (then the content creator who issued the promotional code receives a bonus).
In-app purchases directly from the App Store on IOS 11 and later🔗
In iOS 11 Apple introduced a new way of purchasing - directly from the AppStore.
MRGS can work with such payments. If a user initiates the purchase in the AppStore, your application will be opened, and we will save the user's purchase in pendingPayment, and we will wait for your decision to continue the purchase. In order to work with deferred payments, we provide the API:
//Checks if there is a deferred payment
- (BOOL)hasPendingAppStorePromotionPayment;
//Get the product, which the user intends to purchase
- (MRGSBankProduct* _Nullable)getPendingAppStorePromotionPaymentProduct;
//Start processing the deferred payment
- (void)proceedPendingAppStorePromotionPayment;
// Start a deferred payment with an optional payload indication
- (void)proceedPendingAppStorePromotionPaymentWithDeveloperPayload:(NSString* _Nullable)payload;
We can also work with the AppStore showcases (for example, if the user has bought a product, you should remove it from the AppStore showcase for this user) To work with the showcase, we suggest the following API:
//Hides the in-app on the store page
- (void)hideProductInStore:(NSString*)paymentIdentifier completionHandler:(void (^)(NSError *error))handler;
//Displays the in-app on the store page
- (void)showProductInStore:(NSString*)paymentIdentifier completionHandler:(void (^)(NSError *error))handler;
//Checks the display of the in-app on the store page
- (void)isProductVisibleInStore:(NSString*)paymentIdentifier completionHandler:(void (^)(BOOL visible, NSError *error))handler;
Apple subscription offers and introductory price support🔗
In iOS 12.2 Apple introduced subscription discounts. They can be received only by the user, who has previously been subscribed but canceled his subscription.
In order to use discounts, you first need to create them in the appStoreConnect admin panel. Then, you should get a list of discounts for this product - use the fields MRGSBankProduct.skProduct.discounts (Apple subscription offers discounts) and MRGSBankProduct.skProduct.introductoryPrice (initial discounts), each discount contains a description, price, and period, in during which it operates. If the specified fields are not nil, then the discount is added to iTunes, and you can use it. Also, it is necessary to determine whether the user can get a discount, since the above fields only inform about the availability of a discount in iTunesConnect (AppStore Connect). To do this use the class MRGSBankReceiptProcessor. Then you can show the interface with the discount offer.
In order to start buying a subscription with a discount (meaning Apple subscription offers discounts, introductory discounts are applied automatically), use the MRGSBankPurchaseRequest class, in which you must fill in the discountIdentifier fields, specifying the ID of the discount with which you want to buy a subscription, and the applicationUsername field, in which you must specify the hash from the user ID. The applicationUsername field is used so that Apple can determine within its system that the user is a fraud (for example, often makes refunds). If you do not fill in this field, then we will automatically substitute the user ID hash set via [MRGSUsers setUserId]:
MRGSBankPurchaseRequest* request = [MRGSBankPurchaseRequest requestWithProductIdentifier:@"games.my.mrgs.framework.subscription" developerPayload:@"{\"item\": 123,\"store\": 546}"];
request.discountIdentifier = @"MRGSPromo_5";
request.applicationUsername = @"userHash";
[[MRGSBank sharedInstance] purchaseProductWithRequest:request];
After that we will process the purchases and inform you on the results through the delegate as usual.
We also added a special field MRGSBankTransaction.selctedDiscount, which will contain the discount object if the purchase was made with a discount.
Important
In order for us to generate an application sign and process the payment, we need a key and its identifier. To receive the key you need to open AppStoreConnect-Users-Keys-Subscription, and create the key and the identifier. After that you need to send them to us (directly in the private messages or via e-mail).
Also, we support the introductory price both on the client and on the server, and will be able to track normally not only the free trial periods, but also the usual initial discount of any format.
Working with the application receipt🔗
We support the work with the general application payment receipt. With this feature you can determine the eligibility of a discount for a user, learn about active subscriptions and receive information about subscriptions.
The main class for working with the receipt is MRGSBankReceiptProcessor. To get the class object, use the [MRGSBankReceiptProcessor sharedInstance] method.
The application receipt is a local file which keeps records of all completed purchases (except for consumable purchases) and renewals. It is the file we work with.
Important
To work with the receipt we need a payment verification key, therefore do not forget to add a special key needed to verify payments in the application settings in the MRGS admin panel. You can find the key in iTunesConnect-YourApp-InappPurcases-SharedSecret.
Usually, the receipt appears in the application right after downloading, but sometimes (for example, installing from iTunes, or restoring from a backup)the receipt can be missing. If there is no receipt, you need to make an update request (we will do it automatically), which will require the user to enter a password. A causeless pop-up can confuse the user, so we added the isReceiptAvailable method, which allows to check the availability of the receipt, and, if it is missing, show the user a window that his password will be requested for certain purposes.
Example:
if(![[MRGSBankReceiptProcessor sharedInstance] isReceiptAvailable]){
//Show the warning window
}else{
//Call the necessary methods
}
Important to know
The first request to any of the methods below (the ones with a callback) can be lingering and will require an Internet connection, since we need to send the receipt to our server and receive its decryption. But after that we will work with cached data (except for the special cases when the data needs to be updated), and requests will occur instantly, and upon the necessity to receive relevant data, we will download it again from the server. Even if you call all the methods simultaneously, only one request will still be sent to our server, and after its completion all other methods will receive a callback.
Possible error
If upon testing you get the SSErrorDomain Code=100 error (error of updating the receipt from the Apple), refer to this article
Receiving the list of purchased non-consumable products🔗
If you use non-consumable products, you need to restore them for the user in some situations (for example, changing a device/account). The list of purchased non-consumable products can be received by calling the restore method (according to the guides, it should be a separate button so that the user understands why is required to log into the account). Also, the list of purchased products can be received from the receipt. To do this, use the method:
-(void)getAllPurchasedNonConsumableProductsWithCompletionHandler: (void (^_Nonnull)(NSArray<MRGSBankReceiptItem*>* purchasedNonConsumables, NSError * _Nullable error)) completion;
The response will be a block, which is called after receiving the list. It contains an array of purchased non-consumable products, or an error, if there is any.
Note
There is a possibility, that this feature works only on production, and does not work in Sandbox/Testflight.
Determining eligibility for apple subscription offers and introductory prices🔗
If you use introductory prices or apple subscription offers, you need to determine the eligibility of these offers for the user, since he may have bought a subscription with a discount, and this offer is no longer relevant for him (technically impossible to buy).
The subscriptions are divided into groups (in iTunesConnect), and the possibility to offer a discount is determined for all the subscriptions within one group. It was for groups that we created verification methods. (For example, if the user bought a monthly subscription with an introductory discount from the one group, he cannot buy (change to) an annual subscription with a discount and from the same group)
In order to check which of the groups have available discounts, use the methods:
-(void)getUserIntroductoryEligabilityForSubscriptions: (NSArray<MRGSBankSubscriptionGroup*>*) subscriptionGroups withCompletionHandler: (void (^_Nonnull)(NSArray<MRGSBankSubscriptionGroup*>* _Nonnull eligableGroups, NSError * _Nullable error)) completion;
-(void)getUserDiscountEligabilityForSubscriptions: (NSArray<MRGSBankSubscriptionGroup*>*) subscriptionGroups withCompletionHandler: (void (^_Nonnull)(NSArray<MRGSBankSubscriptionGroup*>* _Nonnull eligableGroups, NSError * _Nullable error)) completion;
Create the necessary subscription groups in advance. The group consists of a name (it is not obligatory to be filled) and an array of the subscription identifiers, included in this group.
Usage example:
MRGSBankSubscriptionGroup* group1 = [MRGSBankSubscriptionGroup createGroupWithName:@"Subscription_Group_1" andIdentifiers:@[@"games.my.mrgs.framework.AutoRenew1",@"games.my.mrgs.framework.AutoRenew2"]];
MRGSBankSubscriptionGroup* group2 = [MRGSBankSubscriptionGroup createGroupWithName:@"Subscription_Group_2" andIdentifiers:@[@"games.my.mrgs.framework.AutoRenew3",@"games.my.mrgs.framework.AutoRenew4"]];
NSArray<MRGSBankSubscriptionGroup*>* subscriptionGroups = @[group1,group2];
[[MRGSBankReceiptProcessor sharedInstance] getUserDiscountEligabilityForSubscriptions:subscriptionGroups withCompletionHandler:^(NSArray<MRGSBankSubscriptionGroup *> * _Nonnull eligableGroups, NSError * _Nullable error) {
for(MRGSBankSubscriptionGroup* group in eligableGroups){
//Eligable group process
}
}];
[[MRGSBankReceiptProcessor sharedInstance] getUserIntroductoryEligabilityForSubscriptions:subscriptionGroups withCompletionHandler:^(NSArray<MRGSBankSubscriptionGroup *> * _Nonnull eligableGroups, NSError * _Nullable error) {
for(MRGSBankSubscriptionGroup* group in eligableGroups){
//Eligable group process
}
}];
Working with the subscription information🔗
When working with subscriptions, you may need to check whether there are active subscriptions, when they will end, or check the information of a specific subscription. Usually this information comes from the game server, but some non-server games initiate a restore upon every launch to find out the status of the subscription, which is not completely correct from the point of view of the user's experience. With our help, you can:
- Get the list of active subscriptions.
- Get the list of all subscriptions ever purchased.
- Get the necessary information about a specific subscription.
To describe the subscription object from the receipt, we created a MRGSBankReceiptItem class, which keeps the information about the product identifier (productIdentifier) and the expiration time (for subscriptions).
To receive the subscription information you the methods:
-(void)getActiveSubscriptionsAndExpirationsWithCompletionHandler: (void (^_Nonnull)(NSArray<MRGSBankReceiptItem*>* activeSubscriptions, NSError * _Nullable error)) completion;
-(void)getAllSubscriptionsExpirationDatesWithCompletionHandler: (void (^_Nonnull)(NSArray<MRGSBankReceiptItem*>* subscriptions, NSError * _Nullable error)) completion;
-(void)getExpirationDateForSubscription: (NSString*)productIdentifier withCompletionHandler: (void (^_Nonnull)(MRGSBankReceiptItem* _Nullable subscription, NSError * _Nullable error)) completion;
Usage examples:
//Get all active subscriptions, including those, which were prolonged
[[MRGSBankReceiptProcessor sharedInstance] getActiveSubscriptionsAndExpirationsWithCompletionHandler:^(NSArray<MRGSBankReceiptItem *> * _Nonnull activeSubscriptions, NSError * _Nullable error)
{
for(MRGSBankReceiptItem* subscription in activeSubscriptions){
//Process active subscription
}
}];
//Get the list of all subscriptions ever purchased
[[MRGSBankReceiptProcessor sharedInstance] getAllSubscriptionsExpirationDatesWithCompletionHandler:^(NSArray<MRGSBankReceiptItem *> * _Nonnull subscriptions, NSError * _Nullable error)
{
for(MRGSBankReceiptItem* subscription in subscriptions){
//Process subscription, that was bought any time ago
}
}];
//Get the information about a specific subscription
[[MRGSBankReceiptProcessor sharedInstance] getExpirationDateForSubscription:@"games.my.mrgs.framework.AutoRenew3" withCompletionHandler:^(MRGSBankReceiptItem * _Nullable subscription, NSError * _Nullable error) {
NSDate* weekAgo = [NSDate dateWithTimeIntervalSinceNow:-604800];
if(subscription && subscription.expirationDate > weekAgo && subscription.expirationDate < [NSDate date]){
//The subscription has not been prolonged (the user refused or had insufficient funds) less that a week ago
}
}];
Important
We take subscription renewals into consideration. Thus, if the subscription has been renewed and the local receipt has not been renewed (which is common), we will still provide the up-to-date information about subscriptions.
Fraud detection🔗
To help Apple detect in-app purchase fraud, at the beginning of the purchase, you can set the parameter:
MRGSBankPurchaseRequest* request = [MRGSBankPurchaseRequest requestWithProductIdentifier:<sku> developerPayload:<developerPayload>];
request.applicationUsername = <user_id_hash>;
[[MRGSBank sharedInstance] purchaseProductWithRequest:request];
In case you do not set this identifier, MRGS will automatically set its value as a hash from the user set to us at startup
Emulating parental purchase permission (Ask To Buy)🔗
Apple allows parents to confirm purchases of children. In this case, the status of pending will be received during the payment process. In order to test this functionality, you can set the parameter:
MRGSBankPurchaseRequest* request = [MRGSBankPurchaseRequest requestWithProductIdentifier:<sku> developerPayload:<developerPayload>];
request.simulatesAskToBuyInSandbox = true;
[[MRGSBank sharedInstance] purchaseProductWithRequest:request];
Created: 2020-02-17