How to Easily Configure In-App Purchases into a Mobile Application?

A Tutorial, Containing Step-By-Step Instructions (With Pictures and Code Samples)

Why talk about it at all?

I would single out not one but several reasons why I think that the material of this tutorial will be useful for you:

  • the version of the “Plan To Table” app was approved only after the 5th moderation on the App Store;
  • while implementing the in-app purchases, I encountered many small, uncomplicated, but completely non-obvious procedures that needed to be done;
  • sooner or later you most likely will still meet in-app purchases and the material of this tutorial will come in handy, containing step-by-step instructions.

Why In-App Purchases?

This is a very good question! Why do we need them, if the App Store commission is 30%? It’s huge, no matter how hard you look! You won’t find such commissions anywhere else.

Let’s begin!

To create the test project we will use the following technologies: AngularJS 1.x, cordova, cordova-plugin-inapppurchase.

#1. Registering a new application

The first step is to select the package ID. Let’s name it “com.iap-service.app”. Then go to the developers’ portal and register it just like this: developer.apple.com/account/ios/certificate/ -> “Identifiers” -> “App IDs” -> “+”.

App ID Description: Purchase ServiceIdentifier: SG5B7ZUFY4.com.iap-service.app

#2. Creating in-app purchases

Ok, here we go! In the opened window, we have to choose the type of the in-app purchase from the following:

  • Consumable purchase (game gold)
  • Non-expendable purchase (specific race track)
  • Subscription with automatic renewal
  • Subscription without automatic renewal
  • productId
  • title
  • price
  • description

#3. Registering test users

After we created the application and built-in purchases, we definitely need test users. Yes, not one, but several at once. Test users are special because when they choose to pay with the in-app purchases, real money isn’t drawn from their card.

#4. Creating and installing certificates and profiles

Well, all we need is the “Production certificate” and respectively the “Distribution profile”:

#5. Adding the in-app purchases to the application

Let’s move on to the app creation!

angular.module('inAppPurchases.config', [])
.constant("IN_APP_PURCHASES",
{
iOS: [
'monthly_subscription'
],
Android: []
}
)
var _self = this;// to save a list of in-app purchasesvar _IAP = [];var _subscriptions = [];var _receipt = {};//returns link to _IAP, so we don't care when _IAP will be updated :)this.getProducts = function () {return _IAP;};this.getReceipt = function () {return _receipt;};this.getSubscriptions = function () {return _subscriptions;};// this method is called in app.js, this is the first init callthis.loadProducts = function () {var _productIds = IN_APP_PURCHASES[device.platform];// get available productswindow.inAppPurchase.getProducts(_productIds).then(function (products) {if (products.length) {products.forEach(function (product) {var productInfo = {id: product.productId,name: product.title,price: product.price,// we don't use full desc, we use only first sentance of descdescription: product.description.substring(0,product.description.indexOf('.')),checked: false};_IAP.push(productInfo);});} else {// empty array - no available products}_self.getActiveSubscription();return _IAP;}, function (err) {// error getting a list of in-app purchases_self.getActiveSubscription();$q.reject(err);});};
// here we get all bought products to be able to define// if need to redirect user to payments or not// this method saves results locally// has only resolve functionfunction _restore () {return window.inAppPurchase.restorePurchases().then(function(data) {// iOS provides the receipt isolated from the restore dataif (window.device && window.device.platform === "iOS") {return window.inAppPurchase.getReceipt().then(function(receipt) {FunctionService.cloneSafe(receipt, _receipt);return _receipt;}, function (err) {//returns _receipt anywayreturn _receipt;});} else { // Android provides the receipts with the restore dataFunctionService.cloneSafe(data, _subscriptions);return _subscriptions;}}, function (err) {//returns _subscriptions anywayreturn _subscriptions;});}
// in app.js loadProducts is called,// so call restorePurchases() there, in loadProducts// because they can't be called together// here we use results from _restore() to define if need to redirect user   to payments or not// has only resolve functionthis.getActiveSubscription = function () {// _restore doesn't have rejectreturn _restore().then(function (subscriptions) {//we are able to not use result, because we have it's local copyswitch (window.device.platform) {case "iOS":// return false or subscription cut objectreturn _receipt.purchaseState === 0&& {productId: _receipt.productId, receipt: _receipt};break;case "Android":var _activeSubscriptions = _subscriptions.filter(function (subscription) {return subscription.receipt.purchaseState == 0;});// return 0 or subscription objectreturn _activeSubscriptions.length &&   _activeSubscriptions[0];break;default: //this shouldn't be used because of _checkDevicereturn false; // return falsebreak;}});};
  • false, in case of an error or lack of active subscription;
  • the object of active purchase, in case of successful subscription.
