React Native Payments - atabegruslan/Notes GitHub Wiki
Introductory article: https://docs.expo.dev/guides/in-app-purchases
Use this library: https://github.com/hyochan/react-native-iap
It support both IAP and Subscriptions. It supports both iOS and Android.
In it, there is already an example demo app: https://github.com/hyochan/react-native-iap/blob/main/IapExample/README.md
An independent good video tutorial for using this: https://www.youtube.com/watch?v=kOWdwnHf4xY
git clone [email protected]:hyochan/react-native-iap.git
cd react-native-iap-main/IapExample
yarn
cd ios
pod install
cd ..
Then edit like this: https://github.com/facebook/metro/issues/431#issuecomment-566262158
yarn ios
You can actually try it in action without setting up payments in your own AppStoreConect or Google Play Console, because the maker of react-native-iap have their own demos setup on their accounts.
See: https://medium.com/dooboolab/react-native-in-app-purchase-121622d26b67
PS: Here, no need to add the Payment capability via xCode. Apparently the makers of this already did.
To test it on real iPhone:
https://github.com/atabegruslan/Notes/wiki/React-Native-Payments#with-real-iphones
To test it on iOS Simulator:
Open react-native-iap-main > IapExample > ios
in xCode.
Then refer to this: https://github.com/atabegruslan/Notes/wiki/React-Native-Payments#with-simulator
PS: If the IapExample uses product ID of com.cooni.point1000, then create the same product ID here.
Tweek the demo example app’s source code, just to view the result data.
The run it from xCode (Do NOT run via the React Native script yarn ios
)
To test it on Android: https://github.com/atabegruslan/Notes/wiki/React-Native-Payments#android
However, as of now, if you run yarn android:play
, you will notice that it won't work, because nowadays Android is unstable.
Reference: https://react-native-iap.hyo.dev/docs/get-started/
Step 0: Set up on AppStoreConnect and Google Play Console
Set up these pre-requisites first in Apple and Google: https://github.com/atabegruslan/Notes/wiki/React-Native-Payments#how-do-money-ultimately-reach-you
iOS: AppStoreConnect > Go into App > Left Side Menu > App Store section > Monetization subsection: In App Purchases or Subscriptions
Android: Google Play Console > Go into App > Left Side Menu > Monetize with Play section > Products subsection > In App Products or Subscriptions
Creating IAP in Apple and Google is straightforward. But creating Subscriptions can be a bit more confusing.
Here are 2 good tutorials for creating Subscriptions in Apple and Google:
- Apple: https://www.youtube.com/watch?v=vg_XKY6VtX8
- Google: https://www.youtube.com/watch?v=ak4WiPK6HwE
Tricky Part 1: In Apple, after you filled all the required fields for Subscription, but you still see a "missing metadata" status. That's because you should also enter some Localizations for its Subscription Group.
Tricky Part 2: In Google, when you fill out the prices for all the countries, it may seem like that you are forced to manually enter all the prices for all the countries. But rather you should use the "Set Prices" button here: https://youtu.be/ak4WiPK6HwE?t=254
Note for Apple:
So, Tricky Part 3: If you already had a previous build released, and your dashboard looks like this:
Then you should first cancel that release and then continue.
Additional notes:
- With IAP, Apple will also require that the Account Holder must accept the Paid Apps Agreement in the Business section of AppStoreConnect.
- With Subscriptions, Apple will also require a Terms of Use link. It can either be Apple's standard EULA: https://www.apple.com/legal/internet-services/itunes/dev/stdeula , or you can upload your own custom EULA to AppStoreConnect: https://developer.apple.com/help/app-store-connect/manage-app-information/provide-a-custom-license-agreement . Then you can paste the link into the App's Description:
Step 1: npx expo install react-native-iap
Step 2: in app.json
, add:
{
"expo": {
"plugins": ["react-native-iap"]
}
}
If step 1 didn't automatically do that.
Step 3 (ios only): Open ios
folder in xCode, add the In App Purchase capability. Here is how you can add a capability: https://developer.apple.com/documentation/xcode/adding-capabilities-to-your-app
Step 4: https://github.com/hyochan/react-native-iap/blob/main/docs/docs/api-reference/hooks.md#installation
If you are using expo-router
and your existing code is like this:
export default function RootLayout() {
return(
<Stack>
<Stack.Screen name="index" />
</Stack>
)
}
then add it in this way:
import { withIAPContext } from 'react-native-iap';
function RootLayout() {
return(
<Stack>
<Stack.Screen name="index" />
</Stack>
)
}
export default withIAPContext(RootLayout);
If you are using React Navigation, you can imitate this https://github.com/hyochan/react-native-iap/blob/main/IapExample/src/navigators/StackNavigator.tsx#L18
Step 5:
Todo: beyond here, I am not sure yet
Initialize Connection:
import { initConnection, endConnection } from 'react-native-iap';
At the beginning, initialize the connection to the store:
await initConnection();
At the end, if there is a connection, end it by endConnection()
Fetch Products:
To get your in-app products (IAPs):
import { getProducts } from 'react-native-iap';
const products = await getProducts({ skus: ['product_id'] });
Request Purchase:
Trigger the purchase flow:
import { requestPurchase } from 'react-native-iap';
await requestPurchase({ sku: 'product_id' });
Handle Purchase Updates:
Listen for purchase updates:
import { purchaseUpdatedListener, finishTransaction } from 'react-native-iap';
const purchaseUpdateSubscription = purchaseUpdatedListener(async (purchase) => {
const { transactionReceipt } = purchase;
if (transactionReceipt) {
// Handle transaction, send receipt to your server for validation
await finishTransaction({ purchase, isConsumable: true });
}
});
return () => {
purchaseUpdateSubscription.remove();
};
Subscriptions:
import { getSubscriptions, requestSubscription } from 'react-native-iap';
const subscriptions = await getSubscriptions({ skus: ['product_id'] }); // This step is needed in iOS
const result = await requestSubscription({ sku: 'product_id' }); // This way is insufficient in Android
// In Android, you actually need to do it this way
// await requestSubscription({
// 'product_id',
// ...(offerToken && { subscriptionOffers: [{ sku, offerToken }] }),
// });
subscriptions
:
[
{
"localizedPrice":"$24.99",
"type":"subs",
"price":"24.99",
"introductoryPricePaymentModeIOS":"",
"currency":"USD",
"title":"1 month subscription for calls",
"introductoryPriceSubscriptionPeriodIOS":"",
"introductoryPrice":"",
"introductoryPriceAsAmountIOS":"",
"description":"bla bla bla",
"discounts":[
],
"introductoryPriceNumberOfPeriodsIOS":"",
"subscriptionPeriodNumberIOS":"1",
"countryCode":"USA",
"subscriptionPeriodUnitIOS":"MONTH",
"productId":"your.product.id",
"platform":"ios"
}
]
result
:
{
"productId":"your.product.id",
"transactionId":"0",
"transactionReceipt":"MIAGC…xo/4MAAAAAAAA=",
"transactionDate":1749025582877
}
More info about the required Offer Token in Android: https://github.com/hyochan/react-native-iap/issues/2155#issuecomment-1689152125 .
You can obtain the Offer Token by import { useIAP } from 'react-native-iap';
then const { subscriptions } = useIAP();
.
The contents of subscriptions
:
[
{
"description":"",
"name":"the title",
"platform":"android",
"productId":"xxx.yyy.zzz",
"productType":"subs",
"subscriptionOfferDetails":[
{
"basePlanId":"the-base-plan-name",
"offerId":null,
"offerTags":[
],
"offerToken":"Xxxx==",
"pricingPhases":{
"pricingPhaseList":[
"Array"
]
}
}
],
"title":"the title (xxx.yyy.zzz (unreviewed))"
}
]
- Buying Android Subscription, getting
Error: Billing is unavailable. This may be a problem with your device, or the Play Store may be down.
: https://github.com/hyochan/react-native-iap/issues/1243#issuecomment-1709854926 - Buying Android Subscription, getting Item Unavailable Error: https://github.com/hyochan/react-native-iap/issues/618#issuecomment-565736823
Disclaimer: This nominally "validating receipt" step is actually more like a results retrieval step.
Google Play Developer API
-
purchaseToken
will be obtained from the mobile app after purchase. - Need OAuth2 access token from Google service account.
- Checks if the purchase is valid, refunded, etc:
- For IAP: https://developers.google.com/android-publisher/api-ref/rest/v3/purchases.products/get
- For Subscription: https://developers.google.com/android-publisher/api-ref/rest/v3/purchases.subscriptions/get
Other resources:
- https://gist.github.com/derrek/763ef95c71491833ae3c1e4acad6785e (maybe ?)
- https://stackoverflow.com/questions/35127086/android-inapp-purchase-receipt-validation-google-play (maybe ?)
App Store Server API
- Use Private key (.p8) , Key ID & Issuer ID to obtain JWT.
- Getting the full purchase data:
- https://developer.apple.com/documentation/appstorereceipts/verifyreceipt (obsolete)
- https://developer.apple.com/documentation/appstoreserverapi/get-transaction-info
Android
- purchaseToken - Obtained when the purchase happens. Use it with the Play Developer API to fetch status (orderId, refund, etc).
- orderId
- productId
- purchaseTime
There's also:
- Monetize > Reports > sales & retention data
iOS
- transaction_id
- product_id
- purchase_date
There's also:
- Sales & Trends > aggregate reports
- Financial Reports > revenue summaries
- https://www.youtube.com/watch?v=L7TSyoTP2gg
- https://medium.com/@subtain.techling/subscription-in-react-native-a-comprehensive-guide-75fa1ec34f95
- https://www.youtube.com/watch?v=QxHeZiW4KCA
- https://www.youtube.com/live/bE6eyZcU89U
- https://www.youtube.com/watch?v=IbviHzKHDXY
- https://www.youtube.com/watch?v=UErKquhKUVA
- https://www.youtube.com/live/i5UqNMZUUKM
- https://github.com/RevenueCat/react-native-purchases
- https://www.revenuecat.com/blog/engineering/ios-in-app-subscription-tutorial-with-storekit-2-and-swift
- https://www.revenuecat.com/docs/getting-started/entitlements/android-products
This tutorial should cover it all: https://www.youtube.com/watch?v=u5p1P0gCmJo
In short, create some Licensed Testers in Google Play Console, verify those emails, then use those accounts in Google Play Store.
More documentation: https://developer.android.com/google/play/billing/test
Create sandbox tester account here: https://appstoreconnect.apple.com/access/users/sandbox
Follow this tutorial: https://www.youtube.com/watch?v=GeB2ws0YgsQ
Then you also get email to verify your email.
Note:
- Was: Settings > iTunes & App Store
- Now: App Store app > scroll down > sign in with Sandbox Apple ID
More documentation:
- https://developer.apple.com/help/app-store-connect/test-in-app-purchases/overview-of-testing-in-sandbox
- https://developer.apple.com/documentation/storekit/testing-in-app-purchases-with-sandbox
StoreKit Testing:
- https://developer.apple.com/documentation/Xcode/setting-up-storekit-testing-in-xcode
- https://developer.apple.com/videos/play/wwdc2020/10659
- https://www.youtube.com/watch?v=Nf-6IeGXRTY
In xCode: Create a StoreKit Config File (named Products) and an InApp Consumable.
Then edit the Schema to include the StoreKit Config file.
Then run Simulator from xCode (Press the Play button near the top left of xCode).
If you are using React Native, then DONT run it via the React Native script in terminal. You must run it from xCode, otherwise the StoreKit config file won't be taken into account.
If you are using React Native Expo, and after you pressed the Play button in xCode, you got the error saying that it cant connect to the server. Then you need to first run in the terminal npx expo run:ios
and keep it running. Then run from xCode by pressing the Play button.
More documentations:
GooglePay / Google Play Store, or physically via a shop
Apple pay (which is just a wrapper around credit cards, paypal, momo, ...) or iTunes wallet
Ensure your info is setup here:
More info:
- https://developer.android.com/google/play/billing
- https://support.google.com/googleplay/android-developer/answer/10281818?hl=en
Ensure your info is setup here:
https://appstoreconnect.apple.com > "Agreements, Tax & Banking"
More info: https://developer.apple.com/help/app-store-connect/getting-paid/overview-of-receiving-payments
How to cancel: https://support.google.com/googleplay/answer/7018481?hl=en&co=GENIE.Platform%3DAndroid
Webhook that fires when cancellation happens: https://developer.android.com/google/play/billing/rtdn-reference
How to cancel: https://www.youtube.com/shorts/VhEVpWFWG48
Webhook that fires when cancellation happens: https://developer.apple.com/documentation/appstoreservernotifications
More info:
- https://developer.apple.com/help/app-store-connect/manage-subscriptions/enable-billing-grace-period-for-auto-renewable-subscriptions
- https://developer.apple.com/forums/thread/85636 (unsure ?)
- https://developer.android.com/google/play/billing/integrate
- https://developer.android.com/google/play/billing/subscriptions
- https://support.google.com/googleplay/android-developer/answer/1153481?hl=en&sjid=10682715252229488722-NC
- https://support.google.com/googleplay/android-developer/answer/140504?hl=en-GB&sjid=18411447860957700209-NC