React-Native-IAP: One package to rule them all πŸ§™β€β™‚οΈ

Anisha Malde - Feb 20 '23 - - Dev Community

React Native developers often face the problem of adding native support for multiple operating systems, which takes time and effort. What if there was an open source project to handle In-App purchasing (IAP) dependencies across iOS, Google PlayStore, and Amazon Appstore for you? Hello react-native-iap!

I recently had this challenge while integrating Amazon IAP in a React Native app. After researching the top open source projects for purchasing, react-native-iap enabled IAP functionality without the complexity of operating system specific APIs β€” truly one (react native) package to rule them all! πŸ§™β€β™‚οΈβœ¨

For this article, I am going to walk you through the project and then I’ll explain how I launched their sample with the Amazon IAP App Tester.

⬇️ The sample app

The first thing I did was clone the Github repository for react-native-iap as it contained all the working examples for Amazon Appstore, Google Play, and Apple Appstore.

git clone https://github.com/dooboolab/react-native-iap

Next, I navigated to the IapExample folder:
Image description
From within the folder, I used these commands to start up in the specific platform:



yarn ios
yarn android:play
yarn android:amazon


Enter fullscreen mode Exit fullscreen mode

Note: If building an app with Java, make sure your Java version is compatible with the Kotlin version used by the app - (i.e.: Java 17)

πŸͺ The useIAP hook for all the stores

Exploring the sample I saw it uses their new useIAP hook that handles purchases for all the different stores. This was great as the useIAP hook allows you to access a number of operating system agnostic variables and functions allowing you to use the reuse the same logic across platforms.



const {
  connected,
  getSubscriptions,
  getProducts,
  products,
  subscriptions,
  currentPurchaseError,
  initConnectionError,
  finishTransaction,
  currentPurchase,
  purchaseHistory,
  availablePurchases,
} = useIAP();


Enter fullscreen mode Exit fullscreen mode
  • connected is a boolean variable that checks whether the native IAP module is able to interact with react.
  • getProducts & getSubscriptions are the functions that update the products and subscriptions variables when fetched.
  • currentPurchaseError & initConnectionError are the errors returned from failed purchases & failed connection respectively.
  • currentPurchase returns the current purchase.
  • finishTransaction is the function you call to β€˜consume’ purchases.
    • For consumables, once an item is consumed, it will be removed from getAvailablePurchases() and you should record the purchase into your database before calling finishTransaction().
    • For non-consumables, purchases need to be acknowledged on Android, or they will be automatically refunded after a few days. This method acknowledges a purchase when you have delivered it to your user.
  • purchaseHistory returns an array of all the previous purchases
  • availablePurchases returns an array of all the available items that can be purchased There are two other methods that are important, however they are not available through the hook and will need to be imported from the package: ```javascript

import {requestPurchase, requestSubscription} from 'react-native-iap';

* `requestPurchase` & `requestSubscription` are the functions that handle the purchase of the products/subscriptions.

Taking the example of scenario where a user is making a purchase of a subscription, I mapped how I could utilise the variables and functions:
#### Retrieve the available subscriptions 
The first step would be to retrieve the available subscriptions and present them to a user. I can easily do this by checking I am `connected` and then calling the `getSubscriptions` function. This will automatically update the subscriptions variable with the `subscriptions`:
```javascript


 const {connected, subscriptions, getSubscriptions} = useIAP();

 useEffect(() => {
    if (connected) {
      getSubscriptions({skus: [
        'com.amazon.sample.iap.subscription.mymagazine.month',
        'com.amazon.sample.iap.subscription.mymagazine.quarter',
      ]});
    }
  }, [getSubscriptions]);


Enter fullscreen mode Exit fullscreen mode

Handle the purchase request

Next to handle a purchase request e.g. when a purchaseSubscription button is pressed, I can make my call of requestSubscription:



 requestSubscription = async (sku: Sku) => {
    try {
      await requestSubscription({sku});
    } catch (error) {
      //Handle error
    }
  };


