Featured Image
Software Development

Flutter in-app purchase tutorial: monetize your application

In-app purchases have become advantageous for new monetization strategies as they accelerate growth, prompting new revenue streams and opening doors to multiple opportunities. Whether you are getting down to creating a new game, an entertainment platform, or a productivity app, Flutter will make your task easy by supporting seamless implementation of in-app purchases. 

In this blog, we’ll detail the process of integration of in-app purchases into your Flutter app and help you with step-by-step guidance to get you started.

Introduction to In-App Purchases (IAP)

In-app purchases (IAP) have become one of the most powerful and predominant monetization strategies these days. They enable the purchasing of additional features, content, etc., offered within the app by a user. IAP has become extremely critical for revenue generation mainly for apps that are free to download. With in-app purchases in place, developers are able to offer two versions to the end user- a basic version for free and a premium version with features, virtual goods, or subscriptions for monetization. This monetization approach is undoubtedly becoming popular, and that too for a diverse category of apps, including productivity or lifestyle apps to mobile games. 

Benefits of In-App Purchases

There are multiple advantages offered by in-app purchases for both developers and users:

For Developers:

  • Revenue Generation: A steady revenue stream is a major benefit that comes along with IAPs, especially for free apps. This model allows a wider reach for app developers by offering two versions to the users: a basic version for free and a premium version with monetization options.
  • User Engagement: With additional content and features in the offering, the apps ensure consistent user engagement. Users get hooked and keep looking for more, thus spending more time in the app. This amplified engagement leads to a higher lifetime value for each user.
  • Flexibility: Developers get a flexible ground to experiment with various pricing models so as to find the most effective strategies for monetization. The monetization methods can include both one-time purchases and recurring periodic subscriptions.

For Users:

  • Enhanced Experience: Users get an enhanced and interactive experience while accessing the premium features or content via in-app purchases, which makes the app all the more enjoyable and useful for them.
  • Customization: With IAPs, users get a chance to customize their app experience as per their choice. They can set their preferences and needs within the app through cosmetic items or functional upgrades and make it unique for their use.

Types of In-App Purchases

There are three types of In-app purchases; each category having its own purpose and benefits for both developers and users:

Consumable

Consumable IAPs are the features or items within the app that can be purchased, used, and repurchased. These features keep on getting depleted upon use, and the users are required to buy them again for continued benefits. 

Examples:

  • In-game currency: Virtual coins or gems to buy items or upgrades.
  • Extra lives: Additional chances in a game after losing all lives.
  • Power-ups: Temporary boosts in gameplay, like increased speed or strength.

Non-consumable

Non-consumable IAPs are different from consumable IAPs as these require one-time purchasing, offering permanent benefits within the app. Once the premium version is acquired, users don’t need to buy additional features to enjoy the benefits, as they become available indefinitely.

Examples:

  • Ad removal: Removes ads for a smooth experience.
  • Unlocking premium features: Provides access to advanced functionalities that are not available in the free version.
  • Additional content: Extra levels, characters, or content packs that enhance the app experience.

Subscriptions

Subscriptions are another type of IAP where users enter into recurring purchases to get access to premium content or services for a specific period, for instance weekly, monthly, or yearly. The subscription can either be auto-renewed or bought again unless canceled.

Examples:

  • Premium content: Continued access to exclusive articles, videos, or other content.
  • Exclusive features: Grants access to premium services like cloud storage or advanced analytics.
  • Membership programs: Benefits like discounts, early access to new content, or special perks.

Examples of Successful Apps Using In-App Purchases

  • Candy Crush Saga: Users develop a keen interest in this app as it offers multiple consumable in-app purchases like extra lives and boosters. This makes their gameplay more engaging and keeps them hooked so that they keep coming back. 
  • Spotify: This app has become quite popular because of its subscription-based in-app purchases. It offers premium music streaming services, and with IAPs, it provides an ad-free music listening experience as well as offline access.
  • Genshin Impact: This app provides consumable and non-consumable in-app purchases to users where they can buy in-game currency as well as character avatars.