//if success - choose state to go tofunction _onSuccessLogin () {// check gotten active subscriptionif (!window.device|| !window.device.platform !== 'iOS'|| !InAppPurchasesService.getReceipt().productId) {$state.go('termsOfUse');} else {IonicPopupWrapperService.confirm({template: 'Would you like to subscribe?',ok_cb: function () {$state.go('inAppPurchases');}});}}
<ion-list class="list"show-delete="false"can-swipe="false"><ion-item ng-repeat-start="purchase in IAP"ng-click="check($index);"><i class="radio pt-color-balanced"ng-class="{'ion-ios-circle-outline':!purchase.checked,   'ion-ios-checkmark':purchase.checked}"></i><span>{{purchase.description}}</span></ion-item><span ng-repeat-end="">Subscribe to Purchase Service {{purchase.description}} for   {{purchase.price}} per month.The subscription will give user a full application functionality.This subscription will automatically renew until canceled.</span></ion-list>
this.subscribe = function () {  return inAppPurchase  .subscribe(_product.id)  .then(function (data) {    _restore ();    return data;  });};
$ gulp$ сordova plugin add cordova-plugin-statusbar$ cordova plugin add ionic-plugin-keyboard$ cordova plugin add cordova-plugin-device$ cordova plugin add cordova-plugin-splashscreen$ cordova plugin add cordova-plugin-network-information$ cordova plugin add cordova-plugin-code-push@latest
$ cordova platform add ios$ ionic resources$ cordova build ios

#6. Terms of Use & Privacy Policy

And it will be rejected!.. That’s because you need to add 2 more pages to the application: “Terms of Use” & “Privacy Policy”!

