Implement In-app purchase in Ionic 4 apps (iOS)
Tags: ionic, ios, inapppurchase
Published: 2020-03-28 11:56:36

<main role="main"><article class=" u-minHeight100vhOffset65 u-overflowHidden postArticle postArticle--full is-supplementalPostContentLoaded is-withAccentColors" lang="en"><div class="postArticle-content js-postField js-notesSource editable" id="editor_6" g_editable="true" role="textbox" contenteditable="true" data-default-value="Title
Tell your story…" spellcheck="false"><section name="4eaa" class="section section--body section--first section--last"><div class="section-divider"><hr class="section-divider"></div><div class="section-content"><div class="section-inner sectionLayout--insetColumn"><p name="9268" class="graf graf--p graf-after--figure">In this post, you’ll learn how to implement the famous (and infamous) In-App Purchase functionality in iOS apps using Ionic 4.</p><blockquote name="61a2" class="graf graf--blockquote graf-after--p"><strong class="markup--strong markup--blockquote-strong">Complete code of this post can be found in the Github repository </strong><a href="https://github.com/enappd/ionic-4-in-app-purchase"  class="markup--anchor markup--blockquote-anchor" rel="noopener"    target="_blank"><strong class="markup--strong markup--blockquote-strong">ionic-4-in-app-purchase</strong></a></blockquote><p name="63e5" class="graf graf--p graf-after--blockquote">I have another post explaining the <a href="https://enappd.com/blog/in-app-purchase-in-android-app-using-ionic-4/97"  class="markup--anchor markup--p-anchor" rel="noopener"    target="_blank">In-app purchase implementation for Android apps</a>.</p><blockquote name="3916" class="graf graf--blockquote graf-after--p">Read the ** marked sections only if you haven’t gone through the Android post for In-app purchase, otherwise ignore these ** sections.</blockquote><h3 name="b231" class="graf graf--h3 graf-after--blockquote">What is In-app purchase, again&nbsp;?&nbsp;**</h3><p name="4c51" class="graf graf--p graf-after--h3">In-App Purchase is the functionality that lets you purchase items from within your mobile apps. These are different from other payment gateways in the sense that the payment is taken care of by Google Play store or Apple App store itself. These one-time purchases are money in the bank for app developers, while the app store also takes its share.</p><h4 name="ca44" class="graf graf--h4 graf-after--p">Types of In-app&nbsp;purchase</h4><p name="8d15" class="graf graf--p graf-after--h4">There are four types of products / purchases available using In-app purchase method</p><ol class="postList"><li name="9c16" class="graf graf--li graf-after--p"><strong class="markup--strong markup--li-strong">Consumable</strong>&#8202;—&#8202;Consumable allow the user to buy a certain item once. Often used in game apps, one-time in-app purchases can give you added functionality like extra characters, extra life, new powers etc. This purchase can be done again and again, e.g. You can buy more and more lives for your game character.<br>E.g. Buying a life in Candy Crush&nbsp;?</li><li name="da98" class="graf graf--li graf-after--li"><strong class="markup--strong markup--li-strong">Non-Consumable</strong>&#8202;—&#8202;This type of product can be bought only once, and it never expires. This can be used for something like a premium membership in the app, or you can say “<strong class="markup--strong markup--li-strong">unlock</strong>” feature<br>E.g. Getting a premium membership of an app for lifetime</li><li name="6f20" class="graf graf--li graf-after--li"><strong class="markup--strong markup--li-strong">Non-renewable Subscriptions</strong>&#8202;—&#8202;Subscription is different from one time payment, it is supposed to run for a period of time and then it expires. Non-renewable Subscription expires after a set period of time and does not renew automatically.&nbsp;<br>E.g. Premium membership of Netflix (Did they become auto-renewable&nbsp;? I need to check my credit card bills)</li><li name="efa6" class="graf graf--li graf-after--li"><strong class="markup--strong markup--li-strong">Auto-renewable Subscriptions</strong>&#8202;—&#8202;Auto-renewable Subscription expires after a set period of time and renews automatically. This is the most preferred choice for subscription based apps. But this option also faces the maximum scrutiny from app store reviews.<br>E.g. Premium membership of Tinder</li></ol><h3 name="96c0" class="graf graf--h3 graf-after--li">Why is In-app purchase so important&nbsp;?</h3><p name="1f5f" class="graf graf--p graf-after--h3">In-app purchases can give you major advantages in terms of sales. Following are few reason why In-app purchases are so important</p><ul class="postList"><li name="7922" class="graf graf--li graf-after--p"><strong class="markup--strong markup--li-strong">Creative Control&#8202;</strong>—&#8202;While most of the payment gateways require you to have the payment UI a certain way, In-app purchases allows you to be as creative as you want in terms of UI and UX. Because everything is integrated inside the app itself, the payment becomes a part of the app, rather than a third-party service.</li><li name="bbda" class="graf graf--li graf-after--li"><strong class="markup--strong markup--li-strong">Freemium model</strong>&#8202;—&#8202;You allow the user to “try” the free version before investing even a few cents into the rest of your app and when they are convinced to upgrade no additional trip into the app store is required. This way your user engagement increases, and more users convert to paid ones.</li><li name="8bef" class="graf graf--li graf-after--li"><strong class="markup--strong markup--li-strong">Less user interaction, better UX</strong>&#8202;—&#8202;In-app purchase only takes a single tap. Sending the user to the App/Play Store to buy other products requires at least 2 or more taps. Even more if you integrate payment gateways in the app</li><li name="e2a3" class="graf graf--li graf-after--li"><strong class="markup--strong markup--li-strong">Allows variety of options&#8202;—&#8202;</strong>As we discussed above, the four types of in-app purchase products can provide a wide variety of product and add-on experience for your users. Creating the same experience using a third-party payment gateway can be cumbersome for developers</li><li name="85b3" class="graf graf--li graf-after--li"><strong class="markup--strong markup--li-strong">Reliable Google and Apple ecosystem</strong>&#8202;—&#8202;Since the in-app purchase is offered by Google and Apple themselves, it can be assumed to be of highest quality. Any app containing in-app purchase is reviewed very closely before being allowed to published. So users can rest assured that these apps are least risky in terms of payment issues etc.</li><li name="cf8c" class="graf graf--li graf-after--li"><strong class="markup--strong markup--li-strong">Regularly updated</strong>&#8202;—&#8202;Since the in-app purchase is an App/Play store feature itself, it can be safely assumed that these functionalities will be regularly updated by the platforms as iOS and Android versions change. While the same cannot be said about third-party services, which struggle to update when a new version of Android / iOS is released in market</li></ul><h3 name="e1db" class="graf graf--h3 graf-after--li">What is Ionic&nbsp;4?</h3><p name="56d0" class="graf graf--p graf-after--h3">You probably already know about Ionic, but I’m putting it here just for the sake of beginners. <strong class="markup--strong markup--p-strong">Ionic</strong> is a complete open-source SDK for hybrid mobile app development created by <a href="https://medium.com/u/a76fa51de1ba?source=post_page---------------------------"  class="markup--anchor markup--p-anchor"    target="_blank">Max Lynch</a>, <a href="https://medium.com/u/14b1be5c1354?source=post_page---------------------------"  class="markup--anchor markup--p-anchor"    target="_blank">Ben Sperry</a> and Adam Bradley of Drifty Co. in 2013. Ionic provides tools and services for developing hybrid mobile apps using Web technologies like CSS, HTML5, and Sass. Apps can be built with these Web technologies and then distributed through native app stores to be installed on devices by leveraging Cordova.</p><p name="010c" class="graf graf--p graf-after--p">So, in other words&#8202;—&#8202;If you create Native apps in Android, you code in Java. If you create Native apps in iOS, you code in Obj-C or Swift. Both of these are powerful but complex languages. <strong class="markup--strong markup--p-strong">With Cordova (and Ionic) you can write a single piece of code for your app that can run on both iOS and Android </strong>(and windows!), that too with the simplicity of HTML, CSS, and JS.</p><h3 name="2084" class="graf graf--h3 graf-after--p">Structure of the&nbsp;post</h3><p name="3e7c" class="graf graf--p graf-after--h3">I will go ahead in step-by-step fashion so you can follow easily</p><ol class="postList"><li name="fa3c" class="graf graf--li graf-after--p">Setup your app in iOS App Store</li><li name="3841" class="graf graf--li graf-after--li">Setup In-app purchase on App Store Connect</li><li name="01f7" class="graf graf--li graf-after--li">Create a basic Ionic 4 app</li><li name="e477" class="graf graf--li graf-after--li">Setup the In-App purchase plugin</li><li name="7923" class="graf graf--li graf-after--li">Test the app on iOS device</li><li name="0117" class="graf graf--li graf-after--li">Detailed study on In-app purchase functions</li><li name="1ffa" class="graf graf--li graf-after--li">Keep in mind&nbsp;!</li><li name="1472" class="graf graf--li graf-after--li">Subscriptions and Receipt validations</li></ol><h3 name="d8de" class="graf graf--h3 graf-after--li">Step 1&#8202;—&#8202;Setup your app in App&nbsp;Store</h3><p name="44db" class="graf graf--p graf-after--h3"><strong class="markup--strong markup--p-strong">You don’t need to do this step if you already have an iOS app and identifier registered.</strong></p><p name="4e9f" class="graf graf--p graf-after--p">First of all, you will need to become an iOS developer on App Store. This requires a membership, worth USD 99&nbsp;, and it needs to be renewed every year (unlike Google Play’s one time payment).</p><blockquote name="2589" class="graf graf--blockquote graf-after--p">Apple Developer Console takes care of certificates, identifiers etc. App Store Connect takes care of all the app side stuff.</blockquote><h4 name="f809" class="graf graf--h4 graf-after--blockquote">Apple Developer Console&nbsp;Steps</h4><p name="7fe3" class="graf graf--p graf-after--h4">Once you have your Apple developer account, login to <a href="https://developer.apple.com/account"  class="markup--anchor markup--p-anchor" rel="noopener" target="_blank">https://developer.apple.com/account</a> to access all your certificates and profiles.</p><figure tabindex="0" contenteditable="false" name="ec41" class="graf graf--figure graf-after--p"><div class="aspectRatioPlaceholder is-locked" style="max-width: 700px; max-height: 403px;"><div class="aspectRatioPlaceholder-fill" style="padding-bottom: 57.49999999999999%;"></div><img class="graf-image" data-image-id="1*7oLBhIgWp45IMtp10kPelQ.png" data-width="800" data-height="460" alt="Apple developer account shows you info about all Certificates, profiles, devices etc" src="https://cdn-images-1.medium.com/max/800/1*7oLBhIgWp45IMtp10kPelQ.png"><div class="crosshair u-ignoreBlock"></div></div><br/><figcaption class="imageCaption" contenteditable="true" data-default-value="Type caption for image (optional)">Apple developer account shows you info about all Certificates, profiles, devices&nbsp;etc</figcaption></figure><p name="4a78" class="graf graf--p graf-after--figure">In the Developer console, create a new identifier for your app (if you don’t have one already). Identifier is the bundle ID of your app. This helps the App Store identify which app is connected to what in-app purchase products, essentially</p><figure tabindex="0" contenteditable="false" name="2611" class="graf graf--figure graf-after--p"><div class="aspectRatioPlaceholder is-locked" style="max-width: 700px; max-height: 252px;"><div class="aspectRatioPlaceholder-fill" style="padding-bottom: 36%;"></div><img class="graf-image" data-image-id="1*_VsX0JsiUtp5depN5Y2tNw.png" data-width="1364" data-height="491" alt="App store- Enter the bundle ID to create an identifier" src="https://cdn-images-1.medium.com/max/800/1*_VsX0JsiUtp5depN5Y2tNw.png"><div class="crosshair u-ignoreBlock"></div></div><br/><figcaption class="imageCaption" contenteditable="true" data-default-value="Type caption for image (optional)">App store- Enter the bundle ID to create an identifier</figcaption></figure><p name="170c" class="graf graf--p graf-after--figure">Also, you’ll see that In-app purchase features is pre-selected in the feature list.</p><figure tabindex="0" contenteditable="false" name="85db" class="graf graf--figure graf-after--p"><div class="aspectRatioPlaceholder is-locked" style="max-width: 700px; max-height: 179px;"><div class="aspectRatioPlaceholder-fill" style="padding-bottom: 25.6%;"></div><img class="graf-image" data-image-id="1*JbxXo8CdtPm49Ehd8vm3Jw.png" data-width="1307" data-height="334" alt="In-app purchase is preset in the new identifier" src="https://cdn-images-1.medium.com/max/800/1*JbxXo8CdtPm49Ehd8vm3Jw.png"><div class="crosshair u-ignoreBlock"></div></div><br/><figcaption class="imageCaption" contenteditable="true" data-default-value="Type caption for image (optional)">In-app purchase is preset in the new identifier</figcaption></figure><p name="1ca0" class="graf graf--p graf-after--figure">Go ahead and register your identifier.</p><figure tabindex="0" contenteditable="false" name="0bfb" class="graf graf--figure graf-after--p"><div class="aspectRatioPlaceholder is-locked" style="max-width: 700px; max-height: 379px;"><div class="aspectRatioPlaceholder-fill" style="padding-bottom: 54.1%;"></div><img class="graf-image" data-image-id="1*tYQ0hS-Re1sz6cHbAKktWA.png" data-width="800" data-height="433" alt="Newly created identifier in your Apple Developer Console" src="https://cdn-images-1.medium.com/max/800/1*tYQ0hS-Re1sz6cHbAKktWA.png"><div class="crosshair u-ignoreBlock"></div></div><br/><figcaption class="imageCaption" contenteditable="true" data-default-value="Type caption for image (optional)">Newly created identifier in your Apple Developer Console</figcaption></figure><h4 name="9270" class="graf graf--h4 graf-after--figure">App Store connect&nbsp;Steps</h4><p name="ddc4" class="graf graf--p graf-after--h4">Previously called, iTunes connect, this is the place where you will find all your apps uploaded, prepare app store listings, add in-app purchase products, beta test etc.</p><p name="dcb1" class="graf graf--p graf-after--p">At this point, you have created an <code class="markup--code markup--p-code">identifier</code> in Apple developer console, but you’ll also need to create corresponding app in App Store Connect as well.</p><p name="b94b" class="graf graf--p graf-after--p">Log in to your App Store Connect account, go to <strong class="markup--strong markup--p-strong">My Apps. </strong>Add a new app for iOS from the <code class="markup--code markup--p-code">+</code> button</p><figure tabindex="0" contenteditable="false" name="c041" class="graf graf--figure graf-after--p"><div class="aspectRatioPlaceholder is-locked" style="max-width: 700px; max-height: 338px;"><div class="aspectRatioPlaceholder-fill" style="padding-bottom: 48.199999999999996%;"></div><img class="graf-image" data-image-id="1*fDep8lsg2LL0DDp37C4rQA.png" data-width="1381" data-height="666" src="https://cdn-images-1.medium.com/max/800/1*fDep8lsg2LL0DDp37C4rQA.png"><div class="crosshair u-ignoreBlock"></div></div><br/><figcaption class="imageCaption" contenteditable="true" data-default-value="Type caption for image (optional)">Add new app in App Store&nbsp;Connect</figcaption></figure><p name="7501" class="graf graf--p graf-after--figure">You’ll land on the app information page now. Next, we’ll create In-app purchase products.</p><h3 name="3a0b" class="graf graf--h3 graf-after--p">Step 2&#8202;—&#8202;Setup In-app purchase on App Store&nbsp;Connect</h3><p name="452f" class="graf graf--p graf-after--h3">You can create in-app products in App Store Connect dashboard, even without uploading first build of the app (unlike Android, where you need to upload first APK to even add an in-app purchase product)</p><p name="a80a" class="graf graf--p graf-after--p">Go to Features tab → In-app purchases → Add new product using <code class="markup--code markup--p-code">+</code></p><figure tabindex="0" contenteditable="false" name="323e" class="graf graf--figure graf-after--p"><div class="aspectRatioPlaceholder is-locked" style="max-width: 700px; max-height: 313px;"><div class="aspectRatioPlaceholder-fill" style="padding-bottom: 44.7%;"></div><img class="graf-image" data-image-id="1*3liB4lM_O0OGxTYDnU-1cg.png" data-width="1386" data-height="619" alt="Add new in-app purchase product in App store connect" src="https://cdn-images-1.medium.com/max/800/1*3liB4lM_O0OGxTYDnU-1cg.png"><div class="crosshair u-ignoreBlock"></div></div><br/><figcaption class="imageCaption" contenteditable="true" data-default-value="Type caption for image (optional)">Add new in-app purchase product in App store&nbsp;connect</figcaption></figure><p name="1d58" class="graf graf--p graf-after--figure">Let’s create a Consumable for now (which is the same as I did in <a href="https://enappd.com/blog/in-app-purchase-in-android-app-using-ionic-4/97"  class="markup--anchor markup--p-anchor" rel="noopener"    target="_blank">Android blog</a>).</p><ul class="postList"><li name="c38d" class="graf graf--li graf-after--p">Create the product, then add name, description and a 1024x1024 JPG icon for the same</li><li name="ccaf" class="graf graf--li graf-after--li">Add Product ID, you’ll need this in your code</li><li name="f897" class="graf graf--li graf-after--li">Add a price for the product (minimum is $1)</li><li name="10d8" class="graf graf--li graf-after--li">Add a screenshot and details at the bottom</li><li name="2209" class="graf graf--li graf-after--li">Make sure you check <code class="markup--code markup--li-code">Cleared for Sale</code></li></ul><p name="4380" class="graf graf--p graf-after--li">You’ll see a <code class="markup--code markup--p-code">ready to submit</code> on the top of the page. Don’t worry for now, we’ll handle that later.</p><p name="d932" class="graf graf--p graf-after--p">You’ll see your product listed in the in-app purchases tab now.</p><figure tabindex="0" contenteditable="false" name="4377" class="graf graf--figure graf-after--p"><div class="aspectRatioPlaceholder is-locked" style="max-width: 700px; max-height: 273px;"><div class="aspectRatioPlaceholder-fill" style="padding-bottom: 39%;"></div><img class="graf-image" data-image-id="1*FBITwrZ-3jpFyj-OwAJrAw.png" data-width="1132" data-height="441" src="https://cdn-images-1.medium.com/max/800/1*FBITwrZ-3jpFyj-OwAJrAw.png"><div class="crosshair u-ignoreBlock"></div></div><br/><figcaption class="imageCaption" contenteditable="true" data-default-value="Type caption for image (optional)">New in-app purchase product listed in App Store&nbsp;connect</figcaption></figure><h4 name="833a" class="graf graf--h4 graf-after--figure">Create iOS Sandbox&nbsp;Users</h4><p name="110e" class="graf graf--p graf-after--h4">To test your In-App Purchase, you will need a “Sandbox” user account. Enter the “Manage users” section of AppStore Connect to create one (or more).</p><figure tabindex="0" contenteditable="false" name="7681" class="graf graf--figure graf-after--p"><div class="aspectRatioPlaceholder is-locked" style="max-width: 700px; max-height: 330px;"><div class="aspectRatioPlaceholder-fill" style="padding-bottom: 47.099999999999994%;"></div><img class="graf-image" data-image-id="1*j3pBuLiDcN7YrgTUljPowQ.png" data-width="1366" data-height="643" alt="Add new Sandbox test user in App Store connect" src="https://cdn-images-1.medium.com/max/800/1*j3pBuLiDcN7YrgTUljPowQ.png"><div class="crosshair u-ignoreBlock"></div></div><br/><figcaption class="imageCaption" contenteditable="true" data-default-value="Type caption for image (optional)">Add new Sandbox test user in App Store&nbsp;connect</figcaption></figure><p name="af5b" class="graf graf--p graf-after--figure"><strong class="markup--strong markup--p-strong">Note:</strong> that if you mistakenly use your test-user-account credentials to log in to a production environment on your test device (instead of in to your test environment), your account credentials become invalid and cannot be used as a test account again. If a test user have mysteriously stopped working, try creating a new Sandbox user.</p><blockquote name="d827" class="graf graf--blockquote graf-after--p"><strong class="markup--strong markup--blockquote-strong">Important</strong>&nbsp;: To be able to use iOS In-app purchase, you need to have all Tax and Banking information updated and approved in App Store Connect. Also, you’ll have to agree to all Apple agreements pending in <strong class="markup--strong markup--blockquote-strong">Agreements, tax and banking</strong> section.</blockquote><figure tabindex="0" contenteditable="false" name="b52f" class="graf graf--figure graf-after--blockquote"><div class="aspectRatioPlaceholder is-locked" style="max-width: 700px; max-height: 184px;"><div class="aspectRatioPlaceholder-fill" style="padding-bottom: 26.3%;"></div><img class="graf-image" data-image-id="1*S46cUraOH8wu2vsvsBsFTQ.png" data-width="1381" data-height="363" alt="App Store Connect requires you to accept all agreements, and enter Tax and Banking info for In-App Purchases" src="https://cdn-images-1.medium.com/max/800/1*S46cUraOH8wu2vsvsBsFTQ.png"><div class="crosshair u-ignoreBlock"></div></div><br/><figcaption class="imageCaption" contenteditable="true" data-default-value="Type caption for image (optional)">App Store Connect requires you to accept all agreements, and enter Tax and Banking info for In-App Purchases</figcaption></figure><h3 name="bf32" class="graf graf--h3 graf-after--figure">Step 3— Create a basic Ionic 4&nbsp;app</h3><blockquote name="ee25" class="graf graf--blockquote graf-after--h3"><em class="markup--em markup--blockquote-em">I have covered this topic in detail in </em><a href="https://enappd.com/blog/how-to-create-an-ionic-4-app-for-beginners/13/?source=post_page---------------------------"  class="markup--anchor markup--blockquote-anchor" rel="noopener"    target="_blank"><em class="markup--em markup--blockquote-em">this blog</em></a><em class="markup--em markup--blockquote-em">.</em></blockquote><p name="7cf9" class="graf graf--p graf-after--blockquote">In short, the steps you need to take here are</p><ul class="postList"><li name="9e47" class="graf graf--li graf-after--p">Make sure you have node installed in the system (V10.15.3 at the time of this blog post)</li><li name="622c" class="graf graf--li graf-after--li">Install <strong class="markup--strong markup--li-strong">ionic cli </strong>using npm (my Ionic version is 4.7.4 currently)</li><li name="9de3" class="graf graf--li graf-after--li">Create an Ionic app using <code class="markup--code markup--li-code">ionic start</code></li></ul><p name="edf3" class="graf graf--p graf-after--li">You can create a <code class="markup--code markup--p-code">blank</code> starter for the sake of this tutorial. On running <code class="markup--code markup--p-code">ionic start ionic-4-in-app-purchase blank</code>&nbsp;, node modules will be installed. Once the installation is done, run your app on browser using</p><pre name="e3ab" class="graf graf--pre graf-after--p">$ ionic serve</pre><p name="5c38" class="graf graf--p graf-after--pre">The app will launch on browser. You can go to <strong class="markup--strong markup--p-strong">Inspect → Device Mode</strong> to see the code in a mobile layout. You can create a basic layout for In-app purchase, or you can just use a simple button for all actions, doesn’t matter. All the real action will happen when we build the app for iOS on device. Here’s how my layout looks like (layout taken from <a href="https://store.enappd.com/product/ionic-4-woocommerce-starter/"  class="markup--anchor markup--p-anchor" rel="noopener"    target="_blank">Woocommerce Ionic Starter</a>)</p><figure tabindex="0" contenteditable="false" name="bb1f" class="graf graf--figure graf-after--p"><div class="aspectRatioPlaceholder is-locked" style="max-width: 350px; max-height: 623px;"><div class="aspectRatioPlaceholder-fill" style="padding-bottom: 178%;"></div><img class="graf-image" data-image-id="1*IZmVqodx_-ikRjddhUae1g.png" data-width="350" data-height="623" alt="Basic layout for in-app purchase sample app" src="https://cdn-images-1.medium.com/max/800/1*IZmVqodx_-ikRjddhUae1g.png"><div class="crosshair u-ignoreBlock"></div></div><br/><figcaption class="imageCaption" contenteditable="true" data-default-value="Type caption for image (optional)">Basic layout for in-app purchase sample&nbsp;app</figcaption></figure><h3 name="39d2" class="graf graf--h3 graf-after--figure">Step 4— Setup the In-App purchase plugin in&nbsp;app</h3><p name="8312" class="graf graf--p graf-after--h3">To implement In-app purchase functionality, we’ll use the plugin <code class="markup--code markup--p-code"><a href="https://github.com/j3k0/cordova-plugin-purchase"  class="markup--anchor markup--p-anchor" rel="noopener"    target="_blank">cordova-plugin-purchase</a></code>&nbsp;. This is also available as Ionic Native.</p><h4 name="32cb" class="graf graf--h4 graf-after--p">Install plugin</h4><p name="7b5f" class="graf graf--p graf-after--h4">Install the plugin using</p><pre name="5b2e" class="graf graf--pre graf-after--p">$ ionic cordova plugin add <code class="markup--code markup--pre-code">"https://github.com/j3k0/cordova-plugin-purchase.git#v9"</code></pre><blockquote name="2ad5" class="graf graf--blockquote graf-after--pre"><strong class="markup--strong markup--blockquote-strong">I am using the repository from Github directly, as this change is recently made and not available in npm</strong></blockquote><p name="d51d" class="graf graf--p graf-after--blockquote">Once installed, include the module in your <code class="markup--code markup--p-code">app.module.ts</code> as well as in your page where you will implement in-app purchase</p><pre name="892a" class="graf graf--pre graf-after--p">// app.module.ts<br>import { InAppPurchase2 } from '@ionic-native/in-app-purchase-2';...<br>  providers: [ InAppPurchase2 ]<br>...</pre><p name="eb9e" class="graf graf--p graf-after--pre">and in your <code class="markup--code markup--p-code">cart.page.ts</code></p><pre name="93af" class="graf graf--pre graf-after--p">// cart.page.ts<br>import { InAppPurchase2 } from '@ionic-native/in-app-purchase-2';<br>...<br><code class="markup--code markup--pre-code">constructor(public platform: Platform, private store: InAppPurchase2) {...}</code></pre><h4 name="75ec" class="graf graf--h4 graf-after--pre">Implement plugin&nbsp;methods</h4><p name="ba76" class="graf graf--p graf-after--h4">In-app purchase works broadly in four steps</p><ol class="postList"><li name="2f9b" class="graf graf--li graf-after--p">Check if platform and store is ready</li><li name="e4bb" class="graf graf--li graf-after--li">Register your product with product ID (we’ll create product in Play Store in Section 5). Register multiple products if you have.</li><li name="30ae" class="graf graf--li graf-after--li">Register handles for a particular product’s purchase. These handles are event listeners, which will listen if the purchase was successful, failed etc.</li><li name="6203" class="graf graf--li graf-after--li">Purchase&#8202;—&#8202;If above steps go fine, you can start the purchase flow, which will be handled by Google’s native in-app purchase UI. This will ask for authentication on your phone before purchase</li></ol><p name="bec0" class="graf graf--p graf-after--li">Let’s me first print out the <code class="markup--code markup--p-code">cart.page.ts</code> file here, and then we’ll discuss the methods</p><figure tabindex="0" contenteditable="false" name="a4c6" class="graf graf--figure graf--iframe graf-after--p is-defaultValue"><div class="aspectRatioPlaceholder is-locked"><div class="aspectRatioPlaceholder-fill" style="padding-bottom: 35.699999999999996%;"></div><div class="iframeContainer">{% gist https://gist.github.com/enappd/a570068687a3f9b46f6b6929a04e3d9f.js %}</div></div></figure><p name="1005" class="graf graf--p graf-after--figure">Let’s go through the code step-by-step</p><ol class="postList"><li name="9c65" class="graf graf--li graf-after--p"><strong class="markup--strong markup--li-strong">Check for Platform ready</strong>&#8202;—&#8202;All store function will strictly run only inside Platform ready. If you don’t put your functions inside it, it can throw a <code class="markup--code markup--li-code">plugin not installed</code> error</li><li name="4adf" class="graf graf--li graf-after--li"><strong class="markup--strong markup--li-strong">Register product</strong>&#8202;—&#8202;Registering a product basically validates the product with Play store if the product really exists, and if the type and ID of product is correct. Any purchase or refresh action should be performed only after registration</li><li name="eada" class="graf graf--li graf-after--li"><strong class="markup--strong markup--li-strong">Event handlers</strong>&#8202;—&#8202;There are several event handlers registered for different events of the purchase process. Let’s see the important ones</li></ol><ul class="postList"><li name="d028" class="graf graf--li graf-after--li"><strong class="markup--strong markup--li-strong">loaded</strong>: Called when product data is loaded from the store</li><li name="cf5a" class="graf graf--li graf-after--li"><strong class="markup--strong markup--li-strong">updated</strong>: Called when any change occurred to a product</li><li name="e458" class="graf graf--li graf-after--li"><strong class="markup--strong markup--li-strong">error</strong>: Called when an order failed. The `err` parameter is an IAPError object</li><li name="83c2" class="graf graf--li graf-after--li"><strong class="markup--strong markup--li-strong">approved</strong>: Called when a product order is approved</li><li name="bf9c" class="graf graf--li graf-after--li"><strong class="markup--strong markup--li-strong">owned</strong>: Called when a non-consumable product or subscription is owned</li><li name="680e" class="graf graf--li graf-after--li"><strong class="markup--strong markup--li-strong">cancelled</strong>: Called when a product order is cancelled by the user</li><li name="6702" class="graf graf--li graf-after--li"><strong class="markup--strong markup--li-strong">refunded</strong>: Called when an order is refunded by the user</li><li name="44ec" class="graf graf--li graf-after--li"><strong class="markup--strong markup--li-strong">registered</strong>: Called when product has just been registered</li><li name="ddca" class="graf graf--li graf-after--li"><strong class="markup--strong markup--li-strong">valid</strong>: Called when the product details have been successfully loaded</li><li name="1864" class="graf graf--li graf-after--li"><strong class="markup--strong markup--li-strong">invalid</strong>: Called when the product cannot be loaded from the store</li><li name="7fa6" class="graf graf--li graf-after--li"><strong class="markup--strong markup--li-strong">initiated</strong>: Called when the purchase process has been initiated</li><li name="d8d3" class="graf graf--li graf-after--li"><strong class="markup--strong markup--li-strong">finished</strong>: Called when the purchase process has completed.</li><li name="bf18" class="graf graf--li graf-after--li"><strong class="markup--strong markup--li-strong">expired</strong>: Called when validation find a subscription to be expired.</li></ul><p name="7056" class="graf graf--p graf-after--li">Each of these event can help you detect what the status of the purchase is. To understand the major events in the life-cycle, refer to the flow diagram below</p><figure tabindex="0" contenteditable="false" name="448d" class="graf graf--figure graf-after--p"><div class="aspectRatioPlaceholder is-locked" style="max-width: 700px; max-height: 342px;"><div class="aspectRatioPlaceholder-fill" style="padding-bottom: 48.8%;"></div><img class="graf-image" data-image-id="1*jJAYkGA-nPsXLVrNfPD_Kg.png" data-width="1024" data-height="500" alt="In-app purchase flow" src="https://cdn-images-1.medium.com/max/800/1*jJAYkGA-nPsXLVrNfPD_Kg.png"><div class="crosshair u-ignoreBlock"></div></div><br/><figcaption class="imageCaption" contenteditable="true" data-default-value="Type caption for image (optional)">In-app purchase&nbsp;flow</figcaption></figure><p name="9776" class="graf graf--p graf-after--figure"><strong class="markup--strong markup--p-strong">4. Purchase product</strong>&#8202;—&#8202;The&nbsp;<code class="markup--code markup--p-code">.order</code> method starts the purchase process. This process will be successful only when the product is valid and successfully loaded on app start. On success, you’ll receive an object with product details.</p><p name="bc77" class="graf graf--p graf-after--p">Once the transaction is approved, the product still isn’t owned: the store needs confirmation that the purchase was delivered before closing the transaction.</p><p name="399d" class="graf graf--p graf-after--p">To confirm delivery, you’ll use the <code class="markup--code markup--p-code">product.finish()</code> method.</p><p name="6f19" class="graf graf--p graf-after--p"><strong class="markup--strong markup--p-strong">5. Restore purchase&#8202;</strong>—&#8202;In an app where you use in-app products, you need to check every time if the user has the ownership (has purchased) of the product or not. E.g. you may remove ads in the app based on whether the user has purchased a premium membership.</p><p name="3c7c" class="graf graf--p graf-after--p">This process is done by getting the details of the product after registering. If the user has purchased a particular product, the product will return <code class="markup--code markup--p-code">owned: true</code> in the details fetched by <code class="markup--code markup--p-code">store.get('product_id')</code> method. Accordingly you can take decision in the app.</p><p name="1489" class="graf graf--p graf-after--p"><strong class="markup--strong markup--p-strong">Note</strong>: The product will return <code class="markup--code markup--p-code">owned: true</code> only for products other than <code class="markup--code markup--p-code">CONSUMABLE</code>&nbsp;. Consumable go back to <code class="markup--code markup--p-code">valid</code> state, and purchase can be verified by <code class="markup--code markup--p-code">transaction</code> details in product info</p><h3 name="69b9" class="graf graf--h3 graf-after--p">Step 6&#8202;—&#8202;Test the app on iOS&nbsp;device</h3><blockquote name="df4e" class="graf graf--blockquote graf-after--h3">You cannot test the in-app purchase functionality on iOS simulator. A real device is required.</blockquote><p name="4771" class="graf graf--p graf-after--blockquote">The major step, fingers crossed 🤞</p><h4 name="1acc" class="graf graf--h4 graf-after--p"><strong class="markup--strong markup--h4-strong">Difference from&nbsp;Android</strong></h4><p name="7016" class="graf graf--p graf-after--h4">An iOS app DOES NOT NEED to be published to start testing in-app purchase. This is a major relief for iOS developers, as Android developers have to wait for their alpha/beta/internal testing version to be published before they could even start testing in-app purchase. But iOS will give you pain when you try to submit in-app purchases for production, but that’s for later.</p><h4 name="a4bd" class="graf graf--h4 graf-after--p">Login as Sandbox&nbsp;User</h4><p name="9958" class="graf graf--p graf-after--h4">In your device, log out if already have a login. Then login from your Sandbox user account. Remember that if you mistakenly use your test-user-account credentials to log in to a production environment on your test device (instead of in to your test environment), your account credentials become invalid and cannot be used as a test account again.</p><p name="3d0a" class="graf graf--p graf-after--p">In case you made a “dummy” sandbox user, with a <a href="https://temp-mail.org/en/"  class="markup--anchor markup--p-anchor" rel="noopener"    target="_blank">temp email</a> like me, make sure you verify the user before testing in-app purchase.</p><h4 name="581e" class="graf graf--h4 graf-after--p">Build the&nbsp;app</h4><p name="4edf" class="graf graf--p graf-after--h4">Build the app for iOS using</p><pre name="b314" class="graf graf--pre graf-after--p">$ ionic cordova prepare ios</pre><p name="f3b5" class="graf graf--p graf-after--pre">This will create the <code class="markup--code markup--p-code">xcworkspace</code> file for the iOS project. Open this file in Xcode, and</p><ul class="postList"><li name="657d" class="graf graf--li graf-after--p">Make sure your app bundle ID matches the one provided for In-app purchase app in App Store connect</li><li name="b7a7" class="graf graf--li graf-after--li">Make sure you have a valid certificate for development selected in Xcode</li><li name="497e" class="graf graf--li graf-after--li">Enable In-app purchase capability in app using Xcode</li></ul><figure tabindex="0" contenteditable="false" name="3479" class="graf graf--figure graf-after--li"><div class="aspectRatioPlaceholder is-locked" style="max-width: 700px; max-height: 386px;"><div class="aspectRatioPlaceholder-fill" style="padding-bottom: 55.2%;"></div><img class="graf-image" data-image-id="1*xXovHHb5mirKagaC-4_ikw.png" data-width="852" data-height="470" alt="Toggle in-app purchase capability ON in Xcode" src="https://cdn-images-1.medium.com/max/800/1*xXovHHb5mirKagaC-4_ikw.png"><div class="crosshair u-ignoreBlock"></div></div><br/><figcaption class="imageCaption" contenteditable="true" data-default-value="Type caption for image (optional)">Toggle in-app purchase capability ON in&nbsp;Xcode</figcaption></figure><h4 name="1164" class="graf graf--h4 graf-after--figure">Test the&nbsp;app</h4><p name="d7f9" class="graf graf--p graf-after--h4">Once you build the app in device, it’s straight away time for testing. Click the checkout button, and you’ll be asked for your account password (or finger print) to authorize the purchase. Once you do that, an alert will inform you of a successful purchase.</p><figure tabindex="0" contenteditable="false" name="1ee3" class="graf graf--figure graf-after--p"><div class="aspectRatioPlaceholder is-locked" style="max-width: 350px; max-height: 621px;"><div class="aspectRatioPlaceholder-fill" style="padding-bottom: 177.4%;"></div><img class="graf-image" data-image-id="1*0WrOuiYwMVUHD8FCAB6zsQ.gif" data-width="350" data-height="621" alt="In-app purchase working in iOS" src="https://cdn-images-1.medium.com/max/800/1*0WrOuiYwMVUHD8FCAB6zsQ.gif"><div class="crosshair u-ignoreBlock"></div></div><br/><figcaption class="imageCaption" contenteditable="true" data-default-value="Type caption for image (optional)">In-app purchase working in&nbsp;iOS</figcaption></figure><p name="2502" class="graf graf--p graf-after--figure">You don’t need to have a payment method added with your Apple account for this to work (another surprising relief from Apple&nbsp;! ) 🍎 ✌️</p><h4 name="78c2" class="graf graf--h4 graf-after--p">Test Time Durations for Subscriptions</h4><p name="d345" class="graf graf--p graf-after--h4">iOS makes it very easy to test subscriptions by providing a sample time duration for which the purchase stays valid. When testing auto-renewable in-app purchase subscriptions in the sandbox environment, the duration times will be compressed to allow for more streamlined testing. Additionally, a sandbox subscription will only auto-renew a maximum of 6 times. After the subscription has auto-renewed 6 times, it will no longer renew in the sandbox. The compressed duration times are as follows:</p><pre name="6e00" class="graf graf--pre graf-after--p"><code class="markup--code markup--pre-code">Actual duration      Sandbox duration<br>   1 week               3 minutes <br>   1 month              5 minutes<br>   2 months             10 minutes <br>   3 months             15 minutes <br>   6 months             30 minutes <br>   1 year               1 hour</code></pre><h3 name="692d" class="graf graf--h3 graf-after--pre">Step 7— Detailed study of Store functions</h3><p name="9d24" class="graf graf--p graf-after--h3">We can now check how each method works in the flow.</p><ul class="postList"><li name="5d82" class="graf graf--li graf-after--p"><strong class="markup--strong markup--li-strong">Register</strong>&#8202;—&#8202;When you register your product, and the product is successfully registered, you get a response like this from the plugin</li></ul><pre name="8d3b" class="graf graf--pre graf-after--li">[store.js] DEBUG: state: ionic_101 -&gt; registered</pre><p name="ba65" class="graf graf--p graf-after--pre"><strong class="markup--strong markup--p-strong">Note</strong>&nbsp;: Even if you try to register a product not existing in App Store Connect&nbsp;, it will return the same message. But you will face error when trying to purchase such a product.</p><p name="808c" class="graf graf--p graf-after--p">Just after <code class="markup--code markup--p-code">register</code>&nbsp;, you will receive only limited details of the product. Rest of the details will come when you <code class="markup--code markup--p-code">refresh</code> store</p><figure tabindex="0" contenteditable="false" name="4104" class="graf graf--figure graf-after--p"><div class="aspectRatioPlaceholder is-locked" style="max-width: 559px; max-height: 646px;"><div class="aspectRatioPlaceholder-fill" style="padding-bottom: 115.6%;"></div><img class="graf-image" data-image-id="1*fTXXtRqhDuU1CX20w0up4g.png" data-width="559" data-height="646" alt="Product details received after register" src="https://cdn-images-1.medium.com/max/800/1*fTXXtRqhDuU1CX20w0up4g.png"><div class="crosshair u-ignoreBlock"></div></div><br/><figcaption class="imageCaption" contenteditable="true" data-default-value="Type caption for image (optional)">Product details received after&nbsp;register</figcaption></figure><ul class="postList"><li name="743a" class="graf graf--li graf-after--figure"><strong class="markup--strong markup--li-strong">Refresh</strong>&#8202;—&#8202;Refresh function refreshes the state of in-app products and fetches detailed information like following</li></ul><pre name="208b" class="graf graf--pre graf-after--li">{<br>  countryCode = IN;<br>  currency = INR;<br>  description = "This in-app purchase allows ad free app usage";<br>  id = "ionic_101";<br>  introPrice = "&lt;null&gt;";<br>  introPriceMicros = "&lt;null&gt;";<br>  introPriceNumberOfPeriods = "&lt;null&gt;";<br>  introPricePaymentMode = "&lt;null&gt;";<br>  introPriceSubscriptionPeriod = "&lt;null&gt;";<br>  price = "\U20b9\U00a079.00";<br>  priceMicros = 79000000;<br>  title = "Ad Free app";<br>}</pre><p name="50a5" class="graf graf--p graf-after--pre">&gt; Refresh function fetches all the products from the store, and also reveals which registered product is valid and which is invalid, as shown in above console log.</p><p name="5619" class="graf graf--p graf-after--p">&gt; Refresh also fetches the previous purchase details that tells the app which products have been purchased.</p><p name="4ce4" class="graf graf--p graf-after--p">&gt; In the app, this detailed information of products can be fetched by <code class="markup--code markup--p-code">product.get()</code> method. This information can be used to know the exact status of the product’s purchase. Following is the extra response of <code class="markup--code markup--p-code">product.get('ionic_101)</code> method after <code class="markup--code markup--p-code">Refresh</code> (if you have purchased once)&#8202;—&#8202;it provides you with the transaction info, based on which you can take app decisions</p><pre name="827b" class="graf graf--pre graf-after--p">"transaction":{<br>  "type":"ios-appstore",<br>  "id":"1000000565248780"<br>}</pre><p name="7837" class="graf graf--p graf-after--pre">&gt; Calling the <code class="markup--code markup--p-code">product.get()</code> method for <code class="markup--code markup--p-code">ionic_102</code> will return a <code class="markup--code markup--p-code">valid: false</code> in details.</p><ul class="postList"><li name="5c8a" class="graf graf--li graf-after--p"><strong class="markup--strong markup--li-strong">Handlers&#8202;—&#8202;</strong>Registering the handlers in the app after purchase of a product triggers the <code class="markup--code markup--li-code">approved</code> event for me. In response, you get the same product info that we got from <code class="markup--code markup--li-code">product.get('ionic_101')</code> method, where we get the transaction info of the product as well. This can help us figure out the status of the product’s purchase.<br>Also, the product info contains <code class="markup--code markup--li-code">owned: false</code>because CONSUMABLES return to <code class="markup--code markup--li-code">valid</code> state after purchase, while others go to <code class="markup--code markup--li-code">owned</code> state</li><li name="67c7" class="graf graf--li graf-after--li"><strong class="markup--strong markup--li-strong">Purchase&#8202;—&#8202;</strong>Once a purchase is made successfully, you will get to know the success from the UI itself</li></ul><figure tabindex="0" contenteditable="false" name="2a6b" class="graf graf--figure graf-after--li"><div class="aspectRatioPlaceholder is-locked" style="max-width: 350px; max-height: 623px;"><div class="aspectRatioPlaceholder-fill" style="padding-bottom: 178%;"></div><img class="graf-image" data-image-id="1*og34PIEWd8-gol2n-d3QyA.png" data-width="350" data-height="623" alt="Payment successful notification in iOS in-app purchase" src="https://cdn-images-1.medium.com/max/800/1*og34PIEWd8-gol2n-d3QyA.png"><div class="crosshair u-ignoreBlock"></div></div><br/><figcaption class="imageCaption" contenteditable="true" data-default-value="Type caption for image (optional)">Payment successful notification in iOS in-app&nbsp;purchase</figcaption></figure><p name="a53a" class="graf graf--p graf-after--figure">But on the code level, there are few things happening →</p><ul class="postList"><li name="ab66" class="graf graf--li graf-after--p">Immediately after purchase (in the&nbsp;<code class="markup--code markup--li-code">.then()</code> of <code class="markup--code markup--li-code">order()</code> ), we receive the product data, but that is not the valid picture of the product status, so don’t use it for decision making.</li><li name="8471" class="graf graf--li graf-after--li">After this, <code class="markup--code markup--li-code">updated()</code> event is triggered, which provides following details of the product</li></ul><figure tabindex="0" contenteditable="false" name="317e" class="graf graf--figure graf--iframe graf-after--li"><div class="aspectRatioPlaceholder is-locked"><div class="aspectRatioPlaceholder-fill" style="padding-bottom: 35.699999999999996%;"></div><div class="iframeContainer">{% gist https://gist.github.com/enappd/a242a2487517590f2ef81ec513cfadfc.js %}</div></div><figcaption class="imageCaption" contenteditable="true" data-default-value="Type caption for embed (optional)">Product data returned after purchase. Notice the transaction data attached</figcaption></figure><p name="20e3" class="graf graf--p graf-after--figure">Here, you can see the <code class="markup--code markup--p-code">transaction</code> object containing the transaction info. This confirm that the purchase is made. You can save this information in your database for future usage.</p><pre name="353a" class="graf graf--pre graf-after--p">"transaction":{<br>  "type":"ios-appstore",<br>  "id":"1000000565248780"<br>}</pre><ul class="postList"><li name="a201" class="graf graf--li graf-after--pre">After this, the <code class="markup--code markup--li-code">approved()</code> event is triggered, which is a signal that the purchase is successful. The data received in this trigger is as follows</li></ul><figure tabindex="0" contenteditable="false" name="3a4f" class="graf graf--figure graf--iframe graf-after--li is-defaultValue"><div class="aspectRatioPlaceholder is-locked"><div class="aspectRatioPlaceholder-fill" style="padding-bottom: 35.699999999999996%;"></div><div class="iframeContainer">{% gist https://gist.github.com/enappd/26bc205db1dfecb1dd232e44f058db9d.js %}</div></div></figure><p name="452e" class="graf graf--p graf-after--figure is-selected">&gt; Notice, <code class="markup--code markup--p-code">“state”: “valid”</code> has now changed to <code class="markup--code markup--p-code">“state”: “approved”</code>&nbsp;. After transaction finishes, the <code class="markup--code markup--p-code">state</code> again goes back to <code class="markup--code markup--p-code">valid</code>&nbsp;. Once <code class="markup--code markup--p-code">approved</code>&nbsp;, you can consider the purchase to be complete, and save the transaction ID in your database</p><p name="7931" class="graf graf--p graf-after--p">&gt; Also, now there is a value in <code class="markup--code markup--p-code">transactions</code> array</p><h4 name="c347" class="graf graf--h4 graf-after--p">Un-finished Purchases</h4><p name="c1ac" class="graf graf--p graf-after--h4">If your app wasn’t able to deliver the content, <code class="markup--code markup--p-code">product.finish()</code> won't be called.</p><p name="a6ac" class="graf graf--p graf-after--p">Don’t worry, the <code class="markup--code markup--p-code">approved</code> event will be re-triggered the next time you call <code class="markup--code markup--p-code">store.refresh()</code>, which can very well be the next time the application starts. Pending transactions are persistent.</p><h4 name="498a" class="graf graf--h4 graf-after--p">Few important points</h4><ul class="postList"><li name="7ac0" class="graf graf--li graf-after--h4">When finished, a consumable product will get back to the <code class="markup--code markup--li-code">VALID</code> state, while other will enter the <code class="markup--code markup--li-code">OWNED</code> state. So don’t put a condition on <code class="markup--code markup--li-code">owned: true</code> for <code class="markup--code markup--li-code">CONSUMABLE</code></li><li name="6721" class="graf graf--li graf-after--li">Any error in the purchase process will bring a product back to the <code class="markup--code markup--li-code">VALID </code>state.</li><li name="b62c" class="graf graf--li graf-after--li">During application startup, products may go instantly from <code class="markup--code markup--li-code">REGISTERED </code>to <code class="markup--code markup--li-code">APPROVED</code> or <code class="markup--code markup--li-code">OWNED</code>, for example if they are purchased non-consumables or non-expired subscriptions.</li><li name="25be" class="graf graf--li graf-after--li">Non-Renewing Subscriptions are iOS products only. Please see the <a href="https://github.com/j3k0/cordova-plugin-purchase/blob/master/doc/ios.md#non-renewing"  class="markup--anchor markup--li-anchor" rel="noopener"    target="_blank">iOS Non Renewing Subscriptions documentation</a> for a detailed explanation.</li></ul><h3 name="c5b1" class="graf graf--h3 graf-after--li">Step 8&#8202;—&#8202;Subscriptions and Receipt validations</h3><p name="f9d7" class="graf graf--p graf-after--h3">All this trouble has been taken to test the in-app purchase <code class="markup--code markup--p-code">consumables</code>. Subscriptions work very similar way till purchase, but a server receipt validation is mandatory for Subscriptions.</p><p name="efdb" class="graf graf--p graf-after--p">When the receipt validator returns a <code class="markup--code markup--p-code">store.PURCHASE_EXPIRED</code> error code, the subscription will automatically loose its <code class="markup--code markup--p-code">owned</code> status.</p><p name="ad16" class="graf graf--p graf-after--p">Typically, you’ll enable and disable access to your content this way.</p><pre name="c162" class="graf graf--pre graf-after--p"><code class="markup--code markup--pre-code">this.iap2.when("my_subcription").updated((product: IAPProduct) =&gt; {<br>  if (product.owned)<br>    // serve the app with subscription<br>  else<br>    // serve the app without subscription<br>});</code></pre><p name="b892" class="graf graf--p graf-after--pre">For more details on Receipt validation, read the<a href="https://ionicframework.com/docs/native/in-app-purchase-2"  class="markup--anchor markup--p-anchor" rel="noopener"    target="_blank"> documentation provided by Ionic</a>.</p><h3 name="0191" class="graf graf--h3 graf-after--p">Conclusion</h3><p name="97aa" class="graf graf--p graf-after--h3">In this post we learnt how to implement the In-App purchase feature in iOS apps. We also tested the app in an iOS device and understood what all the events and methods mean.</p><p name="2041" class="graf graf--p graf-after--p">It is a long a meticulous feature where a lot of things are required to be done correctly. But it’s a very stable feature, which once implemented correctly, will not cause you future troubles.</p><blockquote name="e390" class="graf graf--blockquote graf-after--p"><strong class="markup--strong markup--blockquote-strong">Complete code of this post can be found in the Github repository </strong><a href="https://github.com/enappd/ionic-4-in-app-purchase"  class="markup--anchor markup--blockquote-anchor" rel="noopener"    target="_blank"><strong class="markup--strong markup--blockquote-strong">ionic-4-in-app-purchase</strong></a></blockquote><h3 name="476a" class="graf graf--h3 graf-after--blockquote">Next Steps</h3><p name="d7bd" class="graf graf--p graf-after--h3">Now that you have learned the implementation of In-app purchase in Ionic 4, you can also try</p><ul class="postList"><li name="39ea" class="graf graf--li graf-after--p">Ionic 4 Payment Gateways&#8202;—&#8202;<a href="https://enappd.com/blog/ionic-4-stripe-payment-integration-with-firebase-for-apps-and-pwa/17"  class="markup--anchor markup--li-anchor" rel="noopener"    target="_blank">Stripe</a> | <a href="https://enappd.com/blog/ionic-4-paypal-payment-integration-for-apps-and-pwa/16"  class="markup--anchor markup--li-anchor" rel="noopener"    target="_blank">PayPal</a> | <a href="https://enappd.com/blog/how-to-integrate-apple-pay-in-ionic-4-apps/21"  class="markup--anchor markup--li-anchor" rel="noopener"    target="_blank">Apple Pay</a> | <a href="https://enappd.com/blog/how-to-integrate-razorpay-in-ionic-4-apps-and-pwa/20"  class="markup--anchor markup--li-anchor" rel="noopener"    target="_blank">RazorPay</a></li><li name="8665" class="graf graf--li graf-after--li">Ionic 4 Charts with&#8202;—&#8202;<a href="https://enappd.com/blog/ionic-4-charts-using-google-charts/66"  class="markup--anchor markup--li-anchor" rel="noopener"    target="_blank">Google Charts </a>| <a href="https://enappd.com/blog/adding-charts-in-ionic-4-apps-and-pwa-part-3/60"  class="markup--anchor markup--li-anchor" rel="noopener"    target="_blank">HighCharts</a> | <a href="https://enappd.com/blog/adding-charts-in-ionic-4-apps-and-pwa-part-2/54"  class="markup--anchor markup--li-anchor" rel="noopener"    target="_blank">d3.js</a> | <a href="https://enappd.com/blog/charts-in-ionic-4-apps-and-pwa-part-1/52"  class="markup--anchor markup--li-anchor" rel="noopener"    target="_blank">Chart.js</a></li><li name="fd9c" class="graf graf--li graf-after--li">Ionic 4 Social Logins&#8202;—&#8202;<a href="https://enappd.com/blog/facebook-login-in-ionic-4-apps-using-firebase/25"  class="markup--anchor markup--li-anchor" rel="noopener"    target="_blank">Facebook</a> | <a href="https://enappd.com/blog/google-login-in-ionic-4-apps-using-firebase/39"  class="markup--anchor markup--li-anchor" rel="noopener"    target="_blank">Google</a> | <a href="https://enappd.com/blog/twitter-login-in-ionic-4-apps-using-firebase/24"  class="markup--anchor markup--li-anchor" rel="noopener"    target="_blank">Twitter</a></li><li name="31b6" class="graf graf--li graf-after--li">Ionic 4 Authentications&#8202;—&#8202;<a href="https://enappd.com/blog/email-authentication-with-firebase-in-ionic-4/38"  class="markup--anchor markup--li-anchor" rel="noopener"    target="_blank">Via Email</a> | <a href="https://enappd.com/blog/firebase-anonymous-login-in-ionic-4/37"  class="markup--anchor markup--li-anchor" rel="noopener"    target="_blank">Anonymous</a></li><li name="4a75" class="graf graf--li graf-after--li">Ionic 4 Features&#8202;—&#8202;<a href="https://enappd.com/blog/using-geolocation-geocoding-and-reverse-geocoding-in-ionic-4/45"  class="markup--anchor markup--li-anchor" rel="noopener"    target="_blank">Geolocation</a> | <a href="https://enappd.com/blog/qr-code-scanning-and-optical-character-recognition-ocr-in-ionic-4/9"  class="markup--anchor markup--li-anchor" rel="noopener"    target="_blank">QR Code reader </a>| <a href="https://enappd.com/blog/best-fitness-plugins-for-ionic-4-how-to-use-pedometer/15"  class="markup--anchor markup--li-anchor" rel="noopener"    target="_blank">Pedometer</a></li><li name="819d" class="graf graf--li graf-after--li">Media in Ionic 4&#8202;—&#8202;<a href="https://enappd.com/blog/spotify-like-music-in-ionic-4-apps/48"  class="markup--anchor markup--li-anchor" rel="noopener"    target="_blank">Audio</a> | <a href="https://enappd.com/blog/adding-video-player-in-ionic-4-app/64"  class="markup--anchor markup--li-anchor" rel="noopener"    target="_blank">Video</a> | <a href="https://enappd.com/blog/image-picker-in-ionic-4-app/67"  class="markup--anchor markup--li-anchor" rel="noopener"    target="_blank">Image Picker</a> | <a href="https://enappd.com/blog/how-to-add-image-cropper-in-ionic-4-app/68"  class="markup--anchor markup--li-anchor" rel="noopener"    target="_blank">Image Cropper</a></li><li name="eee3" class="graf graf--li graf-after--li">Ionic 4 Essentials&#8202;—&#8202;<a href="https://enappd.com/blog/ionic-4-save-and-retrieve-data-locally-on-device/59"  class="markup--anchor markup--li-anchor" rel="noopener"    target="_blank">Native Storage</a> | <a href="https://enappd.com/blog/how-to-translate-in-ionic-4-globalization-internationalization-and-localization/11"  class="markup--anchor markup--li-anchor" rel="noopener"    target="_blank">Translations</a> | <a href="https://enappd.com/blog/rtl-right-to-left-use-in-ionic-4/50"  class="markup--anchor markup--li-anchor" rel="noopener"    target="_blank">RTL</a></li><li name="8bbe" class="graf graf--li graf-after--li">Ionic 4 messaging&#8202;—&#8202;<a href="https://enappd.com/blog/implement-ionic-4-firebase-push/34"  class="markup--anchor markup--li-anchor" rel="noopener"    target="_blank">Firebase Push</a> | <a href="https://enappd.com/blog/automatically-read-sms-in-ionic-4-apps/42"  class="markup--anchor markup--li-anchor" rel="noopener"    target="_blank">Reading SMS</a></li><li name="2467" class="graf graf--li graf-after--li">Ionic 4 with Firebase&#8202;—&#8202;<a href="https://enappd.com/blog/how-to-integrate-firebase-in-ionic-4-apps/23"  class="markup--anchor markup--li-anchor" rel="noopener"    target="_blank">Basics</a> | <a href="https://enappd.com/blog/firebase-with-ionic-4-hosting-auth-and-db-connection/58"  class="markup--anchor markup--li-anchor" rel="noopener"    target="_blank">Hosting and DB</a> | <a href="https://enappd.com/blog/firebase-cloud-functions-in-ionic-4-complete-guide/32"  class="markup--anchor markup--li-anchor" rel="noopener"    target="_blank">Cloud functions</a></li></ul><p name="2c47" class="graf graf--p graf-after--li">If you need a base to start your next Ionic 4 app, you can make your next awesome app using <a href="https://store.enappd.com/product/ionic-4-full-app"  class="markup--anchor markup--p-anchor" rel="noopener"    target="_blank">Ionic 4 Full App</a></p><figure tabindex="0" contenteditable="false" name="0c02" class="graf graf--figure graf-after--p"><div class="aspectRatioPlaceholder is-locked" style="max-width: 560px; max-height: 353px;"><div class="aspectRatioPlaceholder-fill" style="padding-bottom: 63%;"></div><img class="graf-image" data-image-id="0*FEEIJR0kJXNBCWUo.jpeg" data-width="560" data-height="353" alt="Ionic 4 Full App with huge number of layouts and features" src="https://cdn-images-1.medium.com/max/800/0*FEEIJR0kJXNBCWUo.jpeg"><div class="crosshair u-ignoreBlock"></div></div><br/><figcaption class="imageCaption" contenteditable="true" data-default-value="Type caption for image (optional)">Ionic 4 Full App with huge number of layouts and&nbsp;features</figcaption></figure><p name="8b2e" class="graf graf--p graf--empty graf-after--figure graf--trailing"><br></p></div></div></section></div></article></main>