in_app_purchase 0.1.0+4

  • README.md
  • CHANGELOG.md
  • Example
  • Installing
  • Versions
  • 82

In App Purchase #

A Flutter plugin for in-app purchases. Exposes APIs for making in app purchases through the App Store (on iOS) and Google Play (on Android).

Features #

Add this to your Flutter app to:

  1. Show in app products that are available for sale from the underlying shop. Includes consumables, permanent upgrades, and subscriptions.
  2. Load in app products currently owned by the user according to the underlying shop.
  3. Send your user to the underlying store to purchase your products.

Getting Started #

This plugin is in beta. Please use with caution and file any potential issues you see on our issue tracker.

This plugin relies on the App Store and Google Play for making in app purchases. It exposes a unified surface, but you'll still need to understand and configure your app with each store to handle purchases using them. Both have extensive guides:

You can check out the example app README for steps on how to configure in app purchases in both stores.

Once you've configured your in app purchases in their respective stores, you're able to start using the plugin. There's two basic options available to you to use.

  1. in_app_purchase.dart, the generic idiommatic Flutter API. This exposes the most basic IAP-related functionality. The goal is that Flutter apps should be able to use this API surface on its own for the vast majority of cases. If you use this you should be able to handle most use cases for loading and making purchases. If you would like a more platform dependent approach, we also provide the second option as below.

  2. Dart APIs exposing the underlying platform APIs as directly as possible: store_kit_wrappers.dart and billing_client_wrappers.dart. These API surfaces should expose all the platform-specific behavior and allow for more fine-tuned control when needed. However if you use this you'll need to code your purchase handling logic significantly differently depending on which platform you're on.

Initializing the plugin #

// Subscribe to any incoming purchases at app initialization. These can
// propagate from either storefront so it's important to listen as soon as
// possible to avoid losing events.
class _MyAppState extends State<MyApp> {
  StreamSubscription<List<PurchaseDetails>> _subscription;

  @override
  void initState() {
    final Stream purchaseUpdates =
        InAppPurchaseConnection.instance.purchaseUpdatedStream;
    _subscription = purchaseUpdates.listen((List<PurchaseDetails> purchases) {
      _handlePurchaseUpdates(purchases);
    });
    super.initState();
  }

  @override
  void dispose() {
    _subscription.cancel();
    super.dispose();
  }

Connecting to the Storefront #

final bool available = await InAppPurchaseConnection.instance.isAvailable();
if (!available) {
  // The store cannot be reached or accessed. Update the UI accordingly.
}

Loading products for sale #

const Set<String> _kIds = <String>['product1', 'product2'].toSet();
final ProductDetailsResponse response = await InAppPurchaseConnection.instance.queryProductDetails(_kIds);
if (!response.notFoundIds.isEmpty()) {
    // Handle the error.
}
List<ProductDetails> products = response.productDetails;

Loading previous purchases #

final QueryPurchaseDetailsResponse response = await InAppPurchaseConnection.instance.queryPastPurchases();
if (response.error != null) {
    // Handle the error.
}
for (PurchaseDetails purchase : repsonse.pastPurchases) {
    _verifyPurchase(purchase);  // Verify the purchase following the best practices for each storefront.
    _deliverPurchase(purchase); // Deliver the purchase to the user in your app.
    if (Platform.isIOS) {
        // Mark that you've delivered the purchase. Only the App Store requires
        // this final confirmation.
        InAppPurchaseConnection.instance.completePurchase(purchase);
    }
}

Note that the App Store does not have any APIs for querying consummable products, and Google Play considers consummable products to no longer be owned once they're marked as consumed and fails to return them here. For restoring these across devices you'll need to persist them on your own server and query that as well.

Making a purchase #

Both storefronts handle consummable and non-consummable products differently. If you're using InAppPurchaseConnection, you need to make a distinction here and call the right purchase method for each type.

final ProductDetails productDetails = ... // Saved earlier from queryPastPurchases().
final PurchaseParam purchaseParam = PurchaseParam(productDetails: productDetails);
if (_isConsumable(productDetails)) {
    InAppPurchaseConnection.instance.buyConsumable(purchaseParam: purchaseParam);
} else {
    InAppPurchaseConnection.instance.buyNonConsumable(purchaseParam: purchaseParam);
}

// From here the purchase flow will be handled by the underlying storefront.
// Updates will be delivered to the `InAppPurchaseConnection.instance.purchaseUpdatedStream`.

Development #

This plugin uses json_serializable for the many data structs passed between the underlying platform layers and Dart. After editing any of the serialized data structs, rebuild the serializers by running flutter packages pub run build_runner build --delete-conflicting-outputs. flutter packages pub run build_runner watch --delete-conflicting-outputs will watch the filesystem for changes.

0.1.0+4 #