[
{
"id": 1,
"name": "termsOfUse",
"content": "<p class=\"pt-bold\">Last updated: 11.01.17</p><p>Please read these Terms of Use (\"Terms\", \"Terms of Service\") carefully before using the Plan To Table app operated by Ron Wilson</p><p>Your access to and use of the Service is conditioned on your acceptance of and compliance with these Terms. These Terms apply to all visitors, users and others who access or use the Service.</p><p>By accessing or using the Service you agree to be bound by these Terms. If you disagree with any part of the terms then you may not access the Service.</p><p class=\"pt-bold\">Termination</p><p>We may terminate or suspend access to our Service immediately, without prior notice or liability, for any reason whatsoever, including without limitation if you breach the Terms.</p><p>All provisions of the Terms which by their nature should survive termination shall survive termination, including, without limitation, ownership provisions, warranty disclaimers, indemnity and limitations of liability. Create your own Terms of S</p><p class=\"pt-bold\">Links To Other Web Sites</p><p>Our Service may contain links to third­party web sites or services that are not owned or controlled by Plan to Table</p><p>Plan to Table has no control over, and assumes no responsibility for, the content, privacy policies, or practices of any third party web sites or services. You further acknowledge and agree that Plan to Table shall not be responsible or liable, directly or indirectly, for any damage or loss caused or alleged to be caused by or in connection with use of or reliance on any such content, goods or services available on or through any such web sites or services.</p><p>We strongly advise you to read the terms and conditions and privacy policies of any third­party web sites or services that you visit.</p><p class=\"pt-bold\">In-app purchases</p><p>Our Service provide in-app subscriptions. After registration user will have 14 days free trial period. After that our app will ask to make auto renewable subscription. It will cost 9.99 USD per month, and will be charged automatically for every month.</p><p>– Payment will be charged to iTunes Account at confirmation of purchase</p><p>– Subscription automatically renews unless auto-renew is turned off at least 24-hours before the end of the current period</p><p></p><p>– Account will be charged for renewal within 24-hours prior to the end of the current period, and identify the cost of the renewal</p><p>– Subscriptions may be managed by the user and auto-renewal may be turned off by going to the user's Account Settings after purchase</p><p>– Any unused portion of a free trial period, if offered, will be forfeited when the user purchases a subscription to that publication, where applicable</p><p class=\"pt-bold\">Governing Law</p><p>These Terms shall be governed and construed in accordance with the laws of Country USA, without regard to its conflict of law provisions.</p><p>Our failure to enforce any right or provision of these Terms will not be considered a waiver of those rights. If any provision of these Terms is held to be invalid or unenforceable by a court, the remaining provisions of these Terms will remain in effect. These Terms constitute the entire agreement between us regarding our Service, and supersede and replace any prior agreements we might have between us regarding the Service.</p><p class=\"pt-bold\">Changes</p><p>We reserve the right, at our sole discretion, to modify or replace these Terms at any time. If a revision is material we will try to provide at least 30 days notice prior to any new terms taking effect. If you do not agree to the new terms, please stop using the Service.</p>",
"createdAt": null,
"updatedAt": null
},
{
"id": 2,
"name": "privatePolicy",
"content": "<p class=\"pt-bold\">Last updated: 11.01.17</p><p>Plan to Table, operates by Ron Wilson. This page informs you of our policies regarding the collection, use and disclosure of</p><p>Personal Information we receive from users of the App.</p><p>We use your Personal Information only for providing and improving the App. By using the App, you agree to the collection and use of information in accordance with this policy.</p><p class=\"pt-bold\">Information Collection And Use</p><p>While using our App, we may ask you to provide us with certain personally identifiable information that can be used to contact or identify you. Personally identifiable information may include, but is not limited to your name (\"Personal Information\").</p><p class=\"pt-bold\">Log Data</p><p>Like many App operators, we collect information that your sends whenever you use our App (\"Log Data\").</p><p>This Log Data may include information such as your device Internet Protocol (\"IP\") address, the pages of our App that you visit, the time and date of your visit, the time spent on those pages and other statistics.</p><p>In addition, we may use third party services such as Google Analytics that collect, monitor and analyze this.</p><p class=\"pt-bold\">Communications</p><p>We may use your Personal Information to contact you with newsletters, marketing or promotional materials and other information.</p><p class=\"pt-bold\">Security</p><p>The security of your Personal Information is important to us, but remember that no method of transmission over the Internet, or method of electronic storage, is 100% secure. While we strive to use commercially acceptable means to protect your Personal Information, we cannot guarantee its absolute security.</p><p class=\"pt-bold\">Changes To This Privacy Policy</p><p>This Privacy Policy is effective as of (add date) and will remain in effect except with respect to any changes in its provisions in the future, which will be in effect immediately after being posted on this page.</p><p>We reserve the right to update or change our Privacy Policy at any time and you should check this Privacy Policy periodically. Your continued use of the Service after we post any modifications to the Privacy Policy on this page will constitute your acknowledgment of the modifications and your consent to abide and be bound by the modified Privacy Policy.</p><p>If we make any material changes to this Privacy Policy, we will notify you either through the email address you have provided us, or by placing a prominent notice on our website.</p><p class=\"pt-bold\">Contact Us</p><p>If you have any questions about this Privacy Policy, please contact us</p>",
"createdAt": null,
"updatedAt": null
}
]

#7. IPv6

Finally, if the application works correctly, the App Store will definitely approve it. But if you have a backend, but there is no way to reach it through IPv6 — you’ll most probably get another rejection…

#8. Canceling automatic subscription

How can a user cancel subscription in your app? I’m glad to answer this question straightaway! It’s possible on Android, but not trivial. On iPhone, it’s impossible. The most that you can do for your users if they want to unsubscribe is to redirect them to the right page where they just need to press one button and the subscription will be canceled.

Conclusion

Never promise to submit the app tomorrow! Especially when it has in-app purchases. If someone asks you why, just give a link to this article.

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Igor Izraylevych

Co-founder and CEO of S-PRO, Entrepreneur, Advisor & Expert in Mobility & IT Strategy. Custom solutions for enterprise and startups http://s-pro.io/