React Native In-App Purchases — Part 4
In-app purchases example in React Native
In part 1, part 2, and part 3, we explored the basics of in-app purchases, including setup processes for both iOS and Android platforms.
In this blog, we will explore real-world examples of integrating an in-app purchase library in React Native. We will cover the initialization process, subscription purchases, and other purchase functionality.
Integrate In-App Purchases in React Native
You can either create a new React Native project or integrate the library into an existing project.
To create a new project, use the following command:
npx react-native@latest init InAppPurchase
Configure In-App Purchases library
// for Yarn
yarn add react-native-iap
//For npm
npm install react-native-iap
After successfully adding the library, update the native side.
iOS Configuration
To update pods, run the following command:
cd ios; pod install; cd -
Android Configuration
Go to android/build.gradle
and modify the following lines:
buildscript {
ext {
...
supportLibVersion = "28.0.0"
}
}
Configure the payment provider. To support only the Play Store, update android/app/build.gradle
defaultConfig {
...
missingDimensionStrategy "store", "play"
}
For more details, refer to the react-native-iap documentation.
After adding react-native-iap, you must upload a build for close testing on the Play Store console. Approval will take approximately 8 to 10 hours or one day. For iOS, upload the build to TestFlight.
Initiate In-App Purchases in React Native
Wrap the app with HOC
First, wrap your main file with the withIAPContext
Higher-Order Component (HOC):
import React from 'react';
import { withIAPContext } from 'react-native-iap';
const App = () => <View />;
export default withIAPContext(App);
Initialize Connection
Next, call the initializeIAP method to enable the connection:
import React, { useEffect } from 'react';
import { endConnection } from 'react-native-iap'
useEffect(() => {
initializeIAP();
return () => {
endConnection();
};
}, []);
The method initializeIAP to call initConnection is shown below. Once an in-app purchase connects, update another useEffect for the getPurchaseInfo and getSubscriptionInfo functions by changing the setConnection useState to true.
import { Platform } from 'react-native';
import React, { useEffect, useState } from 'react';
import { initConnection, flushFailedPurchasesCachedAsPendingAndroid } from 'react-native-iap';
const isAndroid = Platform.OS === 'android'; // check platform is android or not
const [connection, setConnection] = useState<boolean>(false);// set in-app purchase is connected or not
const initializeIAP = async () => {
try {
await initConnection().then(async (value: boolean) => {
setConnection(value);
isAndroid && (await flushFailedPurchasesCachedAsPendingAndroid());
});
} catch (error) {
console.error('Error initializing IAP: ', error);
}
};
flushFailedPurchasesCachedAsPendingAndroid
is used for only Android. Ensure compatibility with platform conditions.
For more info, check flushFailedPurchasesCachedAsPendingAndroid.
Retrieve the Available Subscriptions
To obtain subscription details, pass the subscription ID to the array of SKUs in the getSubscriptions
function. Based on that, we can make a purchase request.
Similarly, use getProducts
for in-app purchases.
import { getSubscriptions, Subscription, getProducts, Product } from 'react-native-iap'
const subscriptionIds = ['com.simformllc.iapdemo.years'];// for subscriptions
const productIds= ['com.simformllc.iapdemo.yearsallaccess'];// for in-app purchases
const [subscription, setSubscription] = useState<Subscription[]>([]);
const [products, setProducts] = useState<Product[]>([]);
useEffect(() => {
if (connection) {
getSubscriptionInfo();
getPurchaseInfo();
}
}, [connection]);
// To get Subscription information
const getSubscriptionInfo = async () => {
try {
const subscriptions = await getSubscriptions({
skus: subscriptionIds,
});
setSubscription(subscriptions); // set subscription information
} catch (error) {
console.error('Error fetching products: ', error);
}
};
// To get in-app purchases information
const getPurchaseInfo = async () => {
try {
const productsInfo = await getProducts({ skus: productIds });
setProducts(productsInfo);
} catch (error) {
console.error('Error fetching products: ', error);
}
};
Before making any purchase requests, set the purchaseUpdatedListener
to listen for updates when the app launches.
import { purchaseUpdatedListener, Purchase } from 'react-native-iap';
useEffect(() => {
const subscriptionListener = purchaseUpdatedListener(
(purchase: Purchase) => {
console.log(purchase); // get purchase information
},
);
return () => {
subscriptionListener.remove();
};
}, []);
The purchaseUpdatedListener
provides necessary purchase information upon successful completion. Manage your backend API accordingly.
After successfully purchasing a subscription, users will gain access to the platform’s JSON data, as outlined below:
For Android:
{
"autoRenewingAndroid": true,
"dataAndroid": "{\"orderId\":\"GPA.3393-1976-6765-68323\",\"packageName\":\"com.simformLLC.iapdemo\",\"productId\":\"com.simformllc.iapdemo.years\",\"purchaseTime\":1706781727369,\"purchaseState\":0,\"purchaseToken\":\"gdpkmemapmpmmbgjakpccknl...\",\"quantity\":1,\"autoRenewing\":true,\"acknowledged\":false}",
"developerPayloadAndroid": "",
"isAcknowledgedAndroid": false,
"obfuscatedAccountIdAndroid": "",
"obfuscatedProfileIdAndroid": "",
"packageNameAndroid": "com.simformLLC.iapdemo",
"productId": "com.simformllc.iapdemo.years",
"productIds": ["com.simformllc.iapdemo.years"],
"purchaseStateAndroid": 1,
"purchaseToken": "gdpkmemapmpmmbgjakpccknl...",
"transactionDate": 1706781727369,
"transactionId": "GPA.3393-1976-6765-68323",
"transactionReceipt": "{\"orderId\":\"GPA.3393-1976-6765-68323\",\"packageName\":\"com.simformLLC.iapdemo\",\"productId\":\"com.simformllc.iapdemo.years\",\"purchaseTime\":1706781727369,\"purchaseState\":0,\"purchaseToken\":\"gdpkmemapmpmmbgjakpccknl...\",\"quantity\":1,\"autoRenewing\":true,\"acknowledged\":false}"
}
For iOS:
{
"appAccountToken": "",
"originalTransactionDateIOS": 1704875275000,
"originalTransactionIdentifierIOS": 2000000496868441,
"productId": "com.simformllc.iapdemo.years",
"purchaseToken": "",
"quantityIOS": 1,
"transactionDate": 1706782889000,
"transactionId": "2000000514281414",
"transactionReasonIOS": "PURCHASE",
"transactionReceipt": "",
"verificationResultIOS": "eyJhbGciOiJFUzI1NiIsIng1...”
}
Handle the Subscription Purchase Request
When the user presses the subscription button, call requestSubscription
and pass the SKU obtained from getSubscriptions.
To purchase a subscription on Android, include offerToken. You can retrieve the offerToken from the SKU using the getSubscriptions
function.
On the iOS side, you cannot get an offerToken.
import { requestSubscription, Subscription } from 'react-native-iap';
const onSubscription = async (sku: Subscription) => {
try {
const offerToken = isAndroid
? sku?.subscriptionOfferDetails[0]?.offerToken
: null;
const purchaseData = await requestSubscription({
sku: sku?.productId,
...(offerToken && {
subscriptionOffers: [{ sku: sku?.productId, offerToken }],
}),
});
console.log(purchaseData); // after successfully purchase, we'll get purchase information
} catch (error) {
console.log(error);
}
};
Once a user requests a subscription, a modal will pop up from the respective platform, as shown in the image below:
If you wish to add a loader while requesting a subscription purchase, you can initiate the loader prior to the requestSubscription
and terminate it once you receive the purchaseData.
Note: On the Android side, when we request a year’s purchase with a test subscription, you can see the price with duration in the above left-side image, such as 1299.00/30 minutes. So, with the test subscription, you’ll get 30 minutes, but in a real-time scenario, it’ll be a year.
For more information, refer to requestSubscription.
Handle the In-App Purchases Request
When users want to buy an in-app product, use the requestPurchase
method.
import { Product, requestPurchase} from 'react-native-iap';
const onPurchase = async (sku: Product) => {
try {
const purchaseData = await requestPurchase({
sku: sku?.productId,
andDangerouslyFinishTransactionAutomaticallyIOS: false,
skus: productIds, // Array of all the IAP
});
console.log(purchaseData); // After successfully purchase, we'll get the purchase information
} catch (error) {
console.log(error);
}
};
For more information, refer to requestPurchase.
Once a user requests to make in-app purchases, they will receive a purchase modal from the respective platform, as shown in the image below:
Get Current Available Purchases
After buying any subscription, if you want to check your current subscription, use the getAvailablePurchases
function from the library.
import { getAvailablePurchases } from 'react-native-iap';
const getCurrentPurchases = async () => {
try {
const purchases = await getAvailablePurchases();
console.log(purchases);// get current available purchases
} catch (error) {
console.log('Error getting purchases:', error);
}
};
Get Purchases History
If you want to check the previous history of a purchased subscription, use getPurchaseHistory
.
import { getPurchaseHistory } from 'react-native-iap';
const getPurchaseHistoryIap = async () => {
try {
const purchaseHistory = await getPurchaseHistory();
console.log(purchaseHistory); //get previous all history
} catch (error) {
console.error('Error fetching purchase history: ', error);
}
};
In the example below, the first image shows different types of subscriptions. Once you Upgrade to a Pro subscription, you will see the next image, which indicates a successful purchase.
For the complete source code, check out the GitHub repository. 🚀
Conclusion
By following the above steps, you can integrate the react-native-iap library into React Native for in-app purchases, manage subscriptions, handle purchase requests, and access purchase histories.
For more updates on the latest tools and technologies, follow the Simform Engineering blog.