✨ Read how Fotorama reduced app’s subscription refund rate by 40% with Refund Saver

Implementing in-app purchases into your Flutter app

Alexey Goncharov

Updated: October 11, 2024

13 min read

Content

61dc01e7b66b1207bca18d3c flutter tutorial 1 configuration purchases

Flutter is a relatively new framework developed by Google that lets you quickly create cross-platform apps. The other popular framework is React Native by Meta. Flutter apps are built for both iOS and Android at once. Therefore, a purchase library must be compatible with both StoreKit and Billing Library. 

Architecture-wise, any payment plugin – including our Adapty Flutter SDK – is a wrapper around the native libraries, StoreKit, and Billing Library. In our case, it’s a wrapper around our own Adapty iOS and Android SDK libraries. 

Open-source libraries for in-app purchases in Flutter-based apps

Popular solutions for purchases in Flutter apps are the open-source plugins in_app_purchase (developed by the team behind Flutter) and flutter_inapp_purchase (non-official plugin). 

These plugins were made to implement client-side purchases. They don’t feature server-side receipt validation. You’ll need to set up your own server-side infrastructure to validate receipts and collect payment analytics concerning renewals, refunds, trials, cancellations, and more. 

What’s more, these libraries are usually slow to support new store features. Just to name a few of these, right now, they lack promo offers, pay-as-you-go features, and the pay upfront feature for iOS.

Since our library talks to our server, it features all of these:

  • Purchase server validation
  • Full native payment features support
  • DRY syntax
  • Subscriptions and purchases analytics and some other data collection
  • A/B tests, as well as quick experimenting with purchases, pricing, and promo periods
  • Paywalls and promo offers

To keep this article brief and easy to read, we’ll link a few articles we’ve previously written about some steps you should take before you start working on purchases for your Flutter app.

1. Creating a developer account on iOS and Android

First, you’ll need to create a developer account if you don’t have one. Next, you’ll need to create a weekly purchase for both iOS and Android. We’ve explained how to do this in our previous articles:

Creating in-app purchases for iOS

Creating in-app purchases for Android

Once you’re done, you can start creating and configuring your project.

2. Creating and configuring the project

To get your purchases running both in your implementation and our system, you’ll need to fill in these technical details.

61dbfcadde3e1409fe5f8314 iy6l5yif4wtrzqfjzaek9s70lntdy9bul 7h6homozvwghjkvrzry8ohu9pva 7wq18d6lyztyrc3ochoezylyispz580qelit5axr2dlrpu0dat0qjcwdbx2ecgeosqtass0c7w 3

For iOS, you’ll need to:

  • Specify the Bundle ID to link your Adapty project to your app;
  • Set up App Store Server Notifications in App Store Connect, so that you can be notified about subscription events;
  • Specify the App Store Shared Secret, which the Adapty server will use to establish a connection to Apple’s servers and validate receipts.

For Android, both Package Name and Service Account Key File must be specified. The package name is the iOS Bundle ID for Android. You need to use the same one that’s used in the code. It can be found in the /android/app/build.gradle file, which is situated in the following directory:

android.defaultConfig.applicationId

3. Configuring products and paywalls

The Adapty product encapsulates those of various stores. It’s just the App Store and Google Play for now, but we’ll introduce other stores in the future. The idea behind this approach is to make cross-platform stats collection easier, as well as let you work with top-level entities, as opposed to identifiers.

Paywall is an abstract entity that contains a product array and a remote config file (which is a JSON file containing the metadata you specified in your dashboard). You hard code the paywall ID into your app – this ID is used to retrieve the config file and product data. You can edit both of these without having to update the app. In the usual scenario, you design the paywall and fill it with the data received from us.

Creating a product

Let’s use Google Play Console and App Store Connect to create a product that corresponds to a weekly subscription. Fill in the ID of the corresponding products, which you can retrieve from payment systems. It’s important to note that since App Store Connect has no API, you’ll need to do this manually. Just once, though. 

61dbfcadc56e16884ceeda5a 34mxwyuolr8iv5x2uec0mz6 ezswlcwoiag3ixmluw25i8qerq8ybrz vj0crilc9uwnkrao9asthwrbehotn 8r7j5amw8ruxtuy2eogngkul8qubafsly9dsisdjsapx0kx2m8 3

Creating a paywall

When creating a paywall, the key thing is to specify its ID in a convenient format. This identifier will later be used by the SDK to request the paywall data. We believe this to be a good approach: with this architecture, there’s no need to hard code your products on the client side. You can be flexible with your product management, versioning, tests, etc. The alternative option would be Firebase JSON with a set of built-in products. This doesn’t provide error validation and isn’t as user-friendly, though.

JSON

Designing the paywall

At this stage, it may be helpful to already think about designing your paywall. There are different approaches on how to create a profitable and good-looking paywall, but usually, it requires some experienced design work and more coding as well. To make this step easier, you can use the paywall builder featured in Adapty. It currently supports only iOS SDK but later will be available for other platforms as well.

Builder new

It’s a user-friendly editor for creating and editing paywalls on the fly, without any coding or design work required. In a few simple steps, you’d be able to create a native paywall with a beautiful background, headline and a list of features, set of subscription products, manually chosen color scheme, and adjustable CTA button. 

The JSON editor, which comes hand-in-hand with the paywall builder, also allows you to localize your paywall in different languages. This means that you can localize all your paywall texts (header, premium features, CTA button text, etc.) using one JSON field. 

Locales

Now ready for your first purchase, so let’s proceed to installing the SDK.

4. How to use the Adapty SDK for Flutter

