{"id":24506419,"url":"https://github.com/memspace/iap","last_synced_at":"2025-04-14T07:10:57.826Z","repository":{"id":56832767,"uuid":"152191696","full_name":"memspace/iap","owner":"memspace","description":"Flutter plugin for interacting with iOS StoreKit and Android Billing Library","archived":false,"fork":false,"pushed_at":"2018-12-22T00:41:46.000Z","size":214,"stargazers_count":20,"open_issues_count":1,"forks_count":2,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-27T20:51:12.503Z","etag":null,"topics":["android","android-billing-library","dart","flutter","flutter-plugin","ios","storekit"],"latest_commit_sha":null,"homepage":null,"language":"Dart","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/memspace.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-10-09T05:18:19.000Z","updated_at":"2024-05-17T16:48:04.000Z","dependencies_parsed_at":"2022-09-08T05:11:03.999Z","dependency_job_id":null,"html_url":"https://github.com/memspace/iap","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/memspace%2Fiap","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/memspace%2Fiap/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/memspace%2Fiap/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/memspace%2Fiap/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/memspace","download_url":"https://codeload.github.com/memspace/iap/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248837287,"owners_count":21169374,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["android","android-billing-library","dart","flutter","flutter-plugin","ios","storekit"],"created_at":"2025-01-21T23:36:41.280Z","updated_at":"2025-04-14T07:10:57.382Z","avatar_url":"https://github.com/memspace.png","language":"Dart","funding_links":[],"categories":[],"sub_categories":[],"readme":"Flutter plugin for interacting with iOS StoreKit and Android Billing Library.\n\n[![Build Status](https://travis-ci.com/memspace/iap.svg?branch=master)](https://travis-ci.com/memspace/iap) [![codecov](https://codecov.io/gh/memspace/iap/branch/master/graph/badge.svg)](https://codecov.io/gh/memspace/iap)\n\n**Work in progress.**\n\n### How this plugin is different from others\n\nThe main difference is that instead of providing unified interface for in-app purchases\non iOS and Android, this plugin exposes two separate APIs.\n\nThere are several benefits to this approach:\n\n* We can expose _complete_ API interfaces for both platforms, without having to look for lowest\n  common denominator of those APIs.\n* Dart interfaces are designed to match native ones most of the time. `StoreKit` for iOS follows\n  native interface in 99% of cases. `BillingClient` for Android is very similar as well, but also\n  simplifies some parts of native protocol (mostly replaces listeners with Dart `Future`s).\n* Developers familiar with native APIs would find it easier to learn. You can simply refer to\n  official documentation in most cases to find details about certain method of field.\n\nAll Dart code is thoroughly documented with information taken directly from \nApple Developers website (for StoreKit) and Android Developers website (for BillingClient).\n\nNote that future versions may introduce unified interfaces for specific use cases, for instance,\nhandling of in-app subscriptions.\n\n### StoreKit (iOS)\n\n\u003e Plugin currently implements all native APIs except for **downloads**.\n\u003e If you are looking for this functionality consider submitting a pull request\n\u003e or leaving your :+1: [here](https://github.com/memspace/iap/issues/1).\n\nInteracting with StoreKit in Flutter is almost 100% identical to the native ObjectiveC\ninterface.\n\n#### Prerequisites\n\nMake sure to\n\n* Complete Agreements, Tax and Bankings\n* Setup your products in AppStore Connect\n* Enable In-App Purchases for your app in XCode\n\n#### Complete example\n\nCheckout a complete example of interacting with StoreKit in the example app in this repo. Note\nthat in-app purchases is a complex topic and it would be really hard to cover everything\nin a simple example app like this, so it is highly recommended to read official documentation\non setting up in-app purchases for each platform.\n\n#### Getting products\n\n```dart\nfinal productIds = ['my.product1', 'my.product2'];\nfinal SKProductsResponse response = await StoreKit.instance.products(productIds);\nprint(response.products); // list of valid [SKProduct]s\nprint(response.invalidProductIdentifiers) // list of invalid IDs\n```\n\n#### App Store Receipt\n\n```dart\n// Get receipt path on device\nfinal Uri receiptUrl = await StoreKit.instance.appStoreReceiptUrl;\n// Request a refresh of receipt\nawait StoreKit.instance.refreshReceipt();\n```\n\n#### Handling payments and transactions\n\nPayments and transactions are handled within `SKPaymentQueue`.\n\nIt is important to set an observer on this queue as early as possible after\nyour app launch. Observer is responsible for processing all events\ntriggered by the queue. Create an observer by extending following class:\n\n```dart\nabstract class SKPaymentTransactionObserver {\n  void didUpdateTransactions(SKPaymentQueue queue, List\u003cSKPaymentTransaction\u003e transactions);\n  void didRemoveTransactions(SKPaymentQueue queue, List\u003cSKPaymentTransaction\u003e transactions) {}\n  void failedToRestoreCompletedTransactions(SKPaymentQueue queue, SKError error) {}\n  void didRestoreCompletedTransactions(SKPaymentQueue queue) {}\n  void didUpdateDownloads(SKPaymentQueue queue, List\u003cSKDownload\u003e downloads) {}\n  void didReceiveStorePayment(SKPaymentQueue queue, SKPayment payment, SKProduct product) {}\n}\n```\n\nSee API documentation for more details on these methods.\n\nMake sure to implement `didUpdateTransactions` and process all transactions\naccording to your needs. Typical implementation should normally look like this:\n\n```dart\nvoid didUpdateTransactions(\n    SKPaymentQueue queue, List\u003cSKPaymentTransaction\u003e transactions) async {\n  for (final tx in transactions) {\n    switch (tx.transactionState) {\n      case SKPaymentTransactionState.purchased:\n        // Validate transaction, unlock content, etc...\n        // Make sure to call `finishTransaction` when done, otherwise\n        // this transaction will be redelivered by the queue on next application\n        // launch.\n        await queue.finishTransaction(tx);\n        break;\n      case SKPaymentTransactionState.failed:\n        // ...\n        await queue.finishTransaction(tx);\n        break;\n      // ...\n    }\n  }\n}\n```\n\nBefore attempting to add a payment always check if the user can actually\nmake payments:\n\n```dart\nfinal bool canPay = await StoreKit.instance.paymentQueue.canMakePayments();\n```\n\nWhen that's verified and you've set an observer on the queue you can add\npayments. For instance:\n\n```dart\nfinal SKProductsResponse response = await StoreKit.instance.products(['my.inapp.subscription']);\nfinal SKProduct product = response.products.single;\nfinal SKPayment = SKPayment.withProduct(product);\nawait StoreKit.instance.paymentQueue.addPayment(payment);\n// ...\n// Use observer to track progress of this payment...\n```\n\n#### Restoring completed transactions\n\n```dart\nawait StoreKit.instance.paymentQueue.restoreCompletedTransactions();\n/// Optionally implement `didRestoreCompletedTransactions` and \n/// `failedToRestoreCompletedTransactions` on observer to track\n/// result of this operation.\n```\n\n### BillingClient (Android)\n\nThis plugin wraps official [Google Play Billing Library](https://developer.android.com/google/play/billing/billing_library_overview).\nUse `BillingClient` class as the main entry point.\n\nConstructor of `BillingClient` class expects an instance of `PurchaseUpdatedListener` interface\nwhich looks like this:\n\n```dart\n/// Listener interface for purchase updates which happen when, for example,\n/// the user buys something within the app or by initiating a purchase from\n/// Google Play Store.\nabstract class PurchasesUpdatedListener {\n  /// Implement this method to get notifications for purchases updates.\n  ///\n  /// Both purchases initiated by your app and the ones initiated by Play Store\n  /// will be reported here.\n  void onPurchasesUpdated(int responseCode, List\u003cPurchase\u003e purchases);\n}\n```\n\n#### Using `BillingClient`\n\nTo begin working with Play Billing service always start from establishing connection using\n`startConnection` method:\n\n```dart\nimport 'package:iap/iap.dart';\n\nbool _connected = false;\n\nvoid main() async {\n  final client = BillingClient(yourPurchaseListener);\n  await client.startConnection(onDisconnect: handleDisconnect);\n  _connected = true;\n\n  // ...fetch SKUDetails, launch billing flows, query purchase history, etc\n\n  await client.endConnection(); // Always call [endConnection] when work with this client is done.\n}\n\nvoid handleDisconnect() {\n  // Client disconnected. Make sure to call [startConnection] next time before invoking\n  // any other method of the client.\n  _connected = false;\n}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmemspace%2Fiap","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmemspace%2Fiap","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmemspace%2Fiap/lists"}