Search code examples
iosangularin-app-purchase

Ionic 4 - In-app purchase product information can't display before purchase


I have google and follow online tutorials on in-app purchase. I have finished all the setting on Apple's platform and am now testing the in-app purchase function. The function seems working but I am now struggling with 2 issues.

First, I use the store.refresh() and store.get() command to fetch the data from Apple's server. However, I am only able to see the fetched product information after I press the "purchase" button. From the Xcode console, I can see the product information likes pricing, etc. already loaded but just can't display on my view page before I press the purchase button. Did I miss anything?

Second, how to modify my codes if I have more than one product in in-app purchase? I have seen some online resources but seems nothing for ionic and in-app-purchase2 that works.

I have been working on this in-app purchase for 2 weeks especially those time consuming setup in Apple. Any help on the above would be great and highly appreciated!

upgrade.ts file

 import { NavController, Platform } from '@ionic/angular';
 import { InAppPurchase2, IAPProduct } from '@ionic-native/in-app-purchase-2/ngx';

 @Component({
   selector: 'app-upgrade',
   templateUrl: './upgrade.page.html',
   styleUrls: ['./upgrade.page.scss'],
 })

 export class UpgradePage {

   setupReady = 'Not yet';
   public prod: any = {};

   public product: any = {
       name: 'Upgrade to Premium 12 months',
       appleProductId: 'upgrade_12months',
       googleProductId: 'android.test.purchased'
   };

  constructor(private store: InAppPurchase2,
            public platform: Platform,
             ) {
    this.platform.ready().then(() => {
        this.configurePurchasing();
        this.setupReady = 'Ready';
    });
  }

  ionViewDidEnter() {
    this.prod = this.store.get('upgrade_12months');
  }

configurePurchasing() {
  if (!this.platform.is('cordova')) { return; }
  let productId;
  try {
    if (this.platform.is('ios')) {
      productId = this.product.appleProductId;
    } else if (this.platform.is('android')) {
      productId = this.product.googleProductId;
    }

    // Register Product
    // Set Debug High
    this.store.verbosity = this.store.DEBUG;

    // Register the product with the store
    this.store.register({
        id: 'upgrade_12months',
        alias: 'upgrade_12months',
        type: this.store.PAID_SUBSCRIPTION
    });

    this.registerHandlers(productId);
    this.store.refresh();
    this.prod = this.store.get(productId);

    InAppPurchase2.getPlugin().ready().then((status) => {
      console.log(JSON.stringify(this.store.get(productId)));
      console.log('Store is Ready: ' + JSON.stringify(status));
      console.log('Products: ' + JSON.stringify(this.store.products));
    });

    // Errors On The Specific Product
    this.store.when(productId).error( (error) => {
      alert('An Error Occured' + JSON.stringify(error));
    });
    // Refresh Always
    console.log('Refresh Store');
    this.store.refresh();
  } catch (err) {
    console.log('Error On Store Issues' + JSON.stringify(err));
  }
}

 registerHandlers(productId) {
  // Handlers
  this.store.when(productId).approved( (product: IAPProduct) => {
    alert('Approved!');
    // Purchase was approved
    product.finish();
  });

  this.store.when(productId).registered( (product: IAPProduct) => {
    console.log('Registered: ' + JSON.stringify(product));
    console.log(` Registered2 ${product.owned}`);
  });

  this.store.when(productId).updated( (product: IAPProduct) => {
    console.log('Loaded' + JSON.stringify(product));
  });

  this.store.when(productId).cancelled( (product) => {
    alert('Purchase was Cancelled');
  });

  // Overall Store Error
  this.store.error( (err) => {
    console.log('Store Error ' + JSON.stringify(err));
  });
 }


async purchase() {
  if (!this.platform.is('cordova')) { return; }
  let productId;

  if (this.platform.is('ios')) {
    productId = this.product.appleProductId;
  } else if (this.platform.is('android')) {
    productId = this.product.googleProductId;
  }

  this.registerHandlers(productId);
  try {
    const product = this.store.get(productId);
    console.log('Product Info: ' + JSON.stringify(product));
    this.store.order(productId).then((p) => {
      alert('Purchase Action Detected');
      this.registerHandlers(productId);
    }).catch((e: string) => {
      alert('Error Ordering From Store' + e);
    });
  } catch (err) {
    console.log('Error Ordering ' + JSON.stringify(err));
  }
}

restore() {
    this.store.refresh();
}

upgrade.html

 <ion-content padding>
   <ion-row text-center>
     <ion-col>Status:  <b>{{ this.setupReady }}</b></ion-col>
   </ion-row> 

 <br>
 {{ ' Description: '}} {{ this.prod.description }}
 <br>
 {{ 'Price:' }} {{ this.prod.price }}
 <br>
 <div margin-vertical text-center>

          {{ this.prod.title }}
     <ion-button (click)='purchase()' expand="block">

        {{ ' Buy now - ' }} 
        {{ this.prod.price }}

     </ion-button>
 </div>   

   <ion-button full icon-left color="secondary" (click)="restore()">
       <ion-icon name="refresh"></ion-icon>Restore Purchases
   </ion-button>
 </ion-content>

Solution

  • I finally solved this problem as probably none of the online tutorials on in-app purchase has ever mentioned these critical points.

    First, you must register the products and handlers as soon as the app starts, i.e. on the startup page, NOT on the page you show in-app purchase products to your customers.

    Second, register products only ONCE and never unregister them again. Do NOT attempt to register products again in another page.

    These should solve many issues you face for in-app purchase integration. Hope this help many others that were struggling on in-app purchase coding.