Cross-platform app development frameworks certainly make developers’ lives easier, allowing them to build apps for multiple platforms at once. There are some downsides, though. For example, React Native has no ready-made tool for implementing in-app purchases. Therefore, you’ll inevitably have to turn towards third-party libraries.
What options there are for in-app purchases implementation
Popular libraries for in-app subscriptions in React Native apps are react-native-iap and expo-in-app-purchases. I’ll talk about react-native-adapty, though, because there are quite a few benefits to it, compared to the other libraries:
- Unlike those, it provides server-based purchase validation.
- It supports all the features recently implemented by the app stores, all the way from promo offers to pay-upfront features. It’s also quick to support new features to come.
- The code ends up being more clear and straightforward.
- You can modify your product offering and add or remove new offers without having to go through the full release cycle. There’s no need to release beta versions and wait for approval.
There’s much more to the Adapty SDK than that. You get built-in analytics tools for all the key metrics, cohort analysis, server-based purchase validation, A/B testing for paywalls, promo campaigns with flexible segmentation, third-party analytics tool integrations, and more.
In this article
For now, let’s talk about setting up in-app purchases in React Native apps. Here’s what we’re going to cover today:
- Why Expo won’t work for in-app purchases in React Native apps
- Creating a developer account
- Configuring Adapty:
Configuring the App Store
Configuring the Play Store
- Adding subscriptions
- Creating a paywall
- Installing react-native-adapty
- A sample app & the result
In this guide, we’ll try to build an app that displays cat pictures to subscribed users and prompts everyone else with a subscription offer.
Why Expo won’t work for in-app purchases in React Native apps
To cut a long story short: Expo “managed” doesn’t support the native methods app stores offer for purchase processing (also known as store kits). You’ll need to either stick to pure RN or use Expo bare workflow.
Creating a developer account
First, you’ll need to set up app store accounts, as well as create and configure purchases and subscriptions for both iOS and Android. This should hardly take you more than 20 minutes.
If you still haven’t configured your developer account and products in App Store Connect and/or Google Play Console, see these guides:
- For iOS: read the guide from the beginning and up to the “Getting the list of SKProduct” heading, as it’s where we start discussing native implementations.
- For Android: read the guide from the beginning and up to the “Getting a list of products in an app” heading.
For react-native-adapty, you’ll first need to configure your Adapty dashboard. This won’t take much time, but will get you all the advantages listed above Adapty has over hard coding.
On the third step, you’ll be prompted with App Store and Google Play configurations.
For iOS, you’ll need to:
- Specify the Bundle ID;
- Set up the App Store Server Notifications;
- Specify the App Store Connect shared secret.
These fields are required for the purchases to work.
Each field has a 'Read how' hint that contains step-by-step how-to guides. Check these out if you have any questions.
Bundle ID is the unique ID of your app. It must match the one you specified in Xcode, in Targets > [App Name] > General:
For Android, the required fields are the Package Name and Service Account Key File. All these fields have their own Read how hints as well. Package name does in Android what the Bundle ID does in iOS. It must match the one you specified in your code, which can be found in the /android/app/build.gradle file in android.defaultConfig.applicationId:
On the fourth step, you’ll be prompted with connecting the Adapty SDK to your app. Skip this step for now, though—we’ll get back to it a bit later.
Once you’ve signed up, check out the settings tab and remember that this is where your Public SDK key can be found. You’ll need the key later on.
Adding a subscription
Adapty uses products for different subscriptions. Your cat pics subscription can be weekly, bi-annual, or annual. Each of these options will be a separate Adapty product.
Let’s specify in the dashboard that we have one product. To do so, go to Products & A/B Tests → Products and click Create product.
Here, you’ll need to specify the product name, that is, how this subscription will look in your Adapty dashboard.
You’ll also need to specify the App Store Product ID and Play Store Product ID. If you want, specify the period and the name as well for analytics. Click Save.
Creating a paywall
Now, you’ll need to design a paywall, which is a screen that restricts the user’s access to premium features and prompts them with a subscription offer. You’ll need to add the product you’ve created to your paywall. To do so, click Create paywall in the same section (Products & A/B Tests → Paywalls).
- Choose such a Paywall name that you and your team will easily be able to infer, just by looking at the name, which paywall it is.
- You’ll use the Paywall ID to display this paywall in your app. For our sample app, we’ll use “cats_paywall.”
- In the Product drop-down, select your subscription.
Click Save & publish.
That’s it for the configuration. Now, we’ll be adding the dependencies and writing the code.
1. First, add the dependency:
2. Install iOS pods. If you don’t have the CLI pod yet, I strongly recommend you download it. You’ll certainly need it a lot in iOS development.
3. Since iOS React Native projects are written in Obj-C, you’ll need to create a Swift Bridging Header so that Obj-C can read Swift libraries. To do that, just open your Xcode project and create a new Swift file. Xcode will ask whether you want to create a bridging header, which is exactly what you want. Click Create.
4. For Android, make sure that the project – /android/build.gradle by default – is using the kotlin-gradle-plugin of version 1.4.0 or above:
5. For Android, you’ll need to enable multiDex, which can be found in the app’s config file (/android/app/build.gradle by default.)
Voila, you’re all set and can g̶e̶t̶ ̶s̶o̶m̶e̶ ̶r̶e̶s̶t̶ start coding! 🎉
Retrieving the product list in the app
There are tons of useful things happening under react-native-adapty’s hood. You’ll certainly need these, sooner or later, which is why you should initialize the library at the very beginning of your flow. Go as high as you can in your app’s code (you can do this right in the App.tsx as well) and start the initialization:
Here, replace MY_PUBLIC_KEY with your Public SDK key found in the dashboard settings. Actually, the activateAdapty() method can be invoked more than once and in more than one place, but we’ll stick with this design.
Now, we can retrieve the products we’ve added in the Adapty dashboard:
Now, let’s get to practice: We’ll try to build a small app where we can browse the products from our paywalls and make purchases.
I’ll keep things short from here on to avoid making the base logic overcomplicated. I’ll also be coding in TypeScript to show you which types are used and where. For testing, I’ll use my good old iPhone 8. Remember that from iOS 14 on, App Store forbids using store kits in emulators – you can only test using physical devices.
App.tsx root component
1. First, let’s create an App.tsx root component that will have a paywall display button. We’ve already configured the navigation via react-native-navigation – we believe it to be much better than the react-navigation option recommended in the official docs.
What’s going on here? On mount, the fetchPaywalls() function is invoked. It activates the SDK and saves the paywalls in the state so that the user doesn’t have to wait for fetching after tapping the button. There’s just one button in the view that’s supposed to take the user to the paywall we’ve previously designed in the dashboard.
Actually, it’s possible to fetch the paywalls right here, without saving them into the state. By default, adapty.paywalls.getPaywalls() will fetch them from the cache storage (after caching them on launch), which means you won’t have to wait for the method to talk to the server.
Here’s the result:
A paywall component
2. Let’s write a paywall component in the same file.
Here, we’ll just map the products from the paywall and display the purchase button next to each product.
Registering the screen
3. To see what this looks like, let’s register this screen in react-native-navigation. If you’re using some other navigation, skip this step. My root index.js file looks like this:
"Display the paywall” button
4. Now, we’ll just have to assign an action to the "Display the paywall” button. In our case, it’ll prompt a modal via Navigation.
The entire App.tsx file:
That’s it! Now, you can display these paywalls to your users.
If you want to test your iOS subscription in a sandbox, you’ll need to create your own sandbox tester account. Keep in mind that sandbox subscriptions are quickly invalidated to make testing easier. For Android, you won’t need any extra accounts – you can even run tests with an emulator.
Checking whether the user has any active subscriptions
We still need to decide where to store active subscription data to grant the end user access to their premium content. Adapty will help us with this as well, as it saves all purchases associated with the user. Let’s do it this way: if the user has no subscription, they’ll be prompted with a paywall button. If they do, we’ll show them a cat picture.
Since active subscription data is retrieved either from the server or cache storage, you’ll need a loader. For the sake of simplicity, let’s add the isLoading and isPremium states.
Here’s what changed: we’ve added flags to the state. The entire contents of fetchPaywalls() are now wrapped in a try-catch block so that the code will reach setIsLoading(false) in any possible scenario. To check whether the user has an active subscription, we’re retrieving the user’s profile (which contains all their subscription data) and see the value of profile.accessLevels.premium.isActive. You can use as many access levels (accessLevels) – which are basically just subscription tiers, such as Gold or Premium – as you want, but let’s keep the default value for now. Adapty will create the premium access level automatically, and for most apps, this will be enough. isActive will remain true while there’s an active subscription with this access level.
From here on, everything looks quite straightforward. If the user has the premium-tier subscription status, there’s no need to fetch the paywalls – just disable the loader and display the content.
Here, we’re adding a function that renders the content as well as some logic to onRequestBuy: namely, updating isPremium’s state and closing the modal.
That’s the end result:
The whole file:
To sum everything up
We’ve ended up building a pretty looking and extremely useful subscription app. Those who pay will see cats, and everyone else will get paywalls instead. This guide should have taught you everything you might need to implement in-app purchases in your app. And for those who’d be looking forward to delving deeper into store kits – stay tuned for more. Thanks!