Auto-Renewing Subscription on iOS
In this guide, we will build a small application with a subscription that works on iOS.
On iOS, the plugin supports simple subscriptions and subscriptions groups. Introductory prices and promotional offers are supported yet.
Here's what we will build: a simple application to manage a subscription with 2 different levels (basic subscription, and better subscription).
Let's dig into this. We will proceed in 4 steps: setup, initialization, presentation and purchase.
Here what we'll do.
Install Dependencies
Create Cordova Project
Setup AppStore Application
Install and Prepare with XCode
Create In-App Products
Prepare Test Accounts
Of couse you can skip the first few steps if you already have a working application you want to integrate the code into.
Once we have a Cordova iOS application with IAP support enabled and everything is in place on AppStore Connect, we will get into some coding.
Initialize the in-app purchase plugin
Handle the purchase events
Deliver our product
Secure the transactions
Setup
1. Install Dependencies
Needless to say, make sure you have the tools installed on your machine. Developing from a mac is generally recommended for doing iOS development, it's way easier. If you only plan on doing Android, then everything will work.
During the writing of this guide, I've been using the following environment:
NodeJS v10.12.0
Cordova v8.1.2
macOS 10.14.1
I'm not saying it won't work with different version. If you start fresh, it might be a good idea to use an up-to-date environment.
2. Create Cordova Project
Create the project
If it isn't already created:
For details about what those parameters are:
Note, feel free to pick a different project ID and name. Remember whatever values you put in here.
Let's head into our cordova project's directory (should match whatever we used in the previous step.
Add iOS platform
3. Setup AppStore Application
First, I assume you have an Apple developer account. If not time to register, because it's mandatory.
Let's now head to the AppStore Connect website. In order to start developing and testing In-App Purchases, you need all contracts in place as well as your financial information setup. Make sure there are no warning left there.
I'll not guide you through the whole procedure, just create setup your Apple application as usual.
Retrieve the Shared Secret
Since you are here, let's retrieve the Shared Secret. You can use an App-Specific one or a Master Shared Secret, at your convenience: both will work. Keep the value around, it'll be required, especially if you are implementing subscriptions.
4. Install and Prepare with XCode
When you only require iOS support, no need for special command line arguments:
You then have to activate the In-App Purchase capability manually for your application using Xcode. Unfortunately it's not something the plugin can do automatically. So let's first prepare the iOS project:
Then open the project on Xcode:
Get to the project's settings by clicking on the project's icon, which is the top-most item in the left-side pane tree view.
Select the target, go to Capabilities, scroll down to In-App Purchase and make sure it's "ON".
Now try to build the app from Xcode. It might point you to a few stuff it might automatically fix for you if you're starting from a fresh project, like selecting a development team and creating the signing certificate. So just let Xcode do that for you except if you have a good reason not to and know what you're doing.
Successful build? You're good to go!
5. Create In-App Products
If you followed the Setup AppStore Application section, you should have everything setup. Head again to the App's In-App Purchases page: select your application, then Features, then In-App Purchases.
From there you can create your In-App Products. Select the appropriate type, fill in all required metadata and select cleared for sale.
Even if that sounds stupid, you need to fill-in ALL metadata in order to use the In-App Product in development, even the screenshot for reviewers. Make sure you have at least one localization in place too.
The process is well explained by Apple, so I'll not enter into more details.
6. Create Test Users
In order to test your In-App Purchases during development, you should create some test users.
You can do so from the AppStore Connect website, in the Users & Access section. There in the sidebar, you should see "Sandbox > Testers". If you don't, it means you don't have enough permissions to create sandbox testers, so ask your administrator.
From there, it's just a matter of hitting "+" and filling the form. While you're at it, create 2-3 test users: it will be handy for testing.
7. Get a Receipt Validation Server
A proper implementation of subscriptions on iOS requires a receipt validation server that'll get used to get the most up-to-date status of a users subscription.
Implementing your own is not in the scope of this guide, so we'll use Fovea's dedicated service called Billing.
Create an account on: https://billing.fovea.cc.
Fill in the information for iOS: your Bundle ID and the Shared Secret.
Once this is done, you can visit the documentation page, keep it around for when we'll start the implementation: we'll have to copy-paste the store.validator = ...
line into the code.
The service is free for sandbox receipts validation. When you get to production you need to upgrade to a paid plan (see pricing).
Coding
Initialization
Assuming you're starting from a blank project, we'll add the minimal amount of HTML for the purpose of this tutorial. Let's replace the <body>
from the www/index.html
file with the below.
Make sure to comment out Cordova template project's CSS.
We enabled the 'unsafe-inline'
Content-Security-Policy
by adding it to the default-src
section.
Since we'll be using Fovea.Billing, you also need to add your validation server to default-src, find your in the cordova setup documentation. On my case it's https://reeceipt-validation.fovea.cc
.
Let's now or edit the JavaScript file js/index.js
. Replace the content with the code below, which will setup a minimal application framework and render some HTML into the page based on the app state.
Now let's initialize the in-app purchase plugin, where indicated in the onDeviceReady
function.
Here's a little explanation:
We start by registering the product with ID my_subscription1
and my_subscription2
.
We declare the products as renewable subscriptions (store.PAID_SUBSCRIPTION
). ⇒ API Documentation.
We setup the link to the receipt validation server. If you're using Fovea.Billing, you'll find it here.
We setup an error handler. It will display the last error message for 10 seconds on top of the screen.
Finally, we perform the initial refresh()
of all product states. ⇒ API Documentation.
Whatever your setup is, you should make sure the initialization code is executed as soon as the javascript application starts. You have to be ready to handle IAP events as soon as possible.
Presentation
Let's now display the subscription status, as it is provided by the native platform. Before the call to store.refresh()
we will add an handler for the update
event:
This hander is called whenever there's a change in our products' state.
Now we can display some information about our products from the render()
function:
Whenever anything happens to our product, the interface will now be updated to reflect the current state.
Displaying your product information this way, i.e. exactly as loaded from the Store, is required by Apple and Google. Do otherwise and they might simply reject your application.
You can also disconnect the event handler with store.off()
so your subscription view is only updated when it's visible.
If you want a bit more background information about all of this, please check the introduction's displaying products section and the ⇒ API Documentation for full details about the fields found for a product.
Purchase
So far so good, but what if we could actually initiate a purchase? To do so, we'll add a purchase button for both products. We already added placeholders for the purchase buttons, let's create them. Before displaying a purchase button, we need to make sure the user can actually purchase the item. It could be impossible for a few reasons: there's already a purchase in progress, the product is already owned, the feature is disabled for the user (Child Mode).
In our render()
function, we update the code that initialized purchaseProduct1
and purchaseProduct2
.
We could make this a little nicer by changing the button labels to "Upgrade" or "Downgrade" when the other product is owned
, I will leave this as an exercise to the reader.
Now, let's build and test!
Extra step for Android
If using the Fovea validation service, expiryDate
and some other features of the API for an auto-renewing Android subscription will only be available if you complete the "Connect With Google" step using the explainer here.
Testing
To test on iOS with In-App Purchases enabled, I always chose to run my app through Xcode. This way, I can see the logs from both the javascript and native sides, which is useful.
To create a build, first update the Xcode project on the console, swith to Xcode and run.
Run.
Purchase Flow
We already added a "Buy" button. This button calls the store.order()
method which initiates the purchase flow for a product.
At this point, the code starts the process but the purchase will remain "processing" forever, in the approved
state.
For a product in the approved
state, the transaction has been approved by the user's banking institution but it won't be finalized until you inform them to do so. You have to deliver whatever the user purchased before finalizing.
I already introduced the purchase flow in the introduction of this guide, you can check the purchase process section if you need a refresher. The official documentation provides even more details. ⇒ API Documentation
When the user is done with the native interface (i.e. has entered his/her password and confirmed), your app receives the approved
event. So let's add more handlers to the onDeviceReady()
function, before the call to store.refresh()
.
That's enough for a local implementation (where we don't need to inform a server of changes to the subscription status). Let's try the whole thing now. Repeat the steps from the testing section above:
Run from Xcode and here you go! You should be able to purchase your subscriptions.
Full source for this tutorial below:
Last updated