Non Consumable on iOS
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.
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.
Let's also make sure to comment out Cordova template project's CSS.
You also need to enable the 'unsafe-inline'
Content-Security-Policy
by adding it to the default-src
section:
You can download the full index.html file here.
We will now create a new JavaScript file and load it from the HTML. The code below will initialize the plugin.
Here's a little explanation:
Lines 5-8, we check if the plugin is loaded.
Lines 10-13, we register the product with ID nonconsumable1
. We declare it as a non-consumable (store.NON_CONSUMABLE
). ⇒ API Documentation.
Lines 15-17, we setup an error handler. It just logs errors to the console.
Line 21, we perform the initial refresh()
of all products states. ⇒ API Documentation.
Whatever your setup is, you should make sure this runs as soon as the javascript application starts. You have to be ready to handle IAP events as soon as possible.
Presentation
For the sake of this tutorial's simplicity, let's store the state of the feature (locked or unlocked) in localStorage: window.localStorage.unlocked
When the app starts, we'll refresh the #locked
html element:
This part was easy,. Now for a bit more challenge, let's display the title, description and price of the in-app product for purchasing the feature, nonconsumable1
that we registered in the initialization code above.
We'll add a little more at initStore()
function, line 20.
Then define the refreshProductUI()
function at the bottom of the file.
Lines 2, check if the product has been loaded.
Lines 3-5, retrieve and display product informations.
Lines 7-8, add the "Buy Now!" button if product can be purchased.
If you want a bit more background information about this, please check the Displaying Products section and the ⇒ API Documentation for full details about the fields found for a product.
Let's build and test that!
Testing
To test with In-App Purchases enabled, I 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 make a build, first update the Xcode project on the console.
Then switch to Xcode and run.
Purchase
Now that we have our purchase button, let's implement the purchaseNonConsumable1
button.
Can it be easier than that? Well, not so fast! The code as it is won't do much with this order request. To process the purchase we have to implement the various steps of the purchase flow.
I already introduced the purchase flow in the introduction of this guide, check the Purchase process section if you need a refresher. The official documentation provides more details. ⇒ API Documentation
So the first thing that will happen is that the canPurchase
state of the product will change to false
. But remember, we added this in the previous step:
So we're covered. The UI will be refreshed when canPurchase
changes, it will not be possible to hit Purchase, until canPurchase
becomes true again.
When the user is done with the native interface (enter his/her password and confirm), you'll receive the approved
event, let's handle it by adding the below to the initStore()
function, before the call to store.refresh()
.
Then we will add the finishPurchase
function at the end of our JavaScript file.
This is a good enough implementation, but let's go one step further and setup a receipt validator. This is optional, but it prevents the easiest for of hacking, so generally a good idea.
For this tutorial, we will use Fovea's own service which is free during development. You can implement your own receipt validation service later if you like.
Head to https://billing.fovea.cc/ and create an Account.
Setup your project's iOS bundle ID and shared secret, Save.
Go to the Cordova Setup page to copy the line
store.validator = "<something>"
.
Copy this line inside the initStore()
function, anywhere before the initial store.refresh()
. Also add the recommended Content-Security-Policy
to your index.html
as mentioned in the documentation.
Alright, we're done with coding! Let's try the whole thing now. Repeat the steps from the Testing section above:
Run from Xcode and here you go!
Full source for this tutorial is available here: https://gist.github.com/j3k0/3324bb8e759fef4b3054b834a5a88500
Last updated