  • Change the buy methods to return Future<bool> instead of void in order to propagate launchBillingFlow failures up through google_play_connection.

0.1.0+3 #

  • Guard against multiple onSetupFinished() calls.

0.1.0+2 #

  • Fix bug where error only purchases updates weren't propagated correctly in google_play_connection.dart.

0.1.0+1 #

Add more consumable handling to the example app.

0.1.0 #

Beta relase.

  • Ability to list products, load previous purchases, and make purchases.
  • Simplified Dart API that's been unified for ease of use.
  • Platform specific APIs more directly exposing StoreKit and BillingClient.

Includes:

  • 5ba657dc [in_app_purchase] Remove extraneous download logic (#1560)
  • 01bb8796 [in_app_purchase] Minor doc updates (#1555)
  • 1a4d493f [in_app_purchase] Only fetch owned purchases (#1540)
  • d63c51cf [in_app_purchase] Add auto-consume errors to PurchaseDetails (#1537)
  • 959da97f [in_app_purchase] Minor doc updates (#1536)
  • b82ae1a6 [in_app_purchase] Rename the unified API (#1517)
  • d1ad723a [in_app_purchase]remove SKDownloadWrapper and related code. (#1474)
  • 7c1e8b8a [in_app_purchase]make payment unified APIs (#1421)
  • 80233db6 [in_app_purchase] Add references to the original object for PurchaseDetails and ProductDetails (#1448)
  • 8c180f0d [in_app_purchase]load purchase (#1380)
  • e9f141bc [in_app_purchase] Iap refactor (#1381)
  • d3b3d60c add driver test command to cirrus (#1342)
  • aee12523 [in_app_purchase] refactoring and tests (#1322)
  • 6d7b4592 [in_app_purchase] Adds Dart BillingClient APIs for loading purchases (#1286)
  • 5567a9c8 [in_app_purchase]retrieve receipt (#1303)
  • 3475f1b7 [in_app_purchase]restore purchases (#1299)
  • a533148d [in_app_purchase] payment queue dart ios (#1249)
  • 10030840 [in_app_purchase] Minor bugfixes and code cleanup (#1284)
  • 347f508d [in_app_purchase] Fix CI formatting errors. (#1281)
  • fad02d87 [in_app_purchase] Java API for querying purchases (#1259)
  • bc501915 [In_app_purchase]SKProduct related fixes (#1252)
  • f92ba3a1 IAP make payment objc (#1231)
  • 62b82522 [IAP] Add the Dart API for launchBillingFlow (#1232)
  • b40a4acf [IAP] Add Java call for launchBillingFlow (#1230)
  • 4ff06cd1 [In_app_purchase]remove categories (#1222)
  • 0e72ca56 [In_app_purchase]fix requesthandler crash (#1199)
  • 81dff2be Iap getproductlist basic draft (#1169)
  • db139b28 Iap iOS add payment dart wrappers (#1178)
  • 2e5fbb9b Fix the param map passed down to the platform channel when calling querySkuDetails (#1194)
  • 4a84bac1 Mark some packages as unpublishable (#1193)
  • 51696552 Add a gradle warning to the AndroidX plugins (#1138)
  • 832ab832 Iap add payment objc translators (#1172)
  • d0e615cf Revert "IAP add payment translators in objc (#1126)" (#1171)
  • 09a5a36e IAP add payment translators in objc (#1126)
  • a100fbf9 Expose nslocale and expose currencySymbol instead of currencyCode to match android (#1162)
  • 1c982efd Using json serializer for skproduct wrapper and related classes (#1147)
  • 3039a261 Iap productlist ios (#1068)
  • 2a1593da [IAP] Update dev deps to match flutter_driver (#1118)
  • 9f87cbe5 [IAP] Update README (#1112)
  • 59e84d85 Migrate independent plugins to AndroidX (#1103)
  • a027ccd6 [IAP] Generate boilerplate serializers (#1090)
  • 909cf1c2 [IAP] Fetch SkuDetails from Google Play (#1084)
  • 6bbaa7e5 [IAP] Add missing license headers (#1083)
  • 5347e877 [IAP] Clean up Dart unit tests (#1082)
  • fe03e407 [IAP] Check if the payment processor is available (#1057)
  • 43ee28cf Fix Manifest versionCode not found (#1076)
  • 4d702ad7 Supress strong_mode_implicit_dynamic_method for invokeMethod calls. (#1065)
  • 809ccde7 Doc and build script updates to the IAP plugin (#1024)
  • 052b71a9 Update the IAP README (#933)
  • 54f9c4e2 Upgrade Android Gradle Plugin to 3.2.1 (#916)
  • ced3e99d Set all gradle-wrapper versions to 4.10.2 (#915)
  • eaa1388b Reconfigure Cirrus to use clang 7 (#905)
  • 9b153920 Update gradle dependencies. (#881)
  • 1aef7d92 Enable lint unnecessary_new (#701)

0.0.2 #

  • Added missing flutter_test package dependency.
  • Added missing flutter version requirements.

0.0.1 #

  • Initial release.

example/README.md

In App Purchase Example #

Demonstrates how to use the In App Purchase (IAP) Plugin.

Getting Started #

This plugin is in beta. Please use with caution and file any potential issues you see on our issue tracker.

There's a significant amount of setup required for testing in app purchases successfully, including registering new app IDs and store entries to use for testing in both the Play Developer Console and App Store Connect. Both Google Play and the App Store require developers to configure an app with in-app items for purchase to call their in-app-purchase APIs. Both stores have extensive documentation on how to do this, and we've also included a high level guide below.

Android #

  1. Create a new app in the Play Developer Console (PDC).

  2. Sign up for a merchant's account in the PDC.

  3. Create IAPs in the PDC available for purchase in the app. The example assumes the following SKU IDs exist:

    • consumable: A managed product.
    • upgrade: A managed product.
    • subscription: A subscription.

    Make sure that all of the products are set to ACTIVE.

  4. Update APP_ID in example/android/app/build.gradle to match your package ID in the PDC.

  5. Create an example/android/keystore.properties file with all your signing information. keystore.example.properties exists as an example to follow. It's impossible to use any of the BillingClient APIs from an unsigned APK. See here and here for more information.

  6. Build a signed apk. flutter build apk will work for this, the gradle files in this project have been configured to sign even debug builds.

  7. Upload the signed APK from step 6 to the PDC, and publish that to the alpha test channel. Add your test account as an approved tester. The BillingClient APIs won't work unless the app has been fully published to the alpha channel and is being used by an authorized test account. See here for more info.

  8. Sign in to the test device with the test account from step #7. Then use flutter run to install the app to the device and test like normal.

iOS #

  1. Follow "Workflow for configuring in-app purchases", a detailed guide on all the steps needed to enable IAPs for an app. Complete steps 1 ("Sign a Paid Applications Agreement") and 2 ("Configure in-app purchases").

    For step #2, "Configure in-app purchases in App Store Connect," you'll want to create the following products:

    • A consumable with product ID consumable
    • An upgrade with product ID upgrade
    • An auto-renewing subscription with product ID subscription
  2. In XCode, File > Open File example/ios/Runner.xcworkspace. Update the Bundle ID to match the Bundle ID of the app created in step #1.

  3. Create a Sandbox tester account to test the in-app purchases with.

  4. Use flutter run to install the app and test it. Note that you need to test it on a real device instead of a simulator, and signing into any production service (including iTunes!) with the test account will permanently invalidate it. Sign in to the test account in the example app following the steps in the In-App Purchase Programming Guide.

Use this package as a library

1. Depend on it

Add this to your package's pubspec.yaml file:


dependencies:
  in_app_purchase: ^0.1.0+4

2. Install it

You can install packages from the command line:

with Flutter:


$ flutter pub get

Alternatively, your editor might support flutter pub get. Check the docs for your editor to learn more.

3. Import it

Now in your Dart code, you can use:


import 'package:in_app_purchase/in_app_purchase.dart';
  
Version Uploaded Documentation Archive
0.1.0+4 May 11, 2019 Go to the documentation of in_app_purchase 0.1.0+4 Download in_app_purchase 0.1.0+4 archive
0.1.0+3 May 10, 2019 Go to the documentation of in_app_purchase 0.1.0+3 Download in_app_purchase 0.1.0+3 archive
0.1.0+2 May 10, 2019 Go to the documentation of in_app_purchase 0.1.0+2 Download in_app_purchase 0.1.0+2 archive
0.1.0+1 May 8, 2019 Go to the documentation of in_app_purchase 0.1.0+1 Download in_app_purchase 0.1.0+1 archive
0.1.0 May 2, 2019 Go to the documentation of in_app_purchase 0.1.0 Download in_app_purchase 0.1.0 archive
0.0.2 Nov 27, 2018 Go to the documentation of in_app_purchase 0.0.2 Download in_app_purchase 0.0.2 archive
Popularity:
Describes how popular the package is relative to other packages. [more]
82
Health:
Code health derived from static analysis. [more]
84
Maintenance:
Reflects how tidy and up-to-date the package is. [more]
80
Overall:
Weighted score of the above. [more]
82
Learn more about scoring.

We analyzed this package on May 23, 2019, and provided a score, details, and suggestions below. Analysis was completed with status completed using:

  • Dart: 2.3.1
  • pana: 0.12.16
  • Flutter: 1.5.4-hotfix.2

Platforms

Detected platforms: Flutter

References Flutter, and has no conflicting libraries.

Health suggestions

Fix lib/src/store_kit_wrappers/sk_product_wrapper.dart. (-2.48 points)

Analysis of lib/src/store_kit_wrappers/sk_product_wrapper.dart reported 5 hints:

line 47 col 17: Always override hashCode if overriding ==.

line 104 col 17: Always override hashCode if overriding ==.

line 177 col 17: Always override hashCode if overriding ==.

line 259 col 17: Always override hashCode if overriding ==.

line 312 col 17: Always override hashCode if overriding ==.

Fix lib/src/store_kit_wrappers/sk_product_wrapper.g.dart. (-2.48 points)

Analysis of lib/src/store_kit_wrappers/sk_product_wrapper.g.dart reported 5 hints:

line 19 col 22: The function '_$SkProductResponseWrapperToJson' isn't used.

line 34 col 22: The function '_$SKProductSubscriptionPeriodWrapperToJson' isn't used.

line 83 col 22: The function '_$SKProductDiscountWrapperToJson' isn't used.

line 122 col 22: The function '_$SKProductWrapperToJson' isn't used.

line 138 col 22: The function '_$SKPriceLocaleWrapperToJson' isn't used.

Fix lib/src/billing_client_wrappers/enum_converters.g.dart. (-1.99 points)

Analysis of lib/src/billing_client_wrappers/enum_converters.g.dart reported 4 hints:

line 9 col 18: The function '_$_SerializedEnumsFromJson' isn't used.

line 9 col 18: Name non-constant identifiers using lowerCamelCase.

line 15 col 22: The function '_$_SerializedEnumsToJson' isn't used.

line 15 col 22: Name non-constant identifiers using lowerCamelCase.

Fix additional 10 files with analysis or formatting issues. (-9.99 points)

Additional issues in the following files:

  • lib/src/store_kit_wrappers/enum_converters.g.dart (4 hints)
  • lib/src/billing_client_wrappers/purchase_wrapper.dart (2 hints)
  • lib/src/billing_client_wrappers/purchase_wrapper.g.dart (2 hints)
  • lib/src/billing_client_wrappers/sku_details_wrapper.g.dart (2 hints)
  • lib/src/in_app_purchase/google_play_connection.dart (2 hints)
  • lib/src/in_app_purchase/product_details.dart (2 hints)
  • lib/src/in_app_purchase/purchase_details.dart (2 hints)
  • lib/src/store_kit_wrappers/sk_payment_queue_wrapper.dart (2 hints)
  • lib/src/store_kit_wrappers/sk_payment_queue_wrapper.g.dart (1 hint)
  • lib/src/store_kit_wrappers/sk_payment_transaction_wrappers.dart (1 hint)

Maintenance suggestions

The package description is too short. (-20 points)

Add more detail to the description field of pubspec.yaml. Use 60 to 180 characters to describe the package, what it does, and its target use case.

Dependencies

Package Constraint Resolved Available
Direct dependencies
Dart SDK >=2.0.0-dev.28.0 <3.0.0
async ^2.0.8 2.2.0
collection ^1.14.11 1.14.11
flutter 0.0.0
json_annotation ^2.0.0 2.4.0
meta ^1.1.6 1.1.6 1.1.7
Transitive dependencies
sky_engine 0.0.99
typed_data 1.1.6
vector_math 2.0.8
Dev dependencies
build_runner ^1.0.0
flutter_driver
flutter_test
in_app_purchase_example
json_serializable ^2.0.0
shared_preferences ^0.5.2
test ^1.5.2