Skip to content

v13 tutorials: First Steps with the Test Adapter

Gianluca Ghettini edited this page Aug 11, 2023 · 9 revisions

Note: For this tutorial, use the plugin at version 13 or later.

The plugin offers a unified interface to different payment platforms. It does so using Adapters who implements a common interface to the underlying platform.

One of the adapter is a mock implementation used for testing: the Test Adapter which isn't linked with any platform, it provides a way to quickly test your code without getting into platform specific settings.

Let's create a small demo app using this adapter.

Project Setup and Initialization

Starting with a blank Cordova project, we'll install the plugin with cordova plugin add cordova-plugin-purchase. Then let's check in the "deviceready" event handler that the plugin has been correctly loaded.

document.addEventListener('deviceready', onDeviceReady);
function onDeviceReady() {
  CdvPurchase.store.ready(function() {
    console.log("CdvPurchase is ready");
  });
  CdvPurchase.store.initialize([CdvPurchase.Platform.TEST]);
}
  • CdvPurchase.store is a global variable you can use to access the plugin.
  • with store.ready(), we're setting up a callback function that will be called when all platforms have been initialized.
  • with store.initialize(), we're initializing the plugin with an array of desired platforms. In this case we passed only Platform.TEST which is our mock adapter.

Loading Products Metadata

Before In-App Products can be purchased, you need to load the related information from the store. To achieve this, you need to register those with the plugin, at initialization it will load the information.

Here's the addition to our initialization function.

function onDeviceReady() {
  /* ... */
  CdvPurchase.store.register([{
    type: CdvPurchase.ProductType.CONSUMABLE,
    id: 'test-consumable',
    platform: CdvPurchase.Platform.TEST,
  }]);
  CdvPurchase.store.when().productUpdated(onProductUpdate);
  CdvPurchase.store.initialize([CdvPurchase.Platform.TEST]);
}

function onProductUpdated() {}
  • with store.register(), we inform the plugin that there's a consumable product with identifier "test-consumable".
  • with store.productUpdated(), we defined a function that will be called whenever there's new information known about a product.

Note: "test-consumable" is one of the test products defined by the Test Adapter.

Displaying product information

To keep things simple for this tutorial, we'll replace the whole page HTML when the product changes.

function onProductUpdated() {
  const body = document.getElementsByTagName('body')[0];
  const product = CdvPurchase.store.get('test-consumable', CdvPurchase.Platform.TEST);
  body.innerHTML = `
    <div>Product: ${product.title}</div>
    <div>${product.description}</div>
    <div>Price: ${product.pricing.price}</div>
    <button onclick="buy()">Buy</button>
  `;
}

function buy() {}
  • product.title and product.description contains textual information about the product, as fetched from the store.
  • product.pricing contains the pricing information. The .price field contains a human readable representation.

Note: this product only has 1 available pricing, product.pricing is a shortcut to product.offers[0].pricingPhases[0]. For more complex scenario in which there are multiple offers for a product, and/or the product is paid in multiple phases, you need to handle those cases. See the documentation for the Product class for details.

Making a Purchase

The Offer.order() method is used to initiate the purchase flow.

function buy() {
  const product = CdvPurchase.store.get('test-consumable', CdvPurchase.Platform.TEST);
  const offer = product.getOffer();
  if (offer)
    offer.order();
}

We now need to handle the various events happening during the purchase.

Handling Purchases

A common misconception is that purchase events only happen after .order() has been called. This isn't always the case:

  • a purchase can be initiated from the store by redeeming a coupon.
  • a purchase might have been initiated from another device, or another session on the same device, but has been interrupted.
  • a purchase remain pending for a few days:
    • in some country it's possible to finalize in-app purchases by paying cash in a shop.
    • with kids protection, a purchase might be waiting for approval from the parents.

As such, it's necessary to be prepared to handle purchase events has soon as the app is launched.

To do this, we'll add a new even handler in our onDeviceReady function:

function onDeviceReady() {
  /* ... */
  CdvPurchase.store.when().approved(onTransactionApproved);
  CdvPurchase.store.initialize([CdvPurchase.Platform.TEST]);
}

function onTransactionApproved(transaction) {
  alert('purchase approved, congrats');
  transaction.finish();
}

The approved event is triggered when the payment processor has approved the transaction. It's now waiting for an acknowledgement that the (virtual) goods have been delivered. In our case, we just show an alert. After delivery, we should call transaction.finish() to finalize the transaction.