RevenueCat Flutter integration

image

Nikita Shuliak

image

Introduction

If your app revenue happens to be a subscription based one, then you must look at RevenueCat. RevenueCat is a service which makes implementing a subscription easy and fast. It puts the Google Play and App Store subscriptions together in one place and handles them, so it is much easier to work with them from a cross platform framework, like Flutter.

RevenueCat basics

There are 4 models in RevenueCat which you need to understand to setup your subscriptions:
1. Products
2. Entitlements
3. Offerings
4. Packages

Products

First of all you need to import your Google Play and Apple Store subscriptions into the RevenueCat dashboard. That’s what the products are for. Simply create products using subscription identifiers from the store.

Entitlements

Usually apps have different access layers depending on user subscription. For example, there may be standard, a premium subscription, etc. To divide your subscriptions into layers you need to create different entitlements intended for each subscription layer. After that you can import products to these entitlements. The entitlement consists of many products, but one product is assigned only to one entitlement.

As you can see from the scheme, you can assign many different subscriptions to one entitlement. Let’s say there are annual and monthly subscriptions assigned to gold entitlement. Knowing this, the app can provide the same level of access to users with these two different subscriptions.

Offerings

Sometimes it is required to show not just your standard list of subscriptions, but also some special list instead. This is where offerings are needed. You can create many paywalls using offerings and show them in the app depending on your business logic. The offering consists of many packages.

Packages

Finally, packages are needed to represent products in the offering. The package wraps subscriptions up from different stores into one package, so they can be represented as a single product in the offering.

Flutter integration

To add the RevenueCat library to your Flutter project you need to follow these 2 simple steps:
1. Add the latest version of purchases_flutter package dependency into the pubspec.yaml file.
2. Add In-App Purchase capability for your iOS project.

Note: setup requirements can change with the time and depend on your Flutter version. Check the latest changes in the official documentation.

Call the Purchases.configure function and pass a RevenueCat public API key to it depending on the current platform. You can find Public API keys on the apps page in the RevenueCat dashboard.

Future<void> initialize() async  {
 PurchasesConfiguration configuration;
 if (Platform.isAndroid) {
   configuration = PurchasesConfiguration(<public_google_sdk_key>);
 } else if (Platform.isIOS) {
   configuration = PurchasesConfiguration(<public_ios_sdk_key>);
 } else {
   // Configure other platforms if you have any 
 }
 await Purchases.configure(configuration);
}

Core features

When your RevenueCat dashboard is set up and the RevenueCat package is added to your project you can start receiving and buying subscriptions in the app. There are four main features which you need to implement:
1. Get available subscriptions
2. Purchase subscription
3. Get purchased subscriptions
4. Restore purchases

Get available subscriptions

First of all, users need to see subscriptions to buy them. Call Purchases.getOfferings method to receive offerings with packages from RevenueCat dashboard. It will return the current offering and all other offers from your dashboard. Call offerings.current to get a current offer or offerings.all[offeringId] to get a specific offer by its identifier.

/// Gets current offering by default or by [offeringId]
Future<List<Package>?> getOffering({String? offeringId}) async {
 try {
   // Get offerings information
   final offerings = await Purchases.getOfferings();

   // If offering with offeringId exists, return it, otherwise return 
   // default offering
   final offering = switch (offeringId) {
     null => offerings.current,
     _ => offerings.all[offeringId] ?? offerings.current,
   };

   // Return offering packages
   return offering?.availablePackages;
 } catch (e) {
   // handle RevenueCat getOfferings error
 }
}

Note: you can make the offer current in the RevenueCat dashboard. Press the “Make current” button and you will be able to get this offer with offerings.current method.

Purchase subscription

To make a purchase select one of the packages returned from the Purchases.getOfferings method and pass it to Purchases.purchaseStoreProduct method. It will show a native window with a subscription offer. If a user buys a subscription it returns updated CustomerInfo where you can find active subscriptions, active entitlements and other useful information.

If a user closes a subscription window without buying a subscription it will throw the PlatformException with PurchasesErrorCode.purchaseCancelledError error code. You can check it using the PurchasesErrorHelper.getErrorCode method. This exception appears frequently and can be the reason for many bug reports in your crashlytic, so it is better to handle this case separately.

/// Calls native purchase pop up
Future<Map<String, EntitlementInfo>> makePurchase(Package package) async {
 try {
   // Get store product from package
   final storeProduct = package.storeProduct;

   // Purchase store product
   final customerInfo = await Purchases.purchaseStoreProduct(storeProduct);

   // Get purchased environment from returned customerInfo
   final activeEntitlements = customerInfo.entitlements.active;

   return activeEntitlements;
 } catch (e) {
   if (e is PlatformException) {
     var errorCode = PurchasesErrorHelper.getErrorCode(e);
     if (errorCode == PurchasesErrorCode.purchaseCancelledError) {
       // user cancelled to buy a subscription. Can be ignored.
     }
   }

   // handle RevenueCat purchase error
   rethrow;
 }
}

Get purchased subscriptions

Now, when a user has a subscription we need to check its state from time to time. To get user purchased subscriptions call Purchases.getCustomerInfo method. It returns CustomerInfo, like in the subscription purchase, which you can use to get an active subscription. Note that RevenueCat SDK has its own cache and if you want to get the latest CustomerInfo, then call Purchases.invalidateCustomerInfoCache method before.

/// Gets customer info. If [invalidateCache] is true, then cache is 
/// invalidated and latest customer info is returned.
Future<Map<String, EntitlementInfo>> getCustomerInfo(
   {bool invalidateCache = false}) async {
 try {
   // Invalidate cache if requested
   if (invalidateCache) {
     await Purchases.invalidateCustomerInfoCache();
   }

   // Get customer info
   final customerInfo = await Purchases.getCustomerInfo();

   // Get purchased environment from returned customerInfo
   final activeEntitlements = customerInfo.entitlements.active;

   return activeEntitlements;
 } catch (e) {
   // handle RevenueCat getCustomerInfo error
   rethrow;
 }
}

Restore purchase

Don’t forget to implement the restore purchase feature. It allows users to restore subscriptions after app uninstall or on another device. Call Purchases.restorePurchases  to restore user purchases. It also returns CustomerInfo where you can get user active subscriptions.

Future<Map<String, EntitlementInfo>> restorePurchases() async {
 try {
   // Restores user purchases
   final customerInfo = await Purchases.restorePurchases();

   // Get purchased environment from returned customerInfo
   final activeEntitlements = customerInfo.entitlements.active;

   return activeEntitlements;
 } catch (e) {
   // handle RevenueCat restorePurchases error
   rethrow;
 }
}

Conclusion

RevenueCat is a good way to implement in-app purchases in Flutter app. It provides wide and complete functionality to support purchases in your cross-platform app.

Still thinking if RevenueCat is a right choice to implement in-app purchases in your Flutter mobile app?

Share your idea with us, and we’ll come up with the best development solution for your case.

Get in touch today