Hello everyone! In this article I shared the experience of implementing Auto-renewable subscription in an iOS app built using React Native. It will be useful for both React Native and native iOS developers, who code using Swift or Objective-C.

Theory

Let’s refer to the iTunes Paid Applications Agreement to the terms and conditions for auto-renewing subscriptions.

Guideline 3.1.2 — Business — Payments — Subscriptions:

Subscription information should remain available for review after purchase.

Your app’s binary did should include all of the following information about the auto-renewable nature of the subscription if logged in via the Premium Portal:

• Title of publication or service

• Length of subscription (time period and content or services provided during each subscription period)

• Price of subscription, and price per unit if appropriate

• Payment will be charged to iTunes Account at confirmation of purchase

• Subscription automatically renews unless auto-renew is turned off at least 24-hours before the end of the current period

• Account will be charged for renewal within 24-hours prior to the end of the current period, and identify the cost of the renewal

• Subscriptions may be managed by the user and auto-renewal may be turned off by going to the user’s Account Settings after purchase

• Any unused portion of a free trial period, if offered, will be forfeited when the user purchases a subscription to that publication, where applicable

– Your app’s binary did not include a link to the terms of use

– Your app’s binary did not include a link to the privacy policy

App design should be created according to this Agreement. In the next section I will describe the main design points which are important while design for the app with subscriptions is created.

Design (UI/UX)

First of all, if the app has auto renewable subscription the text below (or text like that) should be placed on the screen with Subscriptions Purchase buttons:

Cancel subscription any time. Subscription automatically renews unless auto-renew is turned off at least 24-hours before the end of the current period by going to your iOS Account Settings after purchase. Payment will be charged to iTunes Account. Any unused portion of free trial period, if offered, will be forfeited when you purchase a subscription.

Without this text, the application most probably will be rejected after App Store review.



Another important thing is that buttons Restore Purchases, which links to the Privacy Policy and Terms Of Use, should be placed on the exact screen with Purchase buttons.

If, for example, Privacy Policy and Terms Of Use link will be placed in side menu the app can be rejected too, because Apple justifies this in the way, that additional user interactions are required and user may not find it while purchasing subscriptions. As the result, the application may be declined.

One more important thing is the `Restore purchase` button. Don’t forget place this button in the application design.

And the last but not least thing — items to purchase. Each item should have description, which consists of:

Title

Length of subscription (you may combine it with title)

Price

Another `sales` stuff

In the result, purchase item may look like this:

Purchase item design in the application

Coding / Implementation

In this section I will share some insights of implementing auto-renewable subscriptions in iOS application based on React Native.

To implement in-app purchases in React Native app we use react-native-in-app-utils library (https://github.com/chirag04/react-native-in-app-utils).

Note: for Android in-app purchases you should use another library called react-native-billing (https://github.com/idehub/react-native-billing).

One of the important features to implement is Restore Purchase feature. It is useful to cover cases, when success callback after payment wasn’t called. It may be in cases, when user should link the card while purchasing, if he didnt link it before.

Example of basic implementation:

handleRestorePurchases = () => { this.setState(() => ({ isLoading: true })); InAppUtils.restorePurchases((error, response) => { if (error) { this.setState(() => ({ isLoading: false })); this.delayedInfoAlert(‘itunes Error’, ‘Could not connect to itunes store.’); } else { if (response.length === 0) { this.setState(() => ({ isLoading: false })); this.delayedInfoAlert(‘No Purchases’, “We didn’t find any purchases to restore.”); return; } // sort purchases const sortedPurchases = this.sortPurchases(response.slice()).reverse(); // send latest purchase to API this.handleSuccessfullPurchase(sortedPurchases[0]); } }); }

The important thing here is that restorePurchases function returns all user purchases, even expired ones, and Apple doesn’t promises that latest one in purchases array will be the newest by transactionDate . So, we need to sort purchases in array by transactionDate (you may use simple array.sort() function for this purposes) and take the purchase with the newest transactionDate .

After that we send receipt transactionReceipt to the server API endpoint (because we need to handle purchase event on the backend side) where receipt is validated and processed.

One of important things to do to make your mobile application more secure is to validate receipts.

There are 2 approaches how to do it: client side and backend side. We used backend side validation. There are 2 endpoints provided for receipts validation:

• https://sandbox.itunes.apple.com/verifyReceipt

• https://buy.itunes.apple.com/verifyReceipt

Use the first one for development and testing purposes and don’t forget to change it to the second one when app will be released to production ;)

Refer to the Apple Developers Documentation for more details.



As for the client side validation, you may use iap-receipt-validator module, more details here: https://github.com/sibelius/iap-receipt-validator.

Note: don’t forget to change the value of `production` variable to true when releasing the app as well ;)

And the last thing important to know, that you should call InAppUtils.purchaseProduct function only after calling InAppUtils.load.Products function, otherwise you will receive invalid_product error. You may call InAppUtils.load.Products in ComponentWillMount() lifecycle method, or call purchaseProduct directly in load.Products callback.

Bottom line

That’s all we want to share with you! Be careful with in-app purchases in iOS, don’t forget to switch sandbox/production environment and become Scrooge McDuck after implementing subscriptions in your app!

Clap 👏 👏 👏 if it was helpful and saved you some time 🕑. Follow me and UPTech blog to find out more useful 💡 articles about React Native, iOS and Android Development.