March 30, 2024 • by Suma

Monetizing React Native App: A Beginner’s Guide to Implementing In-App Purchases

Monetizing React Native App: A Beginner’s Guide to Implementing In-App Purchases

In-app purchase have become an integral part of monetization strategy, enabling the creators to generate revenue from their mobile app and also providing users with a seamless purchasing experience. Fortunately, both widely used mobile platforms, Android and iOS, have streamlined the In-App Purchase transaction & revenue distribution process through their app stores. But there aren’t many tutorial on internet about how to implementing it, especially in React Native. You can use paid In-App Purchase management platform such as Adapty or RevenueCat to simplifies the process, but this article will guide you through implementing In-App Purchase in React Native using Google Billing & Apple StoreKit APIs. We’ll also test it with sandbox account.

What exactly is In-app Purchase ?

In-app purchase is a feature provided by a platform to buy digital items or services directly from the mobile app. With In-app purchase feature, the creators are able to distribute their app for free with basics feature, but then offering the users an option to upgrade it to full feature. In-app purchase feature brings numerous benefits to both the creator and the user not only generating sustainable revenue for the creators, iap also encourage creators to provide a better user experience, update the content frequently to keep the users’s engagement.

In-App Purchases Types

There are three types of in-app purchase based on their usage

Consumable

Consumable is a type of In-App Purchases that allows users to buy and use digital items multiple times. These item is typically designed for one-time use but can be bought repeatedly. Consumable items can be virtual currencies like gold or diamond in games, extra health or points in a game, .etc.

Non-Consumable

Non-Consumable is the opposite of the consumable type, where users only need to purchased the digital items once and can use them indefinitely. Once users have purchased it, the item will linger to user’s account across different devices and app installations. The example of non-consumable in-app purchase includes ads Removal, pro version of an app, levels in game, .etc.

Auto-Renewable Subscription

Auto-Renewable Subscription is a type that enabled the users to purchase a service or content for a set of period. This type of item will renew automatically at the end of certain period unless cancelled by the user. For example, Access premium feature for a full week, month, or a year.

Each In-app purchase type has a different requirement & implementation. In the next part this we will only focusing on the subscription-based type in React Native.

In-App Purchase Prerequisite

Before diving into implementation, it’s imperative to adhere to certain prerequisites. Initially, signing up to developer account for both Android and iOS platforms is essential if we are targeting these platforms. This enables us to create the items or products that we intend to offer within our application.

Android Play Console Setup

On Android, it’s essential to create a payment profile. To do this, navigate to the Payment Settings within the Play Console, then click “Create Payments Profile” and ensure all information provided is accurate. Once the payment profile is created, you can link your bank account to receive revenue shares from Google’s In-App Purchases. With this in place, you can proceed to create your In-App Purchase items. Simply access your app in the Play Console, navigate to the Monetize section in the left panel, and select your desired In-App Purchase type. Follow the instructions provided on the page, and you’ll be able to create your first In-App Purchase item effortlessly.

iOS Play Console Setup

On iOS is quite similar to the process on Android. You’ll need to configure your bank account to receive revenue generated from your app. Begin by accessing your App Store Connect website. Navigate to the Agreements tab, locate the row for paid apps, and select “Set Up Tax and Banking.” On this page, input your bank account details, ensuring all required fields are filled accurately, and check the “I have read” checkbox. Finally, save your changes. Once the bank account is set up, you can proceed to create the In-App Purchase (IAP) items. To do this, navigate to your app within the My Apps menu. In the left panel, select your desired in-app purchase type, whether it’s consumable, non-consumable, or subscription-based.

IAP Implementation in React Native

To set up in-app purchases in React Native, we utilize the Google Billing APIs and/or the Apple StoreKit APIs. Instead of creating separate native modules for each platform, we can streamline the process with the react-native-iap library. It offers a unified interface for managing purchases across both the Google Play Store and the Apple App Store. Under the hood, React Native IAP leverages native APIs from Google and Apple to handle purchase flows, verify transactions, and manage subscriptions. By using React Native IAP, developers gain access to a consistent set of methods and events, regardless of the platform, facilitating easier implementation and maintenance of in-app purchases in cross-platform React Native apps.

To install react-native-iap library run this code

npm install react-native-iap
# or
yarn add react-native-iap

Setup for iOS, if you’are targetting to iOS platform

cd ios
pod install
cd ..

react-native-iap library provide us a hooks to simplifies the fetching item, making purchase, and handle purchasing process so let’s use that.

import {
    withIAPContext,
    useIAP
} from 'react-native-iap'

const SubscriptionScreen = () => {
	const {
		connected,
		subscriptions,
		products,
		getSubscriptions,
		getProducts,
		currentPurchase,
		currentPurchaseError,
	} = useIAP();

	return <>
		{/*
			your component
		*/}
	</>
}
export default withIAPContext(SubscriptionScreen)

Let’s retrieve the earlier created IAP item. First we need to declare the Product ID’s :

const items = Platform.select({
    ios: ["com_example_product1ios", "com_example_product2ios", "com_example_product3ios"],
    android: ["com_example_product1", "com_example_product2", "com_example_product3"],
});

if the product is subscription use getSubscriptions method :

if the product is not a subscription, you can use getProducts method:

useEffect(() => {
    if (connected) {
        handleGetSubscription()
    }
}, [connected]);

const handleGetSubscription = async () => {
    try {
        //show loading animation
        await getSubscriptions({ skus: items! });
        //hide loading animation
    } catch (e) {
        //handle error fetching
    }
}

