React Native Billing is built to provide an easy interface to InApp Billing on Android, accomplished by wrapping anjlab's InApp Billing library.
const InAppBilling = require("react-native-billing");
InAppBilling.open()
.then(() => InAppBilling.purchase('android.test.purchased'))
.then((details) => {
console.log("You purchased: ", details)
return InAppBilling.close()
})
.catch((err) => {
console.log(err);
});
npm install --save react-native-billing
rnpm link react-native-billing
With this, rnpm will do most of the heavy lifting for linking. But, you will still need add your Google Play license key to the strings.xml
(step 5). If you are using a React Native version less than v18.0 you will also have to do step 4.3 (override onActivityResult
).
npm install --save react-native-billing
- Add the following in
android/setting.gradle
...
include ':react-native-billing', ':app'
project(':react-native-billing').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-billing/android')
- And the following in
android/app/build.gradle
...
dependencies {
...
compile project(':react-native-billing')
}
- Edit
MainActivity.java
. Step 4.3 is only required if you are using a lower React Native version than 18.0 and/or yourMainActivity
class does not inherit fromReactActivity
. - Add
import com.idehub.Billing.InAppBillingBridgePackage;
- Register package in ReactInstanceManager:
.addPackage(new InAppBillingBridgePackage(this))
- Override
onActivityResult
:
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
mReactInstanceManager.onActivityResult(requestCode, resultCode, data);
}
Larger example:
// Step 1; import package:
import com.idehub.Billing.InAppBillingBridgePackage;
public class MainActivity extends Activity implements DefaultHardwareBackBtnHandler {
...
@Override
protected void onCreate(Bundle savedInstanceState) {
...
mReactInstanceManager = ReactInstanceManager.builder()
.setApplication(getApplication())
.setBundleAssetName("index.android.bundle")
.setJSMainModuleName("index.android")
.addPackage(new MainReactPackage())
// Step 2; register package, with your and send in the MainActivity as a parameter (this):
.addPackage(new InAppBillingBridgePackage(this))
.setUseDeveloperSupport(BuildConfig.DEBUG)
.setInitialLifecycleState(LifecycleState.RESUMED)
.build();
...
}
// Step 3: For RN < v0.18, override onActivityResult
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
mReactInstanceManager.onActivityResult(requestCode, resultCode, data);
}
...
- Add your Google Play license key as a line to your
android/app/src/main/res/values/strings.xml
with the nameRNB_GOOGLE_PLAY_LICENSE_KEY
. For example:
<string name="RNB_GOOGLE_PLAY_LICENSE_KEY">YOUR_GOOGLE_PLAY_LICENSE_KEY_HERE</string>
Alternatively, you can add your license key as a parameter when registering the InAppBillingBridgePackage
, like so:
.addPackage(new InAppBillingBridgePackage("YOUR_LICENSE_KEY", this))
If you want to test with static responses, you can use reserved productids defined by Google. These are:
- android.test.purchased
- android.test.canceled
- android.test.refunded
- android.test.item_unavailable
You will only be able to test the purchase
function with static responses.
If you want to test with these productids, you will have to use a null
license key. This is because your actual license key will not validate when using these productids.
In order to do this send in null
as parameter, along with your Activity-instance, when registering the package:
.addPackage(new InAppBillingBridgePackage(null, this))
See the Google Play docs for more info on static responses.
Testing with static responses is limited, because you are only able to test the purchase
function. Therefore, testing with real In-app products is recommended. But before that is possible, you need to do the following:
- I will assume you've already created your Google Play Developer account and an application there.
- Now you need to create an In-app product under your application at the Google Play Developer Console and activate it (press the button at the top right).
- Assuming you have installed this module (InApp Billing), you can write the JS code as explained in the Javascript API section. I suggest you to use
getProductDetails
function to see if it's the product is retrieved. - When you're ready to test, you'll need to properly create a signed APK. You can follow this guide. (Important: You'll have to install the APK as described in the guide. Not in the way you'd normally debug an React Native app on Android).
- When you have the APK, you need to upload it to Play Developer Console, either the Alpha or the Beta channel will be fine. Remember your app will need to have a proper
applicationId
(normally your package name) andversionCode
set inandroid/app/build.gradle
. - After uploading, you will have to publish it to the market. Don't worry, when publishing the APK to the Alpha or Beta channel the APK will not be available for general public. (Important: It might take several hours for Google to process the APK).
- The final part is, you'll need to add testers for the channel you've published to. The web page will give you a signup URL (opt-in) after you've approved open testing. Visit this URL in the browser of your testing device (it must be a physical device, not a emulator) and signup, and download the app where it redirected.
- Try to buy something with the device. The purchase will eventually be cancelled, but you can also do this manually through your Google Merchant wallet.
Important: You can only test on a physical Android device, not from an emulator.
All methods returns a Promise
.
Important: Opens the service channel to Google Play. Must be called (once!) before any other billing methods can be called.
InAppBilling.open()
.then(() => InAppBilling.purchase('android.test.purchased'));
Important: Must be called to close the service channel to Google Play, when you are done doing billing related work. Failure to close the service channel may degrade the performance of your app.
InAppBilling.open()
.then(() => InAppBilling.purchase('android.test.purchased'))
.then((details) => {
console.log("You purchased: ", details)
return InAppBilling.close()
});
- productId (required): String
- developerPayload: String
- transactionDetails: Object:
- productId: String
- orderId: String
- purchaseToken: String
- purchaseTime: String
- purchaseState: String
- receiptSignature: String
- receiptData: String
- developerPayload: String
InAppBilling.purchase('android.test.purchased')
.then((details) => {
console.log(details)
});
- productId (required): String
- consumed: Boolean (If consumed or not)
InAppBilling.consumePurchase('your.inapp.productid').then(...);
- productId (required): String
- developerPayload: String
- transactionDetails: Object:
- productId: String
- orderId: String
- purchaseToken: String
- purchaseTime: String
- purchaseState: String
- receiptSignature: String
- receiptData: String
- developerPayload: String
InAppBilling.subscribe('your.inapp.productid')
.then((details) => {
console.log(details)
});
- productId (required): String
- subscribed: Boolean
InAppBilling.isSubscribed('your.inapp.productid').then(...);
- productId (required): String
- purchased: Boolean
InAppBilling.isPurchased('your.inapp.productid').then(...);
- ownedProductIds: Array of String
InAppBilling.listOwnedProducts().then(...);
- ownedSubscriptionIds: Array of String
InAppBilling.listOwnedSubscriptions().then(...);
- productId (required): String
- productDetails: Object:
- productId: String
- title: String
- description: String
- isSubscription: Boolean
- currency: String
- priceValue: Double
- priceText: String
InAppBilling.getProductDetails('your.inapp.productid').then(...);
- productIds (required): String-array
- productDetailsArray: Array of the productDetails (same as above)
InAppBilling.getProductDetailsArray(['your.inapp.productid', 'your.inapp.productid2']).then(...);
- productId (required): String
- productDetails: Object:
- productId: String
- title: String
- description: String
- isSubscription: Boolean
- currency: String
- priceValue: Double
- priceText: String
InAppBilling.getSubscriptionDetails('your.inapp.productid').then(...);
- productIds (required): String-Array
- productDetailsArray: Array of the productDetails (same as above)
InAppBilling.getSubscriptionDetailsArray(['your.inapp.productid', 'your.inapp.productid2']).then(...);
- productId (required): String
- transactionDetails: Object:
- productId: String
- orderId: String
- purchaseToken: String
- purchaseTime: String
- purchaseState: String
- receiptSignature: String
- receiptData: String
- developerPayload: String
InAppBilling.getPurchaseTransactionDetails('your.inapp.productid')
.then((details) => {
console.log(details)
});
- productId (required): String
- transactionDetails: Object:
- productId: String
- orderId: String
- purchaseToken: String
- purchaseTime: String
- purchaseState: String
- receiptSignature: String
- receiptData: String
- developerPayload: String
InAppBilling.getSubscriptionTransactionDetails('your.inapp.productid')
.then((details) => {
console.log(details)
});