Let’s look at the main functions we’ll need to configure and use subscriptions.

Installing the library

First, you’ll need to add the adapty_flutter library to your project. To do that, add the following dependency to your pubspec.yaml file:

dependencies:
adapty_flutter: ^2.4.1

After that, run:

flutter pub get

From here, you can import Adapty SDK into your app like this:

import 'package:adapty_flutter/adapty_flutter.dart';

Configuration

iOS: Create Adapty-Info.plist and add it to you project. Add the AdaptyPublicSdkKey in this file with the value of your Public SDK key.

Android: add the AdaptyPublicSdkKey into AndroidManifest.xml (for Android).

You can find your SDK key in Adapty settings:

61dbfcaef59c49d11e233082 lsazt3ucjsc79arcgsxqdhss6j5t7gzc1ozj9kcwzet3 ouvcwuj 63wfcgl1ptjy4xpny8axipncjwfqvyks1yhf88bj2joq3qpn luafk1smbmkclwkxeehl08fbucvxi7d9tx 3

Adapty-Info.plist:

<dict>
	...     
		<key>AdaptyPublicSdkKey</key>

AndroidManifest.xml:

<application ...>
        ...
        <meta-data
               android:name="AdaptyPublicSdkKey"
               android:value="PUBLIC_SDK_KEY" />
 </application>

Next, activate the SDK by invoking this code on the Flutter side:

void main() {
  runApp(MyApp());
}
class _MyAppState extends State<MyApp> {
  @override
  void initState() {
    Adapty().setLogLevel(AdaptyLogLevel.verbose);
    Adapty().activate();
    super.initState();
  }
  // ... _MyAppState implementation ...
}

Adapty logs error messages and other important data to help you understand what’s going on. The function lets you choose one of the five possible values:

Future<void> setLogLevel(AdaptyLogLevel value)

You can read more here.

Adapty creates an internal profile ID for every user. However, if you have your own authentication system, you should set your own Customer User ID:

Future<bool> Adapty.identify(String customerUserId)

You can read more here.

Retrieving paywalls

To retrieve the paywall, run this code:

try {
  final paywall = await Adapty().getPaywall(id: "YOUR_PAYWALL_ID", locale: "en");
  // the requested paywall
} on AdaptyError catch (adaptyError) {
  // handle the error
} catch (e) {
}

Once you have the paywall, you can query the product array that corresponds to it:

Next, build your paywall view using the fetched products and show it to the user.

Making purchases 

In the previous step, you’ve retrieved the paywall. Now, we’ll look for the one you need to display those products in your UI:

try {
  final products = await Adapty().getPaywallProducts(paywall: paywall);
  // the requested products array
} on AdaptyError catch (adaptyError) {
  // handle the error
} catch (e) {
}

Next, using the product array, display all of its items. It also very important to correctly display introductory offers. Read more here.

Let’s say the user wants to buy the first product. For the sake of simplicity, we’ll assume it to be the first item of the product array. 

To initiate the purchase, invoke the makePurchase function. (Remember to wrap this in a try-catch block to still receive all error messages from the SDK):

final product = products.first; // don't forget to check the List is not empty
try {
  final profile = await Adapty().makePurchase(product: product);
  // successful purchase
} on AdaptyError catch (adaptyError) {
  // handle the error
} catch (e) {
}

Once the function has been successfully executed, the result variable will contain an actual user profile. Here’s how to check the access level after the purchase has been completed: 

if (profile?.accessLevels['premium']?.isActive ?? false) {
  // grant access to premium features
}

Note that AdaptyErrorCode.paymentCancelled means the user canceled the purchase themselves, which means it isn’t an actual error message. 

To restore purchases, use the .restorePurchases() method:

try {
  final profile = await Adapty().restorePurchases();
  // check the access level
} on AdaptyError catch (adaptyError) {
  // handle the error
} catch (e) {
}

Take into account that both results from the .makePurchase() and .restorePurchases() contains AdaptyProfile. This object contains data about access levels, subscriptions, and purchases. Usually, you can tell whether the user can access the premium features of your app or not, just by checking their access level.

Subscription status

To avoid having to check through the entire preceding transaction chain, we’re introducing the term “access level.” Access level is a flag that explains how much of the app’s functionality the user can access. If they haven’t made any purchases yet, then their access level will be null. Otherwise, it’ll be what you specified for your product.

For example, you can have two access levels, namely, silver and golden. Different purchases will unlock different access levels and features. Most apps have just one access level.

To see whether the subscription is active, it’s enough to check if the user has an active access level. You can use the .getProfile() method to do just that:

try {
  final profile = await Adapty().getProfile();
  // check the access level
} on AdaptyError catch (adaptyError) {
  // handle the error
} catch (e) {
}

You can also subscribe to the .didUpdateProfileStream stream to timely learn of any changes in the subscriber’s access level. Here’s how: 

Adapty().didUpdateProfileStream.listen((profile) {
  // handle any changes to subscription state
});

Conclusion

We’ve designed our SDK to help you quickly integrate payments into your app.  What’s more, we’ve also tried to simplify all the other steps you might need to take, such as A/B testing, analytics, and further integrations.

We’ll provide full purchase functionality free of charge if your revenue amounts to less than $10,000 per month. Save yourself months of work and focus on the most important thing – your product.

Integrating in-app purchases is easier with Adapty
No need for server coding – Adapty SDK provides an out-of-the-box backend.
Learn More
Unlock 2024 subscription holiday secrets
Discover why apps thrive during Black Friday, Christmas & New Year and how you can do the same.
Get your free report
Unlock 2024 subscription holiday secrets

Recommended posts