Airo Global Software

Think Beyond Future !

enter image description here

One way or another we develop our apps to make cash out of it. Sometimes we sell ads and make users upgrade for a great experience and we have premium content only for paid users.

We should know about each and every piece of information before handling the payment-related stuff. Be prepared before you start to know about Subscriptions In-App Purchase in Flutter.

Before we get into the programming part let’s learn more about in-app purchases and how it is different for both Android and IOS platforms.

What are the types of products in Android and IOS?

There are types of products in both Android and IOS: First Know about the Products in Android:

  • Consumable product: Products like in-game currency are examples of this type of product. Once the user starts to use them, the user can purchase it again.
  • Non-Consumable product: These can be bought only once and it gives a permanent benefit.
  • Subscriptions: These give benefits to the user for a limited period. You can compare Netflix, Spotify subscriptions to these products.

Know about Products in iOS

  • Consumable product.

  • Non-Consumable product.

  • Auto-Renewable Subscriptions: same as android subscriptions.

  • Non-Renewing Subscriptions: It is almost the same as Auto-Renewable Subscriptions.

What are the steps to add a subscription in the Flutter app?

  • First step is we need to Create a Product

    How to create a product for Android:

  • First go to Google Play Console

  • Second step is to click the app for which you want to build a subscription.

  • Third step is to go Inside the menu under Monetize > Products click Subscriptions.

  • Fourth step is to fill the form with the needed details. Here product id is the most essential field. Product id is used to uniquely find each product.

How to create a product for iOS:

  • First you have to Go to App Store Connect.
  • Second step is to click the app for which you want to make a subscription.
  • Third step is to click In the side menu under the in-app purchase section and now click the manage option.
  • Fourth step is to press the plus sign to include new products and select the type of subscription you want.
  • Fifth step is to type the product name and product id. Here product id is the same as android.
  • Sixth step is to select a subscription group and make a new group.
  • Seventh step is to add a subscription group or make a new group.
  • The last step is to Fill every mandatory information. If any given information is missing for the product then the status of the product will be Missing Metadata. Fill every single information until the status changes to Ready to Submit.
  • Second step is to set up testing accounts.

How to setup testing account for Android:

  • Include the tester’s email address in the applications license testers.
  • Include the same used email address in the app’s tester list.

How to setup testing account for IOS:

  • First step is to go to the app store connect.
  • Second step is to go to User and Access.
  • Third step is to find the Tester option under Sandbox. Press on that.
  • Fourth step is to press on the plus sign to include an apple pay sandbox tester.

Need to understand how the purchase of subscription works:

  • The application notifies the billing server that the present user wants to buy a product with id.
  • The billing Server needs the purchase and gives back the response.
  • The response gets at the application through PurchaseUpdateStream.
  • Your application always checks the status of the purchase and takes the action accordingly.
  • If the purchase was correct the application will notify the application’s back end that this user has perfectly purchased a product and this is the shopping token I got from the billing server.
  • The application’s back end will check the purchase with the billing server before giving any advantages to the user. After perfect validation, your app’s back end will mark the present user as a premium user and notify the application.
  • Now the app has to finish the transaction with the billing server. Completion of the transaction is a way of ordering the billing server that you have perfectly delivered the product to the user.
  • Transaction that finished is different for Android and iOS. In Android, you just have to finish the transaction which is successful. In iOS, you have to finish every transaction irrespective of the status of the transaction.
  • Transaction completion is very important because if you don’t finish the transaction in Android, Google will give back the amount of purchase considering that the purchase was failed.
  • In case of application crashes or network problems happening during the transaction when the user opens the application again your app will be notified with all the unfinished transactions through the PurchaseUpdateStream. So, you can continue the plan of purchase of the product.
  • Based on the response received from the app’s back end you will show a special display to the user.

Next step is to integrate in-App purchases with flutter.

To manage our code we will develop one new folder:

class
PaymentService {
/// We want singleton object of ``PaymentService`` so 
create private constructor
 ///
/// Use PaymentService as ``PaymentService.instance``
PaymentService._internal();
static final PaymentService instance = 
PaymentService._internal();
}

Next is to create some variables:

class 
PaymentService
{
/// We want singleton object of ``PaymentService`` so create
private constructor
///
/// Use PaymentService as ``PaymentService.instance``
PaymentService._internal();
static final PaymentService instance =
PaymentService._internal();
/// To listen the status of connection between app and the billing server
StreamSubscription<ConnectionResult>
_connectionSubscription;
/// To listen the status of the purchase made inside or outside of the app (App Store / Play Store)
///
/// If status is not error then app will be notied by this stream
StreamSubscription<PurchasedItem>
_purchaseUpdatedSubscription;
/// To listen the errors of the purchase
StreamSubscription<PurchaseResult>
_purchaseErrorSubscription;
/// List of product ids you want to fetch
final List<String> _productIds = [
'monthly_subscription'
];

/// All available products will be store in this list List _products;

/// All past purchases will be store in this list
List<PurchasedItem> _pastPurchases;
/// view of the app will subscribe to this to get notified
/// when premium status of the user changes
ObserverList<Function> _proStatusChangedListeners =
new ObserverList<Function>();
/// view of the app will subscribe to this to get errors of the purchase
 ObserverList<Function(String)> _errorListeners =
 new ObserverList<Function(String)>();
/// logged in user's premium status
bool _isProUser = false;
bool get isProUser => _isProUser;
}

Want to get the UI latest updates use the below code:

 addToProStatusChangedListeners(Function callback) {
 _proStatusChangedListeners.add(callback);
}
/// view can cancel to _proStatusChangedListeners using this method

removeFromProStatusChangedListeners(Function callback) {

_proStatusChangedListeners.remove(callback);
 }
/// view can subscribe to _errorListeners using this method
addToErrorListeners(Function callback) {
_errorListeners.add(callback);
}
 /// view can cancel to _errorListeners using this method
removeFromErrorListeners(Function callback) {
_errorListeners.remove(callback);
 }

Following code to notify the user:

void _callProStatusChangedListeners() {
_proStatusChangedListeners.forEach((Function callback) {
 callback();
 });
}

 /// Call this method to notify all the subsctibers of _errorListeners
void _callErrorListeners(String error) {
 _errorListeners.forEach((Function callback) {
callback(error);
});
}

Call the interconnection method at the start your app using below code:

 /// with billing server and get all the necessary data
 void initConnection() async {
await FlutterInappPurchase.instance.initConnection;
 _connectionSubscription =
FlutterInappPurchase.connectionUpdated.listen((connected) {});
 _purchaseUpdatedSubscription =
FlutterInappPurchase.purchaseUpdated.listen(_handlePurchaseUpdate);
_purchaseErrorSubscription =
FlutterInappPurchase.purchaseError.listen(_handlePurchaseError);
_getItems();
 _getPastPurchases();
}
 /// call when user close the app
void dispose() {
_connectionSubscription.cancel();
 _purchaseErrorSubscription.cancel();
 _purchaseUpdatedSubscription.cancel();
FlutterInappPurchase.instance.endConnection;
}

Handle purchase errors using the below code:

void _handlePurchaseError(PurchaseResult
purchaseError) {
_callErrorListeners(purchaseError.
message);
}

For handle purchase updates:

void _handlePurchaseUpdate(PurchasedItem productItem) async
{
if (Platform.isAndroid) {
await _handlePurchaseUpdateAndroid(productItem);
 } else {
await _handlePurchaseUpdateIOS(productItem);
}
}

For finish the transaction:

Future<void> 
_handlePurchaseUpdateI
OS(PurchasedItem
purchasedItem) async {
switch (purchasedItem.transactionStateIOS) {
case TransactionState.deferred:
// Edit: This was a bug that was pointed out here : 
https://github.com/dooboolab/flutter_inapp_purchase/issues/234
//
FlutterInappPurchase.instance.finishTransaction(purchasedItem);
break;
case TransactionState.failed:
 _callErrorListeners("Transaction Failed");
FlutterInappPurchase.instance.finishTransaction(purchasedItem);
 break;
case TransactionState.purchased:
await
_verifyAndFinishTransaction(purchasedItem);
break;
case TransactionState.purchasing:
break;
 case TransactionState.restored:
FlutterInappPurchase.instance.finishTransaction(purchasedItem);
break;
default:
}
 }
/// three purchase state 
https://developer.android.com/reference/com/android/billingclient/api/Purchase.PurchaseState
/// 0 : UNSPECIFIED_STATE
/// 1 : PURCHASED
 /// 2 : PENDING
Future<void> 
_handlePurchaseUpdateAndroid(PurchasedItem purchasedItem) async {
switch (purchasedItem.purchaseStateAndroid) {
 case 1:
if (!purchasedItem.isAcknowledgedAndroid) {
 await 
_verifyAndFinishTransaction(purchasedItem);

}
  break;
default:
_callErrorListeners("Something went wrong");
 }
}

For verify purchase is success:

 /// Call API of your back end to verify the receipt
 /// back end has to call billing server's API to verify the purchase token
 _verifyAndFinishTransaction(PurchasedItem purchasedItem) async {
bool isValid = false;
try {
// Call API
isValid = await _verifyPurchase(purchasedItem);
} on NoInternetException {
_callErrorListeners("No Internet");
 return;
} on Exception {
 _callErrorListeners("Something went wrong");
return;
}
 if (isValid) {
 FlutterInappPurchase.instance.finishTransaction(purchasedItem);
 _isProUser = true;
// save in sharedPreference here
_callProStatusChangedListeners();
} else {
_callErrorListeners("Verification failed");
}
}

For get all the available products:

Future<List<IAPItem>> get
products async {
 if (_products == null) {
await _getItems();
}
}
return _products;
}
Future<void> _getItems() async {
List<IAPItem> items =
await 
FlutterInappPurchase.instance.getSubscriptions
(_productIds);
 _products = List();
 for (var item in items) {
this._products.add(item);
}
}

To buy the product:

Future<Null> 
buyProduct(IAPItem item)
async {
try {
await 
FlutterInappPurchase.instance.requestSubscription(item.productId);
 } catch (error) {
 }
}

If you have any doubts about the above topic or have to get services and consultations and get the best Flutter application services. Feel free to contact us. AIRO GLOBAL SOFTWARE will be your strong digital partner. E-mail id: [email protected].

enter image description here Author - Johnson Augustine
Chief Technical Director and Programmer
Founder: Airo Global Software Inc
LinkedIn Profile: www.linkedin.com/in/johnsontaugustine/