Tinder: Being one of the most popular dating apps, it offers subscription-based in-app purchases to users for premium access. The monetized features include unlimited swipes and the provision to see who liked your profile. The app shows an amplified craze amongst users, with premium subscriptions growing by the day across app categories.

Prerequisites

Before beginning the implementation process, keep a checklist of below prerequisites set up:

Flutter SDK and IDE

  • Flutter should be installed on your system [download it from the official Flutter website
  • There should be a suitable IDE for Flutter development in place, like Visual Studio Code or Android Studio.

Accounts on Play Console & App Store Connect

  • You must have accounts on Google Play Developer Console & App Store Connect (Apple’s paid membership). These platforms will be used for managing your in-app products and purchases.
  • For more information, visit the official pages for Google Play’s Billing System & Apple In-app Purchase

Setup Play Console to test purchases in Android

  • It’s mandatory to finish the entire setup of Google Play Console to test in-app purchases in Android.
  • Understand and go through the steps and guidelines for Google Play’s Billing
  • Make sure that only the account owner of the Play Console can access the Payments Profile & API access under Setup in Play Console.
  • You need to complete the Payments Profile, and it will ask for details based on your country.
  • In the test environment, only license testers can be able to make a purchase or buy a subscription. To manage license testers, go to Play Console > Setup > License Testing.
  • In the test environment, in-app purchase subscriptions will renew every 5 minutes.

Setup App Store Connect to test purchases on iOS

  • Understand and go through the steps and guidelines for Apple In-app Purchase.
  • Make sure that the Paid Apps agreement is signed and active.
  • Also ensure that you provide all the metadata like Localization and Review information for each product and subscription listing and their status should read Ready to Submit.

Also read: Learn how to upgrade your Flutter version to 3.13

Adding dependencies

The initial step is to add all the mandatory dependencies to your Flutter project. Once that is done, open your project’s pubspec.yaml file. Here are the below-mentioned dependencies:

dependencies:
  flutter:
    sdk: flutter
  in_app_purchase: ^2.0.0

Save the file and run the flutter pub get. This step will fetch the new dependencies.

Setting up billing client

For enabling in-app purchases, the billing client setup needs to be completed first. A new class will be needed to manage the billing client initialization, hence create that subsequently. For instance, you can create a BillingService class.

Once you have the BillingService class, explore inside it and initialize the billing client using the below code:

import 'package:in_app_purchase/in_app_purchase.dart';
import 'package:in_app_purchase_android/billing_client_wrappers.dart';
import 'package:in_app_purchase_android/in_app_purchase_android.dart';
import 'package:in_app_purchase_storekit/in_app_purchase_storekit.dart';

class BillingService {
  BillingService._();
  static BillingService get instance => _instance;
  static final BillingService _instance = BillingService._();

  final InAppPurchase _iap = InAppPurchase.instance;

  Future<void> initialize() async {
    if(!(await _iap.isAvailable())) return;
    if (Platform.isIOS) {
      final iosPlatformAddition = _iap
          .getPlatformAddition<InAppPurchaseStoreKitPlatformAddition>();
      await iosPlatformAddition.setDelegate(PaymentQueueDelegate());
    }
  }

  Future<void> dispose() async {
    if (Platform.isIOS) {
      final iosPlatformAddition = _inAppPurchase
          .getPlatformAddition<InAppPurchaseStoreKitPlatformAddition>();
      await iosPlatformAddition.setDelegate(null);
    }
  }
}

Fetching products

To enable fetching of the available in-app products from the store, you need to create a method in your BillingService class. An example is fetchProducts(). You can make use of the following code snippet:

Future<List<ProductDetails>> fetchProducts(List<String> productIds) async {
  Set<String> ids = Set.from(productIds);
  ProductDetailsResponse response =
      await _iap.queryProductDetails(ids);

  if (response.notFoundIDs.isNotEmpty) {
    // Handle not found product IDs
  }

  return response.productDetails;
}

Make sure to replace productIds with the actual IDs of your in-app products.

Making a purchase

Incorporation of purchase flow is necessary after setting the fetching of products. For this, you need to create a method in the BillingService class, such as makePurchase(). This will help you handle the purchase flow. Use the below code:

Future<PurchaseDetails> makePurchase(ProductDetails product) async {
  final purchaseParam = PurchaseParam(productDetails: product);
  final purchaseDetails =
      await _iap.buyNonConsumable(purchaseParam: purchaseParam);

  if (purchaseDetails.status == PurchaseStatus.error) {
    // Handle purchase error
  }

  return purchaseDetails;
}

Handling consumable purchases (optional)

If your app contains consumable in-app products, such as in-game currencies or subscription based currencies, then those consumptions need to be handled properly. As soon as a consumable product is purchased, and a user consumes it then the user’s inventory, account, or balance needs to be updated immediately. You need to modify the makePurchase() method as shown below:

Future<PurchaseDetails> makePurchase(ProductDetails product) async {
  final purchaseParam = PurchaseParam(productDetails: product);

  final purchaseDetails = _isConsumable(product.id) // checks if the product is consumable or not
      ? await _iap.buyConsumable(purchaseParam: purchaseParam);
      : await _iap.buyNonConsumable(purchaseParam: purchaseParam);

  if (purchaseDetails.status == PurchaseStatus.error) {
    // Handle purchase error
  }

  return purchaseDetails;
}

Also read: Enabling Authentication and Navigation in Flutter Web with go_router

Verifying the purchase

When a purchase is made, it is critical that the purchase details are updated with the store to enable the purchase order before delivering the products. For this, send the verification data to your backend so that the user’s purchase can be properly verified. Enable a function here by creating a method in your BillingService class, such as verifyPurchase(). You can use the following code: 

Future<bool> verifyPurchase(PurchaseDetails purchaseDetails) {
  // Provide the [purchaseDetails.verificationData] to your backend to verify.
  final response = await _httpClient.post(
    Uri.https(
      host, // your base url host
      path, // your verify purchase endpoint
    ),
    body: purchaseDetails.verificationData,
  );

  if (response[isSuccess] as bool? ?? false) {
    return result[isVerified] as bool;
  } else {
    // handle error
    return false;
  }
}

Listening to purchase updates

You can listen to the purchase updates via purchaseStream. Add a handler method in your BillingService class and set up the listener in your widget. Use the following code:

// inside BillingService class
Future<void> handlePurchaseUpdates(
  List<PurchaseDetails> purchaseDetailsList,
) async {
  for (final purchaseDetails in purchaseDetailsList) {
    purchaseStatus = purchaseDetails.status;
    switch (purchaseDetails.status) {
      case PurchaseStatus.pending:
        // handle pending case and update the UI
        continue;
      case PurchaseStatus.error:
        // handle error case and update the UI
        break;
      case PurchaseStatus.canceled:
        // handle canceled case and update the UI
        break;
      case PurchaseStatus.purchased:
      case PurchaseStatus.restored:
        if (await verifyPurchase(purchaseDetails)) {
          // you can deliver the product if the purchase has been verified
          deliverProduct(purchaseDetails);
        } else {
          // handle the invalid purchases
          handleInvalidPurchase(purchaseDetails);
        }
        break;
    }
    if (purchaseDetails.pendingCompletePurchase) {
      await _iap.completePurchase(purchaseDetails);
    }
  }
}

// inside your widget
late final StreamSubscription<List<PurchaseDetails>> _purchasesSubscription;

@override
void initState() {
  super.initState();
  _purchasesSubscription = InAppPurchase.instance.purchaseStream.listen(
    BillingService.instance.handlePurchaseUpdates,
    onError: (error) {
      // handle error
    },
  );
}

Implementing the UI

By following the above-mentioned steps, you will have your core logic ready. Now you can initiate the integration of the in-app purchase flow into your app’s UI. For this function, create a purchase button.  You can use makePurchase() command method. Whenever this button is pressed, the response will be handled accordingly.

Also read: Simplifying Paginated List fetching in Flutter with the Generic BLoC Pattern

Testing in-app purchases

For a smooth and engaging user experience, testing in-app purchases is crucial. In the current section, we’ll deep dive into the necessary tips and strategies that are helpful for seamless navigation of the testing phase.

Setting up your testing environment

For a coherent testing of in-app purchases, you will first have to create a controlled testing environment that has the ability to reflect the replication of real user experience without any actual payments being made. Here’s how you can achieve this:

Use test accounts: You can use either Google Play Console or App Store Connect to create test accounts. These portals will enable test purchases without any actual payment processing. Ensure proper utilization to avoid any unexpected payments.

Sandbox mode: This mode offers a simulation of purchases without impacting actual transactions. For iOS, it is essential that your app’s operation is being conducted in the App Store Connect Sandbox environment

Testing on real devices: The final step is to always test your product on real devices. Since you can simulate real-world conditions with precision on these devices, you will be able to gather insights that can help you make data-driven decisions. Emulators are not always able to mimic the behavior of actual devices.

Simulating purchases

One of the most fundamental steps for effective functionality of in-app purchase flow is simulating purchases. Below mentioned guidelines will help in ensuring efficacy:

  1. Non-consumable products: You will have to simulate a purchase by selecting the test account for non-consumable products like any premium features of the app or especially for ad removal. Initiate the purchase process after that and conduct a verification process to ensure that the user has gained access to the purchased feature, content, etc. or not.
  1. Consumable products: In comparison to non-consumable products, simulation of consumable purchases requires careful and precise management.  This is most relevant for features like in-game currency. You have to develop the app’s functionality to ensure prompt and correct updates in the user’s balance or inventory after a purchase is made and any subsequent purchases after that. 
  1. Subscription Testing: If your app also caters to subscription models you should test various scenarios, including initial subscription purchases, renewals, cancellations, and changing subscription levels or phases. You must conduct thorough testing to verify that the subscription lifecycle is functioning seamlessly.

Also read: Complete Guide to Integrating Augmented Reality in Flutter

Comparison of In-App Purchase Plugins

in_app_purchase:

The in_app_purchase plugin is the official Flutter solution for managing in-app purchases on both iOS and Android in the best way possible. It supports all three categories of IAPs -consumable, non-consumable, and subscription purchases, thereby offering developers complete control over their IAP implementations. However, its functionality is quite basic and might require manual handling of platform-specific details. This makes it less suitable for cases involving more complexity.

flutter_inapp_purchase:

The flutter_inapp_purchase plugin by Dooboolab provides advanced features and enhanced customization options compared to the official plugin. Even though it supports both platforms and has an active community, its setup requires more work. Additionally, it offers less official support, making it a better option for developers who need more control.

purchases_flutter (RevenueCat):

The purchases_flutter plugin by RevenueCat provides a much more advanced and comprehensive solution for managing in-app purchases and subscriptions across multiple platforms. Complicated tasks like subscription management, as well as the provision of detailed analytics, are simplified by this plugin. However, for complete features of RevenueCat, an account needs to be created, as it itself operates on a subscription-based pricing model. This involves a learning curve and additional costs.

A thorough comparison of these plugins will offer insights to developers for choosing the plugin that fits their needs and project requirements in the best way. Each plugin is unique with its set of features and benefits, so it’s important to evaluate the specific requirements and desired functionality while deciding on the plugin.

Conclusion

Implementation of in-app purchases in Flutter apps is an empowering method to monetize your applications. The detailed steps explained in this blog will simplify the integration of in-app purchases into your Flutter project. You can also start generating revenue once the implementation process is complete. It is important that you also need to resolve error cases aptly and properly test the purchase flow to enable a seamless user experience.
If you need any support or assistance with the implementation of in-app purchases in Flutter apps, you can get in touch with our expert Flutter app development team at Aubergine Solutions. Connect with us today to make way for new revenue opportunities.

author
Nayan Babariya
Senior Flutter Engineer specializing in cross-platform mobile application development using the Flutter framework. I excel at building high-quality, scalable apps and digital solutions.