Enter fullscreen mode Exit fullscreen mode

Handle errors

Next, I can wrap my currentPurchaseError in a useEffect and listen to check if any error occurred and then handle it accordingly:



  const {currentPurchaseError} = useIAP();

  useEffect(() => {
    ... 
  }, [currentPurchaseError]);


Enter fullscreen mode Exit fullscreen mode

Check current purchase

Finally, asynchronously, I can create a function to check the status and execute finishTransaction:



  const {currentPurchase, finishTransaction} = useIAP();

  useEffect(() => {
    const checkCurrentPurchase = async () => {
      try {
        if (currentPurchase?.productId) {
          await finishTransaction({
            purchase: currentPurchase,
            isConsumable: true,
          });
        }
      } catch (error) {
          //Handle error
      }
    };

    checkCurrentPurchase();
  }, [currentPurchase, finishTransaction]);


Enter fullscreen mode Exit fullscreen mode

πŸ§ͺ Test with the Amazon App Tester

The sample looked great so it was now time to unit test IAP functionality by simulating a production environment with the Amazon IAP App Tester in three steps.

Step 1: Download the App Tester

If you haven't already got it, you can download App Tester from the Amazon Appstore, onto the same Android device as your app. The App Tester simulates the production environment and you configure it with IAP items.

Step 2: Create the amazon.sdktester.json

The example app already contains the JSON file with the IAP Items used in the demo and you can find it in IAPExample/android/app/amazon.sdktester.json



{
  "com.amazon.sample.iap.subscription.mymagazine.month": {
    "description":"Monthly Subscription to My Magazine",
    "title":"My Magazine",
    "itemType":"SUBSCRIPTION",
    "price":5.0,
    "subscriptionParent":"com.amazon.sample.iap.subscription.mymagazine"
  },
  "com.amazon.sample.iap.subscription.mymagazine.quarter": {
    "description":"Quarterly Subscription to My Magazine",
    "title":"My Magazine",
    "itemType":"SUBSCRIPTION",
    "price":12.0,
    "subscriptionParent":"com.amazon.sample.iap.subscription.mymagazine"
  }
}


Enter fullscreen mode Exit fullscreen mode

However, you could also create your own IAP items here. Once you have created your in-app items, you can download a JSON-formatted data file containing all of the data for your items like the one above.

Step 3: Push the amazon.sdktester.json file to your device

Next, if you haven't already, connect your Amazon device with your developer environment using the Android Debug Bridge (adb). This is to enable you to copy the JSON file to the /sdcard/ folder on your device file system by running the following command line:
$ adb push [_Your_JSON_File_Folder_]/amazon.sdktester.json /sdcard/amazon.sdktester.json

Note: If your device is running an Android OS version older than 4.0, copy the file to /mnt/sdcard/.

Once that is set-up you will see the In-App items on the App Tester:
IAP Items in App Tester

Finally, running the Amazon version of the example app with the command yarn android:amazon you can test purchases using Amazon IAP:

Implementing with Expo

One thing to note if you are using Expo Go to build your app, when you are testing, make sure to change the build type to debug in your eas.json to ensure it is compatible with the test version of Amazon IAP. This will enable you to test with Fast Refresh too. The release(:app:assembleRelease) version can only be tested when live testing with the Appstore.



"build": {
    "preview": {
      "android": {
        "buildType": "apk",
        "gradleCommand": ":app:assembleDebug"
      }
    },


Enter fullscreen mode Exit fullscreen mode

Big kudos to lead maintainer @andresesfm and the all the contributions from community developers for react-native-iap! Consider showing your support to their open source project on OpenCollective. I’ll definitely be using their package to implement Amazon IAP in my React Native App!

To stay up to date with Amazon Appstore developer updates on the following platforms:

πŸ“£ Follow @AmazonAppDev on Twitter
πŸ“Ί Subscribe to our Youtube channel
πŸ“§ Sign up for the Developer Newsletter

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .