dooboolab-community / flutter_inapp_purchase

(Sun Rised!) Flutter plugin for In App Purchase.
MIT License
549 stars 236 forks source link
dart flutter in-app-purchase

flutter_inapp_purchase

Pub Version Flutter CI Coverage Status License

Flutter V2

This packages is compatible with flutter v2 from 4.0.0. For those who use older version please use < 4.0.0.

Sun Rise :sunrise:

Since many one of you wanted me to keep working on this plugin in #93, I've decided to keep working on current project. I hope many one of you can help me maintain this. Thank you for all your supports in advance :tada:.

~~## Deprecated I've been maintaining this plugin since there wasn't an official plugin out when I implemented it. I saw in flutter github issue #9591 that many people have been waiting for this plugin for more than a year before I've thought of building one. However, there has been an official Google plugin rised today which is in_app_purchase. Please try to use an official one because you might want to get much prompt support from giant Google. Also, thanks for all your supports that made me stubborn to work hard on this plugin. I've had great experience with all of you and hope we can meet someday with other projects. I'll leave this project as live for those who need time. I'll also try to merge the new PR's and publish to pub if there's any further work given to this repo.~~

What this plugin do

This is an In App Purchase plugin for flutter. This project has been forked from react-native-iap. We are trying to share same experience of in-app-purchase in flutter as in react-native. We will keep working on it as time goes by just like we did in react-native-iap.

PR is always welcomed.

Breaking Changes

Migration Guide

To migrate to 0.9.0 you must migrate your Android app to Android X by following the Migrating to AndroidX Guide.

Getting Started

Follow the Medium Blog for the configuration.

Follow the Medium Blog to add subscriptions in app purchase.

For help getting started with Flutter, view our online documentation.

For help on editing plugin code, view the documentation.

Methods

Func Param Return Description
initConnection String Prepare IAP module. Must be called on Android before any other purchase flow methods. In ios, it will simply call canMakePayments method and return value.
getProducts List<String> Product IDs/skus List<IAPItem> Get a list of products (consumable and non-consumable items, but not subscriptions). Note: On iOS versions earlier than 11.2 this method will return subscriptions if they are included in your list of SKUs. This is because we cannot differentiate between IAP products and subscriptions prior to 11.2.
getSubscriptions List<String> Subscription IDs/skus List<IAPItem> Get a list of subscriptions. Note: On iOS this method has the same output as getProducts. Because iOS does not differentiate between IAP products and subscriptions.
getPurchaseHistory List<IAPItem> Gets an invetory of purchases made by the user regardless of consumption status (where possible)
getAvailablePurchases List<PurchasedItem> (aka restore purchase) Get all purchases made by the user (either non-consumable, or haven't been consumed yet)
getAppStoreInitiatedProducts List<IAPItem> If the user has initiated a purchase directly on the App Store, the products that the user is attempting to purchase will be returned here. (iOS only) Note: On iOS versions earlier than 11.0 this method will always return an empty list, as the functionality was introduced in v11.0. See Apple Docs for more info Always returns an empty list on Android.
requestSubscription String sku, String oldSkuAndroid?, int prorationModeAndroid?, String obfuscatedAccountIdAndroid?, String obfuscatedProfileIdAndroid?, String purchaseTokenAndroid? Null Create (request) a subscription to a sku. For upgrading/downgrading subscription on Android pass second parameter with current subscription ID, on iOS this is handled automatically by store. purchaseUpdatedListener will receive the result.
requestPurchase String sku, String obfuscatedAccountIdAndroid?, String obfuscatedProfileIdAndroid?, String purchaseToken? Null Request a purchase. purchaseUpdatedListener will receive the result.
finishTransactionIOS String purchaseTokenAndroid PurchaseResult Send finishTransaction call to Apple IAP server. Call this function after receipt validation process
acknowledgePurchaseAndroid String purchaseToken PurchaseResult Acknowledge a product (on Android) for non-consumable and subscription purchase. No-op on iOS.
consumePurchaseAndroid String purchaseToken PurchaseResult Consume a product (on Android) for consumable purchase. No-op on iOS.
finishTransaction String purchaseToken, bool isConsumable? } PurchaseResult Send finishTransaction call that abstracts all acknowledgePurchaseAndroid, finishTransactionIOS, consumePurchaseAndroid methods.
endConnection String End billing connection.
consumeAllItems String Manually consume all items in android. Do NOT call if you have any non-consumables (one time purchase items). No-op on iOS.
validateReceiptIos Map<String,String> receiptBody, bool isTest http.Response Validate receipt for ios.
validateReceiptAndroid String packageName, String productId, String productToken, String accessToken, bool isSubscription http.Response Validate receipt for android.
showPromoCodesIOS Show redeem codes in iOS.
showInAppMessageAndroid Google Play will show users messaging during grace period and account hold once per day and provide them an opportunity to fix their payment without leaving the app

Purchase flow in `flutter_inapp_purchase@2.0.0+

purchase-flow-sequence

When you've successfully received result from purchaseUpdated listener, you'll have to verify the purchase either by acknowledgePurchaseAndroid, consumePurchaseAndroid, finishTransactionIOS depending on the purchase types or platforms. You'll have to use consumePurchaseAndroid for consumable products and android and acknowledgePurchaseAndroid for non-consumable products either subscription. For ios, there is no differences in verifying purchases. You can just call finishTransaction. If you do not verify the purchase, it will be refunded within 3 days to users. We recommend you to verifyReceipt first before actually finishing transaction. Lastly, if you want to abstract three different methods into one, consider using finishTransaction method.

Data Types

Install

Add flutter_inapp_purchase as a dependency in pubspec.yaml

For help on adding as a dependency, view the documentation.

Configuring in app purchase

Usage Guide

Android connect and endConnection

Get IAP items

void getItems () async {
  List<IAPItem> items = await FlutterInappPurchase.instance.getProducts(_productLists);
  for (var item in items) {
    print('${item.toString()}');
    this._items.add(item);
  }
}

Purchase Item

void purchase() {
  FlutterInappPurchase.instance.requestPurchase(item.productId);
}

Register listeners to receive purchase

StreamSubscription _purchaseUpdatedSubscription = FlutterInappPurchase.purchaseUpdated.listen((productItem) {
  print('purchase-updated: $productItem');
});

StreamSubscription _purchaseErrorSubscription = FlutterInappPurchase.purchaseError.listen((purchaseError) {
  print('purchase-error: $purchaseError');
});

Remove listeners when ending connection

_purchaseUpdatedSubscription.cancel();
_purchaseUpdatedSubscription = null;
_purchaseErrorSubscription.cancel();
_purchaseErrorSubscription = null;

Receipt validation

From 0.7.1, we support receipt validation. For Android, you need separate json file from the service account to get the access_token from google-apis, therefore it is impossible to implement serverless. You should have your own backend and get access_token. With access_token you can simply call validateReceiptAndroid method we implemented. Further reading is here. Currently, serverless receipt validation is possible using validateReceiptIos method. The first parameter, you should pass transactionReceipt which returns after requestPurchase. The second parameter, you should pass whether this is test environment. If true, it will request to sandbox and false it will request to production.

validateReceipt() async {
  var receiptBody = {
    'receipt-data': purchased.transactionReceipt,
    'password': '******'
  };
  const result = await validateReceiptIos(receiptBody, false);
  console.log(result);
}

For further information, please refer to guide.

App Store initiated purchases

When the user starts an in-app purchase in the App Store, the transaction continues in your app, the product will then be added to a list that you can access through the method getAppStoreInitiatedProducts. This means you can decide how and when to continue the transaction. To continue the transaction simple use the standard purchase flow from this plugin.

void checkForAppStoreInitiatedProducts() async {
  List<IAPItem> appStoreProducts = await FlutterInappPurchase.getAppStoreInitiatedProducts(); // Get list of products
  if (appStoreProducts.length > 0) {
    _requestPurchase(appStoreProducts.last); // Buy last product in the list
  }
}

Example

Direct to example readme which is just a cp from example project. You can test this in real example project.

ProGuard

If you have enabled proguard you will need to add the following rules to your proguard-rules.pro

#In app Purchase
-keep class com.amazon.** {*;}
-keep class com.dooboolab.** { *; }
-keep class com.android.vending.billing.**
-dontwarn com.amazon.**
-keepattributes *Annotation*

Q & A

Can I buy product right away skipping fetching products if I already know productId?

How do I validate receipt in ios?

How do I validate receipt in android?

Invalid productId in ios.

Help Maintenance

I've been maintaining quite many repos these days and burning out slowly. If you could help me cheer up, buying me a cup of coffee will make my life really happy and get much energy out of it.

Paypal Buy Me A Coffee