React-Native-IAP: One package to rule them all 🧙‍♂️
Tags: reactnative, amazon, monetisation, community
Published: 2023-02-20 21:45:03

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](https://react-native-iap.dooboolab.com/docs/get-started)!

I recently had this challenge while integrating [Amazon IAP] (https://developer.amazon.com/docs/in-app-purchasing/iap-overview.html?cmp=2023_02_devg&ch=soc&chlast=soc&pub=devto&publast=devto&type=org&typelast=org) 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](https://developer.amazon.com/docs/in-app-purchasing/iap-app-tester-user-guide.html?cmp=2023_02_devg&ch=soc&chlast=soc&pub=devto&publast=devto&type=org&typelast=org). 

### ⬇️ The sample app
The first thing I did was clone the [Github repository](https://github.com/dooboolab/react-native-iap) 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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mriqv9z63bw60ns0he5g.png)
From within the folder, I used these commands to start up in the specific platform:

```
yarn ios
yarn android:play
yarn android:amazon
```
_**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. 
```javascript
const {
  connected,
  getSubscriptions,
  getProducts,
  products,
  subscriptions,
  currentPurchaseError,
  initConnectionError,
  finishTransaction,
  currentPurchase,
  purchaseHistory,
  availablePurchases,
} = useIAP();
```
* `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]);
```
#### 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`:
```javascript
 requestSubscription = async (sku: Sku) => {
    try {
      await requestSubscription({sku});
    } catch (error) {
      //Handle error
    }
  };
```
#### Handle errors
Next, I can wrap my `currentPurchaseError` in a `useEffect` and listen to check if any error occurred and then handle it accordingly:
```javascript
  const {currentPurchaseError} = useIAP();
  
  useEffect(() => {
    ... 
  }, [currentPurchaseError]);
```
#### Check current purchase
Finally, asynchronously, I can create a function to check the status and execute `finishTransaction`:
```javascript
  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]);
```
### 🧪 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](https://developer.amazon.com/docs/in-app-purchasing/iap-app-tester-user-guide.html?cmp=2023_02_devg&ch=soc&chlast=soc&pub=devto&publast=devto&type=org&typelast=org) 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`
```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"
  }
}
```
However, you could also create your own IAP items [here] (https://developer.amazon.com/docs/in-app-purchasing/iap-create-and-submit-iap-items.html#create-new-in-app-items?cmp=_02_devg&ch=soc&chlast=soc&pub=devto&publast=devto&type=org&typelast=org). 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] (https://developer.amazon.com/docs/fire-tablets/connecting-adb-to-device.html?cmp=_02_devg&ch=soc&chlast=soc&pub=devto&publast=devto&type=org&typelast=org) with your developer environment using the [Android Debug Bridge (adb)] (https://developer.android.com/studio/command-line/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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/u4uskiefjywg3y2holq8.gif)
 
Finally, running the Amazon version of the example app with the command `yarn android:amazon` you can test purchases using Amazon IAP:

{% youtube 44N-FoAWKPc %}

### Implementing with Expo
One thing to note if you are using [Expo Go](https://expo.dev/client) 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.
```json
"build": {
    "preview": {
      "android": {
        "buildType": "apk",
        "gradleCommand": ":app:assembleDebug"
      }
    },
```
Big kudos to lead maintainer [@andresesfm](https://github.com/andresesfm) and the all the contributions from community developers for react-native-iap! Consider showing your support to their open source project on [OpenCollective](https://opencollective.com/react-native-iap#sponsor). 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](https://twitter.com/AmazonAppDev) on Twitter
📺 Subscribe to our [Youtube channel](https://www.youtube.com/amazonappstoredevelopers)
📧 Sign up for the [Developer Newsletter](https://m.amazonappservices.com/devto-newsletter-subscribe)