If the fetching method is success, the subscriptions or products variable will be populated asynchronously, so you can display the your offered products on the screen :

<FlatList
    data={subscriptions}
    style={{
        flex: 1,
        marginTop: 8
    }}
    scrollEnabled={false}
    keyExtractor={(item, index) => `index ${index}`}
    renderItem = {({item,index}) => {
        {/*
                showing product name and it's price
        */}
        <Text>{Platform.OS == 'ios' ? item.title : item.name}
        <Text>{Platform.OS == 'ios' ? item.localizedPrice : item.subscriptionOfferDetails[0].pricingPhases.pricingPhaseList[item.subscriptionOfferDetails[0].pricingPhases.pricingPhaseList.length - 1].formattedPrice}</Text>
    }}
/>

To make purchase we can use requestSubscription or requestPurchase depending on your product type.

//if subscription use this
const handlePurchase = async(item) => {
    if (Platform.OS == "ios") {
        await requestSubscription({ sku: item.productId });
    } else {
        await requestSubscription({ subscriptionOffers: [{ sku: item.productId, offerToken: item.subscriptionOfferDetails[0].offerToken }] });
    }
}

//if consumable or non-consumable product use this
const handlePurchase = async(item) => {
    await requestPurchase({sku: item.productId})
}

After making a purchase, we can observe the purchase events. The variables currentPurchase and currentPurchaseError will be updated based on the result of the purchase event.

useEffect(() => {
    const checkCurrentPurchase = async (purchase) => {
        if(purchase){
            //handle the purchase event
            //...
            //at the end, finish the current transaction
            try {
                const ackResult = await finishTransaction(purchase);
                console.log('ackResult', ackResult);
            } catch (ackErr) {
                console.warn('ackErr', ackErr);
            }
        }
    }
    checkCurrentPurchase(currentPurchase);
}, [currentPurchaseError]);
  
useEffect(() => {
    if (currentPurchaseError) {
        //handle error event
    }
}, [currentPurchaseError]);

Finally, the In-App Purchase integration is complete, and it’s now ready for testing.

Testing In-App Purchases

Before publishing the app to public, it’s very important to thoroughly test it’s functionality in a controlled environment. Both Apple & Google offer sandbox environment for developers to test the in-app purchase feature without actually making real payments.

Apple with sandbox account

Conducting testing for an iOS app can be done by uploading the app into testflight and subsequently create sandbox account in your appstoreconnect console to facilitate simulated purchases. While this process may seems simple, but it’s actually not that simple. The testflight app may not accurately detect or incorporate the previously created sandbox account. Instead, it might utilize your actual Apple ID, leading to complications. This issue prevents access to sandbox account settings, crucial for tasks such as canceling or resetting the eligibility of your app’s subscription—an essential feature for expediting the testing process.

Following an extensive investigation on various forums and sources, I’ve discovered a workaround to resolve the issue. To implement this solution, start by signing out of your Apple ID from the App Store App. Next, open your app and activate the purchase paywall. A login form dialog will then appear on the screen; input your previously created sandbox account. The purchase paywall will promptly detect your sandbox account and finalize the purchase process. A success dialog will appear, allowing you to subsequently access the sandbox account settings to manage your app’s subscription.

To access sandbox account setting, open the Settings app, navigate to App Store section, scroll to the very bottom, and locate the sandbox account section. Tap on Apple ID or “Sign In” button, and then select “Manage”.

Android with license testing account

Contrary to iOS app testing, Android testing is notably straightforward and simple to set up. The process involves registering the tester’s email into the license tester list in the Play Console. To achieve this, open the Play Console dashboard, navigate to the Setup menu on the left side panel, and select the License Testing submenu. If you haven’t created a license tester list yet, you’ll need to do so. Additionally, you have the option to specify subscription response scenarios, indicating whether it’s a success, failure, or error. Once the email is registered in the license tester, you can seamlessly test the subscription without any complications.

Pro-tip Note

When developing & testing In-App Purchase, some issues may arise. Consequently, it is essential to consider certain key factors.

  • Explore Every Possible ScenarioWhen testing IAP make sure to test various scenarios, including successful purchase, failure, cancelled, .etc.
  • Handle Transaction Receipt on your own backend.Handling transaction receipt validation on your backend is highly recommended. This ensures that all purchases are verified and authenticated, mitigating the risk of fraudulent transactions. Moreover, implementing receipt validation on your backend provides greater control and flexibility in managing subscriptions, tracking user purchases, and regulating access to premium content or features.
  • Validation of duplicated Transaction IDsWhen user subscribes or make purchases, the transaction will linked to their Google or Apple account. This connection may lead to information leaks if the backend system fails to validate duplicated transaction IDs when users create multiple accounts for the app.
  • Unpublished app will persist in the sandbox environment.When the app is uploaded to TestFlight, Internal, or Closed Test, it will persist within the Apple or Google sandbox server URL, irrespective of the app’s environment being configured as production. In instances where the app’s environment is marked as production, then a user makes a purchase, the webhook notification will be sent to sandbox server url instead of the designated production url. This situation will leads to false production purchases. This is why backend should have validation to address this issue.

Conclusion

In-App Purchase has been proved as the most effective monetization method for creators to generate revenue while delivering significant value to users. Although implementing In-App Purchase in React Native may initially appear challenging and require numerous trial and error attempts, following best practices enables creators to seamlessly integrate it and provide an optimal user experience.

Thank you for taking the time to read! if you have any further inquiries or wish to delve deeper into this topic, feel free to reach out to us via our website or through our various social media channels.

Wishing you a fantastic journey in your programming endeavors!

Testing