CINXE.COM

in_app_purchase | Flutter package

<!DOCTYPE html> <html lang="en-us"><head><script src="https://www.googletagmanager.com/gtm.js?id=GTM-MX6DBN9" async="async"></script><script src="/static/hash-o6oemknr/js/gtm.js" async="async"></script><meta charset="utf-8"/><meta http-equiv="x-ua-compatible" content="ie=edge"/><meta name="viewport" content="width=device-width, initial-scale=1"/><meta name="twitter:card" content="summary"/><meta name="twitter:site" content="@dart_lang"/><meta name="twitter:description" content="A Flutter plugin for in-app purchases. Exposes APIs for making in-app purchases through the App Store and Google Play."/><meta name="twitter:image" content="https://pub.dev/static/hash-o6oemknr/img/pub-dev-icon-cover-image.png"/><meta property="og:type" content="website"/><meta property="og:site_name" content="Dart packages"/><meta property="og:title" content="in_app_purchase | Flutter package"/><meta property="og:description" content="A Flutter plugin for in-app purchases. Exposes APIs for making in-app purchases through the App Store and Google Play."/><meta property="og:image" content="https://pub.dev/static/hash-o6oemknr/img/pub-dev-icon-cover-image.png"/><meta property="og:url" content="https://pub.dev/packages/in_app_purchase"/><title>in_app_purchase | Flutter package</title><link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Google+Sans:wght@400;500;700&amp;family=Google+Sans+Display:wght@400&amp;family=Google+Sans+Text:wght@400;500;700&amp;family=Google+Sans+Mono:wght@400;700&amp;display=swap"/><link rel="shortcut icon" href="/static/hash-o6oemknr/img/flutter-logo-32x32.png"/><link rel="stylesheet" href="https://www.gstatic.com/glue/v25_0/ccb.min.css"/><link rel="search" type="application/opensearchdescription+xml" title="Dart packages" href="/osd.xml"/><link rel="canonical" href="https://pub.dev/packages/in_app_purchase"/><meta name="description" content="A Flutter plugin for in-app purchases. Exposes APIs for making in-app purchases through the App Store and Google Play."/><link rel="alternate" type="application/atom+xml" title="Updated Packages Feed for Pub" href="/feed.atom"/><link rel="stylesheet" type="text/css" href="/static/hash-o6oemknr/material/bundle/styles.css"/><link rel="stylesheet" type="text/css" href="/static/hash-o6oemknr/css/style.css"/><script src="/static/hash-o6oemknr/material/bundle/script.min.js" defer="defer"></script><script src="/static/hash-o6oemknr/js/script.dart.js" defer="defer"></script><script src="https://www.gstatic.com/brandstudio/kato/cookie_choice_component/cookie_consent_bar.v3.js" defer="defer" data-autoload-cookie-consent-bar="true"></script><meta name="pub-page-data" content="eyJwa2dEYXRhIjp7InBhY2thZ2UiOiJpbl9hcHBfcHVyY2hhc2UiLCJ2ZXJzaW9uIjoiMy4yLjAiLCJsaWtlcyI6MjE2OSwicHVibGlzaGVySWQiOiJmbHV0dGVyLmRldiIsImlzRGlzY29udGludWVkIjpmYWxzZSwiaXNMYXRlc3QiOnRydWV9LCJzZXNzaW9uQXdhcmUiOmZhbHNlfQ=="/><link rel="preload" href="/static/hash-o6oemknr/highlight/highlight-with-init.js" as="script"/></head><body class="light-theme"><script src="/static/hash-o6oemknr/js/dark-init.js"></script><noscript><iframe src="https://www.googletagmanager.com/ns.html?id=GTM-MX6DBN9" height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript><div class="site-header"><button class="hamburger" aria-label="menu toggle"></button><a class="logo" href="/"><img class="site-logo" src="/static/hash-o6oemknr/img/pub-dev-logo.svg" alt="" width="140" height="30" role="presentation"/></a><div class="site-header-space"></div><div class="site-header-mask"></div><div class="site-header-search"><form action="/packages" method="GET"><input class="site-header-search-input" name="q" placeholder="New search..." autocomplete="on" title="Search"/></form></div><nav class="site-header-nav scroll-container"><div class="nav-login-container"><button id="-account-login" class="nav-main-button link">Sign in</button></div><div class="nav-container nav-help-container hoverable"><button class="nav-main-button">Help</button><div class="nav-hover-popup"><div class="nav-table-columns"><div class="nav-table-column"><h3>Pub.dev</h3><a class="nav-link" href="/help/search" rel="noopener" target="_blank">Searching for packages</a><a class="nav-link" href="/help/scoring" rel="noopener" target="_blank">Package scoring and pub points</a></div><div class="nav-table-column"><h3>Flutter</h3><a class="nav-link" href="https://flutter.dev/using-packages/" rel="noopener" target="_blank">Using packages</a><a class="nav-link" href="https://flutter.dev/developing-packages/" rel="noopener" target="_blank">Developing packages and plugins</a><a class="nav-link" href="https://dart.dev/tools/pub/publishing" rel="noopener" target="_blank">Publishing a package</a></div><div class="nav-table-column"><h3>Dart</h3><a class="nav-link" href="https://dart.dev/guides/packages" rel="noopener" target="_blank">Using packages</a><a class="nav-link" href="https://dart.dev/tools/pub/publishing" rel="noopener" target="_blank">Publishing a package</a></div></div></div></div><div class="nav-container nav-help-container-mobile foldable"><h3 class="foldable-button">Pub.dev <img class="foldable-icon" src="/static/hash-o6oemknr/img/nav-mobile-foldable-icon.svg" alt="toggle folding of the section" width="13" height="6"/></h3><div class="foldable-content"><a class="nav-link" href="/help/search" rel="noopener" target="_blank">Searching for packages</a><a class="nav-link" href="/help/scoring" rel="noopener" target="_blank">Package scoring and pub points</a></div></div><div class="nav-container nav-help-container-mobile foldable"><h3 class="foldable-button">Flutter <img class="foldable-icon" src="/static/hash-o6oemknr/img/nav-mobile-foldable-icon.svg" alt="toggle folding of the section" width="13" height="6"/></h3><div class="foldable-content"><a class="nav-link" href="https://flutter.dev/using-packages/" rel="noopener" target="_blank">Using packages</a><a class="nav-link" href="https://flutter.dev/developing-packages/" rel="noopener" target="_blank">Developing packages and plugins</a><a class="nav-link" href="https://dart.dev/tools/pub/publishing" rel="noopener" target="_blank">Publishing a package</a></div></div><div class="nav-container nav-help-container-mobile foldable"><h3 class="foldable-button">Dart <img class="foldable-icon" src="/static/hash-o6oemknr/img/nav-mobile-foldable-icon.svg" alt="toggle folding of the section" width="13" height="6"/></h3><div class="foldable-content"><a class="nav-link" href="https://dart.dev/guides/packages" rel="noopener" target="_blank">Using packages</a><a class="nav-link" href="https://dart.dev/tools/pub/publishing" rel="noopener" target="_blank">Publishing a package</a></div></div></nav></div><div id="banner-container"></div><main class="container"><div class="detail-wrapper -active -has-info-box"><div class="detail-header -is-loose"><div class="detail-container"><div class="detail-header-outer-block"><div class="detail-header-content-block"><h1 class="title">in_app_purchase 3.2.0 <span class="pkg-page-title-copy"><img class="pkg-page-title-copy-icon filter-invert-on-dark" src="/static/hash-o6oemknr/img/content-copy-icon.svg" alt="copy &quot;in_app_purchase: ^3.2.0&quot; to clipboard" width="18" height="18" title="Copy &quot;in_app_purchase: ^3.2.0&quot; to clipboard" data-copy-content="in_app_purchase: ^3.2.0" data-ga-click-event="copy-package-version"/><div class="pkg-page-title-copy-feedback"><span class="code">in_app_purchase: ^3.2.0</span> copied to clipboard</div></span></h1><div class="metadata">Published <span><a class="-x-ago" href="" title="Apr 17, 2024" aria-label="7 months ago" aria-role="button" role="button" data-timestamp="1713386744000">7 months ago</a></span> • <a class="-pub-publisher" href="/publishers/flutter.dev"><img class="-pub-publisher-shield filter-invert-on-dark" src="/static/hash-o6oemknr/img/material-icon-verified.svg" alt="verified publisher" width="14" height="14" title="Published by a pub.dev verified publisher"/>flutter.dev</a><span class="package-badge" title="Package is compatible with Dart 3.">Dart 3 compatible</span></div><div class="detail-tags-and-like"><div class="detail-tags"><div class="-pub-tag-badge"><span class="tag-badge-main">SDK</span><a class="tag-badge-sub" href="/packages?q=sdk%3Aflutter" rel="nofollow" title="Packages compatible with Flutter SDK">Flutter</a></div><div class="-pub-tag-badge"><span class="tag-badge-main">Platform</span><a class="tag-badge-sub" href="/packages?q=platform%3Aandroid" rel="nofollow" title="Packages compatible with Android platform">Android</a><a class="tag-badge-sub" href="/packages?q=platform%3Aios" rel="nofollow" title="Packages compatible with iOS platform">iOS</a><a class="tag-badge-sub" href="/packages?q=platform%3Amacos" rel="nofollow" title="Packages compatible with macOS platform">macOS</a></div></div><div class="detail-like"><button id="-pub-like-icon-button" class="mdc-icon-button" data-ga-click-event="toggle-like" aria-pressed="false" title="Like this package"><img class="mdc-icon-button__icon" src="/static/hash-o6oemknr/img/like-inactive.svg" alt="liked status: inactive" width="18" height="18"/><img class="mdc-icon-button__icon mdc-icon-button__icon--on" src="/static/hash-o6oemknr/img/like-active.svg" alt="liked status: active" width="18" height="18"/></button><span class="likes-count"><span id="likes-count">2.1k</span></span></div></div></div></div></div></div><div class="detail-container"><div class="detail-lead"><div class="detail-metadata-toggle"><div class="detail-metadata-toggle-icon">→</div><h3 class="detail-lead-title">Metadata</h3></div><p class="detail-lead-text">A Flutter plugin for in-app purchases. Exposes APIs for making in-app purchases through the App Store and Google Play.</p><p class="detail-lead-more"><a class="detail-metadata-toggle">More...</a></p></div></div><div class="detail-body"><div class="detail-tabs"><div class="detail-tabs-wide-header"><div class="detail-container"><ul class="detail-tabs-header"><li class="detail-tab tab-button detail-tab-readme-title -active">Readme</li><li class="detail-tab tab-link detail-tab-changelog-title"><a href="/packages/in_app_purchase/changelog" role="button">Changelog</a></li><li class="detail-tab tab-link detail-tab-example-title"><a href="/packages/in_app_purchase/example" role="button">Example</a></li><li class="detail-tab tab-link detail-tab-installing-title"><a href="/packages/in_app_purchase/install" role="button">Installing</a></li><li class="detail-tab tab-link detail-tab-versions-title"><a href="/packages/in_app_purchase/versions" role="button">Versions</a></li><li class="detail-tab tab-link detail-tab-analysis-title"><a href="/packages/in_app_purchase/score" role="button">Scores</a></li></ul></div></div><div class="detail-container detail-body-main"><div class="detail-tabs-content"><section class="tab-content detail-tab-readme-content -active markdown-body"><p>A storefront-independent API for purchases in Flutter apps.</p> <!-- If this package were in its own repo, we'd put badges here --> <p>This plugin supports in-app purchases (<em>IAP</em>) through an <em>underlying store</em>, which can be the App Store (on iOS and macOS) or Google Play (on Android).</p> <table> <thead> <tr> <th></th> <th>Android</th> <th>iOS</th> <th>macOS</th> </tr> </thead> <tbody> <tr> <td><strong>Support</strong></td> <td>SDK 16+</td> <td>12.0+</td> <td>10.15+</td> </tr> </tbody> </table> <p> <img src="https://github.com/flutter/packages/blob/main/packages/in_app_purchase/in_app_purchase/doc/iap_ios.gif?raw=true" alt="An animated image of the iOS in-app purchase UI" height="400"> &nbsp;&nbsp;&nbsp;&nbsp; <img src="https://github.com/flutter/packages/blob/main/packages/in_app_purchase/in_app_purchase/doc/iap_android.gif?raw=true" alt="An animated image of the Android in-app purchase UI" height="400"> </p> <h2 class="hash-header" id="features">Features <a href="#features" class="hash-link">#</a></h2> <p>Use this plugin in your Flutter app to:</p> <ul> <li>Show in-app products that are available for sale from the underlying store. Products can include consumables, permanent upgrades, and subscriptions.</li> <li>Load in-app products that the user owns.</li> <li>Send the user to the underlying store to purchase products.</li> <li>Present a UI for redeeming subscription offer codes. (iOS 14 only)</li> </ul> <h2 class="hash-header" id="getting-started">Getting started <a href="#getting-started" class="hash-link">#</a></h2> <p>This plugin relies on the App Store and Google Play for making in-app purchases. It exposes a unified surface, but you still need to understand and configure your app with each store. Both stores have extensive guides:</p> <ul> <li><a href="https://developer.apple.com/in-app-purchase/" rel="ugc">App Store documentation</a></li> <li><a href="https://developer.android.com/google/play/billing/billing_overview" rel="ugc">Google Play documentation</a></li> </ul> <blockquote> <p>NOTE: Further in this document the App Store and Google Play will be referred to as "the store" or "the underlying store", except when a feature is specific to a particular store.</p> </blockquote> <p>For a list of steps for configuring in-app purchases in both stores, see the <a href="https://github.com/flutter/packages/blob/main/packages/in_app_purchase/in_app_purchase/example/README.md" rel="ugc">example app README</a>.</p> <p>Once you've configured your in-app purchases in their respective stores, you can start using the plugin. Two basic options are available:</p> <ol> <li> <p>A generic, idiomatic Flutter API: <a href="https://pub.dev/documentation/in_app_purchase/latest/in_app_purchase/in_app_purchase-library.html">in_app_purchase</a>. This API supports most use cases for loading and making purchases.</p> </li> <li> <p>Platform-specific Dart APIs: <a href="https://pub.dev/documentation/in_app_purchase_storekit/latest/store_kit_wrappers/store_kit_wrappers-library.html">store_kit_wrappers</a> and <a href="https://pub.dev/documentation/in_app_purchase_android/latest/billing_client_wrappers/billing_client_wrappers-library.html">billing_client_wrappers</a>. These APIs expose platform-specific behavior and allow for more fine-tuned control when needed. However, if you use one of these APIs, your purchase-handling logic is significantly different for the different storefronts.</p> </li> </ol> <p>See also the codelab for <a href="https://codelabs.developers.google.com/codelabs/flutter-in-app-purchases" rel="ugc">in-app purchases in Flutter</a> for a detailed guide on adding in-app purchase support to a Flutter App.</p> <h2 class="hash-header" id="usage">Usage <a href="#usage" class="hash-link">#</a></h2> <p>This section has examples of code for the following tasks:</p> <ul> <li><a href="#listening-to-purchase-updates">Listening to purchase updates</a></li> <li><a href="#connecting-to-the-underlying-store">Connecting to the underlying store</a></li> <li><a href="#loading-products-for-sale">Loading products for sale</a></li> <li><a href="#restoring-previous-purchases">Restoring previous purchases</a></li> <li><a href="#making-a-purchase">Making a purchase</a></li> <li><a href="#completing-a-purchase">Completing a purchase</a></li> <li><a href="#upgrading-or-downgrading-an-existing-in-app-subscription">Upgrading or downgrading an existing in-app subscription</a></li> <li><a href="#accessing-platform-specific-product-or-purchase-properties">Accessing platform specific product or purchase properties</a></li> <li><a href="#presenting-a-code-redemption-sheet-ios-14">Presenting a code redemption sheet (iOS 14)</a></li> </ul> <p><strong>Note:</strong> It is not necessary to depend on <code>com.android.billingclient:billing</code> in your own app's <code>android/app/build.gradle</code> file. If you choose to do so know that conflicts might occur.</p> <h3 class="hash-header" id="listening-to-purchase-updates">Listening to purchase updates <a href="#listening-to-purchase-updates" class="hash-link">#</a></h3> <p>In your app's <code>initState</code> method, subscribe to any incoming purchases. These can propagate from either underlying store. You should always start listening to purchase update as early as possible to be able to catch all purchase updates, including the ones from the previous app session. To listen to the update:</p> <pre><code class="language-dart">class _MyAppState extends State&lt;MyApp&gt; { StreamSubscription&lt;List&lt;PurchaseDetails&gt;&gt; _subscription; @override void initState() { final Stream purchaseUpdated = InAppPurchase.instance.purchaseStream; _subscription = purchaseUpdated.listen((purchaseDetailsList) { _listenToPurchaseUpdated(purchaseDetailsList); }, onDone: () { _subscription.cancel(); }, onError: (error) { // handle error here. }); super.initState(); } @override void dispose() { _subscription.cancel(); super.dispose(); } </code></pre> <p>Here is an example of how to handle purchase updates:</p> <pre><code class="language-dart">void _listenToPurchaseUpdated(List&lt;PurchaseDetails&gt; purchaseDetailsList) { purchaseDetailsList.forEach((PurchaseDetails purchaseDetails) async { if (purchaseDetails.status == PurchaseStatus.pending) { _showPendingUI(); } else { if (purchaseDetails.status == PurchaseStatus.error) { _handleError(purchaseDetails.error!); } else if (purchaseDetails.status == PurchaseStatus.purchased || purchaseDetails.status == PurchaseStatus.restored) { bool valid = await _verifyPurchase(purchaseDetails); if (valid) { _deliverProduct(purchaseDetails); } else { _handleInvalidPurchase(purchaseDetails); } } if (purchaseDetails.pendingCompletePurchase) { await InAppPurchase.instance .completePurchase(purchaseDetails); } } }); } </code></pre> <h3 class="hash-header" id="connecting-to-the-underlying-store">Connecting to the underlying store <a href="#connecting-to-the-underlying-store" class="hash-link">#</a></h3> <pre><code class="language-dart">final bool available = await InAppPurchase.instance.isAvailable(); if (!available) { // The store cannot be reached or accessed. Update the UI accordingly. } </code></pre> <h3 class="hash-header" id="loading-products-for-sale">Loading products for sale <a href="#loading-products-for-sale" class="hash-link">#</a></h3> <pre><code class="language-dart">// Set literals require Dart 2.2. Alternatively, use // `Set&lt;String&gt; _kIds = &lt;String&gt;['product1', 'product2'].toSet()`. const Set&lt;String&gt; _kIds = &lt;String&gt;{'product1', 'product2'}; final ProductDetailsResponse response = await InAppPurchase.instance.queryProductDetails(_kIds); if (response.notFoundIDs.isNotEmpty) { // Handle the error. } List&lt;ProductDetails&gt; products = response.productDetails; </code></pre> <h3 class="hash-header" id="restoring-previous-purchases">Restoring previous purchases <a href="#restoring-previous-purchases" class="hash-link">#</a></h3> <p>Restored purchases will be emitted on the <code>InAppPurchase.purchaseStream</code>, make sure to validate restored purchases following the best practices for each underlying store:</p> <ul> <li><a href="https://developer.apple.com/documentation/storekit/in-app_purchase/validating_receipts_with_the_app_store" rel="ugc">Verifying App Store purchases</a></li> <li><a href="https://developer.android.com/google/play/billing/security#verify" rel="ugc">Verifying Google Play purchases</a></li> </ul> <pre><code class="language-dart">await InAppPurchase.instance.restorePurchases(); </code></pre> <p>Note that the App Store does not have any APIs for querying consumable products, and Google Play considers consumable 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.</p> <h3 class="hash-header" id="making-a-purchase">Making a purchase <a href="#making-a-purchase" class="hash-link">#</a></h3> <p>Both underlying stores handle consumable and non-consumable products differently. If you're using <code>InAppPurchase</code>, you need to make a distinction here and call the right purchase method for each type.</p> <pre><code class="language-dart">final ProductDetails productDetails = ... // Saved earlier from queryProductDetails(). final PurchaseParam purchaseParam = PurchaseParam(productDetails: productDetails); if (_isConsumable(productDetails)) { InAppPurchase.instance.buyConsumable(purchaseParam: purchaseParam); } else { InAppPurchase.instance.buyNonConsumable(purchaseParam: purchaseParam); } // From here the purchase flow will be handled by the underlying store. // Updates will be delivered to the `InAppPurchase.instance.purchaseStream`. </code></pre> <h3 class="hash-header" id="completing-a-purchase">Completing a purchase <a href="#completing-a-purchase" class="hash-link">#</a></h3> <p>The <code>InAppPurchase.purchaseStream</code> will send purchase updates after initiating the purchase flow using <code>InAppPurchase.buyConsumable</code> or <code>InAppPurchase.buyNonConsumable</code>. After verifying the purchase receipt and the delivering the content to the user it is important to call <code>InAppPurchase.completePurchase</code> to tell the underlying store that the purchase has been completed. Calling <code>InAppPurchase.completePurchase</code> will inform the underlying store that the app verified and processed the purchase and the store can proceed to finalize the transaction and bill the end user's payment account.</p> <blockquote> <p><strong>Warning:</strong> Failure to call <code>InAppPurchase.completePurchase</code> and get a successful response within 3 days of the purchase will result a refund.</p> </blockquote> <h3 class="hash-header" id="upgrading-or-downgrading-an-existing-in-app-subscription">Upgrading or downgrading an existing in-app subscription <a href="#upgrading-or-downgrading-an-existing-in-app-subscription" class="hash-link">#</a></h3> <p>To upgrade/downgrade an existing in-app subscription in Google Play, you need to provide an instance of <code>ChangeSubscriptionParam</code> with the old <code>PurchaseDetails</code> that the user needs to migrate from, and an optional <code>ProrationMode</code> with the <code>GooglePlayPurchaseParam</code> object while calling <code>InAppPurchase.buyNonConsumable</code>.</p> <p>The App Store does not require this because it provides a subscription grouping mechanism. Each subscription you offer must be assigned to a subscription group. Grouping related subscriptions together can help prevent users from accidentally purchasing multiple subscriptions. Refer to the <a href="https://developer.apple.com/app-store/subscriptions/#groups" rel="ugc">Creating a Subscription Group</a> section of <a href="https://developer.apple.com/app-store/subscriptions/" rel="ugc">Apple's subscription guide</a>.</p> <pre><code class="language-dart">final PurchaseDetails oldPurchaseDetails = ...; PurchaseParam purchaseParam = GooglePlayPurchaseParam( productDetails: productDetails, changeSubscriptionParam: ChangeSubscriptionParam( oldPurchaseDetails: oldPurchaseDetails, prorationMode: ProrationMode.immediateWithTimeProration)); InAppPurchase.instance .buyNonConsumable(purchaseParam: purchaseParam); </code></pre> <h3 class="hash-header" id="confirming-subscription-price-changes">Confirming subscription price changes <a href="#confirming-subscription-price-changes" class="hash-link">#</a></h3> <p>When the price of a subscription is changed the consumer will need to confirm that price change. If the consumer does not confirm the price change the subscription will not be auto-renewed. By default on both iOS and Android the consumer will automatically get a popup to confirm the price change. Depending on the platform there are different ways to interact with this flow as explained in the following paragraphs.</p> <h4 id="google-play-store-android">Google Play Store (Android)</h4> <p>When changing the price of an existing subscription base plan or offer, existing subscribers are placed in a legacy price cohort. App developers can choose to <a href="https://developer.android.com/google/play/billing/price-changes#end-legacy" rel="ugc">end a legacy price cohort</a> and move subscribers into the current base plan price. When the new subscription base plan price is lower, Google will notify the consumer via email and notifications. The consumer will start paying the lower price next time they pay for their base plan. When the subscription price is raised, Google will automatically start notifying consumers through email and notifications 7 days after the legacy price cohort was ended. It is highly recommended to give consumers advanced notice of the price change and provide a deep link to the Play Store subscription screen to help them review the price change. The official documentation can be found <a href="https://developer.android.com/google/play/billing/price-changes" rel="ugc">here</a>.</p> <h4 id="apple-app-store-ios">Apple App Store (iOS)</h4> <p>When the price of a subscription is raised iOS will also show a popup in the app. The StoreKit Payment Queue will notify the app that it wants to show a price change confirmation popup. By default the queue will get the response that it can continue and show the popup. However, it is possible to prevent this popup via the 'InAppPurchaseStoreKitPlatformAddition' and show the popup at a different time, for example after clicking a button.</p> <p>To know when the App Store wants to show a popup and prevent this from happening a queue delegate can be registered. The <code>InAppPurchaseStoreKitPlatformAddition</code> contains a <code>setDelegate(SKPaymentQueueDelegateWrapper? delegate)</code> function that can be used to set a delegate or remove one by setting it to <code>null</code>.</p> <pre><code class="language-dart">//import for InAppPurchaseStoreKitPlatformAddition import 'package:in_app_purchase_storekit/in_app_purchase_storekit.dart'; Future&lt;void&gt; initStoreInfo() async { if (Platform.isIOS) { var iosPlatformAddition = _inAppPurchase .getPlatformAddition&lt;InAppPurchaseStoreKitPlatformAddition&gt;(); await iosPlatformAddition.setDelegate(ExamplePaymentQueueDelegate()); } } @override Future&lt;void&gt; disposeStore() { if (Platform.isIOS) { var iosPlatformAddition = _inAppPurchase .getPlatformAddition&lt;InAppPurchaseStoreKitPlatformAddition&gt;(); await iosPlatformAddition.setDelegate(null); } } </code></pre> <p>The delegate that is set should implement <code>SKPaymentQueueDelegateWrapper</code> and handle <code>shouldContinueTransaction</code> and <code>shouldShowPriceConsent</code>. When setting <code>shouldShowPriceConsent</code> to false the default popup will not be shown and the app needs to show this later.</p> <pre><code class="language-dart">// import for SKPaymentQueueDelegateWrapper import 'package:in_app_purchase_storekit/store_kit_wrappers.dart'; class ExamplePaymentQueueDelegate implements SKPaymentQueueDelegateWrapper { @override bool shouldContinueTransaction( SKPaymentTransactionWrapper transaction, SKStorefrontWrapper storefront) { return true; } @override bool shouldShowPriceConsent() { return false; } } </code></pre> <p>The dialog can be shown by calling <code>showPriceConsentIfNeeded</code> on the <code>InAppPurchaseStoreKitPlatformAddition</code>. This future will complete immediately when the dialog is shown. A confirmed transaction will be delivered on the <code>purchaseStream</code>.</p> <pre><code class="language-dart">if (Platform.isIOS) { var iapStoreKitPlatformAddition = _inAppPurchase .getPlatformAddition&lt;InAppPurchaseStoreKitPlatformAddition&gt;(); await iapStoreKitPlatformAddition.showPriceConsentIfNeeded(); } </code></pre> <h3 class="hash-header" id="accessing-platform-specific-product-or-purchase-properties">Accessing platform specific product or purchase properties <a href="#accessing-platform-specific-product-or-purchase-properties" class="hash-link">#</a></h3> <p>The function <code>_inAppPurchase.queryProductDetails(productIds);</code> provides a <code>ProductDetailsResponse</code> with a list of purchasable products of type <code>List&lt;ProductDetails&gt;</code>. This <code>ProductDetails</code> class is a platform independent class containing properties only available on all endorsed platforms. However, in some cases it is necessary to access platform specific properties. The <code>ProductDetails</code> instance is of subtype <code>GooglePlayProductDetails</code> when the platform is Android and <code>AppStoreProductDetails</code> on iOS. Accessing the skuDetails (on Android) or the skProduct (on iOS) provides all the information that is available in the original platform objects.</p> <p>This is an example on how to get the <code>introductoryPricePeriod</code> on Android:</p> <pre><code class="language-dart">//import for GooglePlayProductDetails import 'package:in_app_purchase_android/in_app_purchase_android.dart'; //import for SkuDetailsWrapper import 'package:in_app_purchase_android/billing_client_wrappers.dart'; if (productDetails is GooglePlayProductDetails) { SkuDetailsWrapper skuDetails = (productDetails as GooglePlayProductDetails).skuDetails; print(skuDetails.introductoryPricePeriod); } </code></pre> <p>And this is the way to get the subscriptionGroupIdentifier of a subscription on iOS:</p> <pre><code class="language-dart">//import for AppStoreProductDetails import 'package:in_app_purchase_storekit/in_app_purchase_storekit.dart'; //import for SKProductWrapper import 'package:in_app_purchase_storekit/store_kit_wrappers.dart'; if (productDetails is AppStoreProductDetails) { SKProductWrapper skProduct = (productDetails as AppStoreProductDetails).skProduct; print(skProduct.subscriptionGroupIdentifier); } </code></pre> <p>The <code>purchaseStream</code> provides objects of type <code>PurchaseDetails</code>. PurchaseDetails' provides all information that is available on all endorsed platforms, such as purchaseID and transactionDate. In addition, it is possible to access the platform specific properties. The <code>PurchaseDetails</code> object is of subtype <code>GooglePlayPurchaseDetails</code> when the platform is Android and <code>AppStorePurchaseDetails</code> on iOS. Accessing the billingClientPurchase, resp. skPaymentTransaction provides all the information that is available in the original platform objects.</p> <p>This is an example on how to get the <code>originalJson</code> on Android:</p> <pre><code class="language-dart">//import for GooglePlayPurchaseDetails import 'package:in_app_purchase_android/in_app_purchase_android.dart'; //import for PurchaseWrapper import 'package:in_app_purchase_android/billing_client_wrappers.dart'; if (purchaseDetails is GooglePlayPurchaseDetails) { PurchaseWrapper billingClientPurchase = (purchaseDetails as GooglePlayPurchaseDetails).billingClientPurchase; print(billingClientPurchase.originalJson); } </code></pre> <p>How to get the <code>transactionState</code> of a purchase in iOS:</p> <pre><code class="language-dart">//import for AppStorePurchaseDetails import 'package:in_app_purchase_storekit/in_app_purchase_storekit.dart'; //import for SKProductWrapper import 'package:in_app_purchase_storekit/store_kit_wrappers.dart'; if (purchaseDetails is AppStorePurchaseDetails) { SKPaymentTransactionWrapper skProduct = (purchaseDetails as AppStorePurchaseDetails).skPaymentTransaction; print(skProduct.transactionState); } </code></pre> <p>Please note that it is required to import <code>in_app_purchase_android</code> and/or <code>in_app_purchase_storekit</code>.</p> <h3 class="hash-header" id="presenting-a-code-redemption-sheet-ios-14">Presenting a code redemption sheet (iOS 14) <a href="#presenting-a-code-redemption-sheet-ios-14" class="hash-link">#</a></h3> <p>The following code brings up a sheet that enables the user to redeem offer codes that you've set up in App Store Connect. For more information on redeeming offer codes, see <a href="https://developer.apple.com/documentation/storekit/in-app_purchase/subscriptions_and_offers/implementing_offer_codes_in_your_app" rel="ugc">Implementing Offer Codes in Your App</a>.</p> <pre><code class="language-dart">InAppPurchaseStoreKitPlatformAddition iosPlatformAddition = InAppPurchase.getPlatformAddition&lt;InAppPurchaseStoreKitPlatformAddition&gt;(); iosPlatformAddition.presentCodeRedemptionSheet(); </code></pre> <blockquote> <p><strong>note:</strong> The <code>InAppPurchaseStoreKitPlatformAddition</code> is defined in the <code>in_app_purchase_storekit.dart</code> file so you need to import it into the file you will be using <code>InAppPurchaseStoreKitPlatformAddition</code>:</p> <pre><code class="language-dart">import 'package:in_app_purchase_storekit/in_app_purchase_storekit.dart'; </code></pre> </blockquote> <h2 class="hash-header" id="contributing-to-this-plugin">Contributing to this plugin <a href="#contributing-to-this-plugin" class="hash-link">#</a></h2> <p>If you would like to contribute to the plugin, check out our <a href="https://github.com/flutter/packages/blob/main/CONTRIBUTING.md" rel="ugc">contribution guide</a>.</p> </section></div></div></div><aside class="detail-info-box"><a class="packages-scores" href="/packages/in_app_purchase/score"><div class="packages-score packages-score-like"><div class="packages-score-value -has-value"><span class="packages-score-value-number">2169</span><span class="packages-score-value-sign"></span></div><div class="packages-score-label">likes</div></div><div class="packages-score packages-score-health"><div class="packages-score-value -has-value"><span class="packages-score-value-number">160</span><span class="packages-score-value-sign"></span></div><div class="packages-score-label">pub points</div></div><div class="packages-score packages-score-popularity"><div class="packages-score-value -has-value"><span class="packages-score-value-number">99</span><span class="packages-score-value-sign">%</span></div><div class="packages-score-label">popularity</div></div></a><div class="detail-screenshot-thumbnail"><div class="thumbnail-container" data-thumbnail="/packages/in_app_purchase/versions/3.2.0/gen-res/gen/iap_ios.webp,/packages/in_app_purchase/versions/3.2.0/gen-res/gen/iap_android.webp" data-thumbnail-descriptions-json="[&quot;Example of in-app purchase on ios&quot;,&quot;Example of in-app purchase on android&quot;]" data-ga-click-event="screenshot-thumbnail-click"><img class="thumbnail-image" src="/packages/in_app_purchase/versions/3.2.0/gen-res/gen/190x190/iap_ios.webp" alt="screenshot" title="View screenshots" tabindex="0"/></div><img class="collections-icon" src="/static/hash-o6oemknr/img/collections_white_24dp.svg" alt="" width="30" height="30" role="presentation"/></div><h3 class="title">Publisher</h3><p><a href="/publishers/flutter.dev"><img class="-pub-publisher-shield filter-invert-on-dark" src="/static/hash-o6oemknr/img/material-icon-verified.svg" alt="verified publisher" width="14" height="14" title="Published by a pub.dev verified publisher"/>flutter.dev</a></p><h3 class="title pkg-infobox-metadata">Metadata</h3><p>A Flutter plugin for in-app purchases. Exposes APIs for making in-app purchases through the App Store and Google Play.</p><p><a class="link" href="https://github.com/flutter/packages/tree/main/packages/in_app_purchase/in_app_purchase" rel="ugc">Repository (GitHub)</a><br/><a class="link" href="https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+in_app_purchase%22" rel="ugc">View&#47;report issues</a><br/><a class="link" href="https://github.com/flutter/packages/blob/main/CONTRIBUTING.md" rel="ugc">Contributing</a><br/></p><h3 class="title">Topics</h3><p><a href="/packages?q=topic%3Ain-app-purchase" rel="nofollow">#in-app-purchase</a> <a href="/packages?q=topic%3Apayment" rel="nofollow">#payment</a></p><h3 class="title">Documentation</h3><p><a class="link" href="/documentation/in_app_purchase/latest/">API reference</a><br/></p><h3 class="title">License</h3><p><img class="inline-icon-img filter-invert-on-dark" src="/static/hash-o6oemknr/img/material-icon-balance.svg" alt="" width="14" height="14" role="presentation"/>BSD-3-Clause (<a href="/packages/in_app_purchase/license">license</a>)</p><h3 class="title">Dependencies</h3><p><a href="https://api.flutter.dev/">flutter</a>, <a href="/packages/in_app_purchase_android" title="^0.3.4">in_app_purchase_android</a>, <a href="/packages/in_app_purchase_platform_interface" title="^1.4.0">in_app_purchase_platform_interface</a>, <a href="/packages/in_app_purchase_storekit" title="^0.3.14">in_app_purchase_storekit</a></p><h3 class="title">More</h3><p><a href="/packages?q=dependency%3Ain_app_purchase" rel="nofollow">Packages that depend on in_app_purchase</a></p></aside></div><script type="application/ld+json">{"@context":"http\u003a\u002f\u002fschema.org","@type":"SoftwareSourceCode","name":"in\u005fapp\u005fpurchase","version":"3.2.0","description":"in\u005fapp\u005fpurchase - A Flutter plugin for in-app purchases. Exposes APIs for making in-app purchases through the App Store and Google Play.","url":"https\u003a\u002f\u002fpub.dev\u002fpackages\u002fin\u005fapp\u005fpurchase","dateCreated":"2018-11-27T22\u003a48\u003a42.713970Z","dateModified":"2024-04-17T20\u003a45\u003a44.000743Z","programmingLanguage":"Dart","image":"https\u003a\u002f\u002fpub.dev\u002fstatic\u002fimg\u002fpub-dev-icon-cover-image.png","license":"https\u003a\u002f\u002fpub.dev\u002fpackages\u002fin\u005fapp\u005fpurchase\u002flicense"}</script></div><div class="detail-metadata"><h3 class="detail-metadata-title"><span class="detail-metadata-toggle">←</span> Metadata</h3><div class="detail-info-box"><a class="packages-scores" href="/packages/in_app_purchase/score"><div class="packages-score packages-score-like"><div class="packages-score-value -has-value"><span class="packages-score-value-number">2169</span><span class="packages-score-value-sign"></span></div><div class="packages-score-label">likes</div></div><div class="packages-score packages-score-health"><div class="packages-score-value -has-value"><span class="packages-score-value-number">160</span><span class="packages-score-value-sign"></span></div><div class="packages-score-label">pub points</div></div><div class="packages-score packages-score-popularity"><div class="packages-score-value -has-value"><span class="packages-score-value-number">99</span><span class="packages-score-value-sign">%</span></div><div class="packages-score-label">popularity</div></div></a><div class="detail-screenshot-thumbnail"><div class="thumbnail-container" data-thumbnail="/packages/in_app_purchase/versions/3.2.0/gen-res/gen/iap_ios.webp,/packages/in_app_purchase/versions/3.2.0/gen-res/gen/iap_android.webp" data-thumbnail-descriptions-json="[&quot;Example of in-app purchase on ios&quot;,&quot;Example of in-app purchase on android&quot;]" data-ga-click-event="screenshot-thumbnail-click"><img class="thumbnail-image" src="/packages/in_app_purchase/versions/3.2.0/gen-res/gen/190x190/iap_ios.webp" alt="screenshot" title="View screenshots" tabindex="0"/></div><img class="collections-icon" src="/static/hash-o6oemknr/img/collections_white_24dp.svg" alt="" width="30" height="30" role="presentation"/></div><h3 class="title">Publisher</h3><p><a href="/publishers/flutter.dev"><img class="-pub-publisher-shield filter-invert-on-dark" src="/static/hash-o6oemknr/img/material-icon-verified.svg" alt="verified publisher" width="14" height="14" title="Published by a pub.dev verified publisher"/>flutter.dev</a></p><h3 class="title pkg-infobox-metadata">Metadata</h3><p>A Flutter plugin for in-app purchases. Exposes APIs for making in-app purchases through the App Store and Google Play.</p><p><a class="link" href="https://github.com/flutter/packages/tree/main/packages/in_app_purchase/in_app_purchase" rel="ugc">Repository (GitHub)</a><br/><a class="link" href="https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+in_app_purchase%22" rel="ugc">View&#47;report issues</a><br/><a class="link" href="https://github.com/flutter/packages/blob/main/CONTRIBUTING.md" rel="ugc">Contributing</a><br/></p><h3 class="title">Topics</h3><p><a href="/packages?q=topic%3Ain-app-purchase" rel="nofollow">#in-app-purchase</a> <a href="/packages?q=topic%3Apayment" rel="nofollow">#payment</a></p><h3 class="title">Documentation</h3><p><a class="link" href="/documentation/in_app_purchase/latest/">API reference</a><br/></p><h3 class="title">License</h3><p><img class="inline-icon-img filter-invert-on-dark" src="/static/hash-o6oemknr/img/material-icon-balance.svg" alt="" width="14" height="14" role="presentation"/>BSD-3-Clause (<a href="/packages/in_app_purchase/license">license</a>)</p><h3 class="title">Dependencies</h3><p><a href="https://api.flutter.dev/">flutter</a>, <a href="/packages/in_app_purchase_android" title="^0.3.4">in_app_purchase_android</a>, <a href="/packages/in_app_purchase_platform_interface" title="^1.4.0">in_app_purchase_platform_interface</a>, <a href="/packages/in_app_purchase_storekit" title="^0.3.14">in_app_purchase_storekit</a></p><h3 class="title">More</h3><p><a href="/packages?q=dependency%3Ain_app_purchase" rel="nofollow">Packages that depend on in_app_purchase</a></p></div><p class="detail-lead-back"><a class="detail-metadata-toggle">Back</a></p></div><div id="-screenshot-carousel" class="carousel"><fab id="-carousel-prev" class="mdc-fab carousel-prev carousel-nav" data-mdc-auto-init="MDCRipple" title="Previous" data-ga-click-event="screenshot-carousel-prev-click" tabindex="0"><div class="mdc-fab__ripple"></div><img class="mdc-fab__icon" src="/static/hash-o6oemknr/img/keyboard_arrow_left.svg" alt="previous" width="24" height="24" aria-hidden="true"/></fab><div id="-image-container" class="image-container"></div><fab id="-carousel-next" class="mdc-fab carousel-next carousel-nav" data-mdc-auto-init="MDCRipple" title="Next" data-ga-click-event="screenshot-carousel-next-click" tabindex="0"><div class="mdc-fab__ripple"></div><img class="mdc-fab__icon" src="/static/hash-o6oemknr/img/keyboard_arrow_right.svg" alt="next" width="24" height="24" aria-hidden="true"/></fab><p id="-screenshot-description" class="screenshot-description"></p></div></main><footer class="site-footer"><a class="link" href="https://dart.dev/">Dart language</a><a class="link sep" href="/report?subject=package%3Ain_app_purchase&amp;url=https%3A%2F%2Fpub.dev%2Fpackages%2Fin_app_purchase">Report package</a><a class="link sep" href="/policy">Policy</a><a class="link sep" href="https://www.google.com/intl/en/policies/terms/">Terms</a><a class="link sep" href="https://developers.google.com/terms/">API Terms</a><a class="link sep" href="/security">Security</a><a class="link sep" href="https://www.google.com/intl/en/policies/privacy/">Privacy</a><a class="link sep" href="/help">Help</a><a class="link icon sep" href="/feed.atom"><img class="inline-icon" src="/static/hash-o6oemknr/img/rss-feed-icon.svg" alt="RSS" width="20" height="20" title="RSS/atom feed"/></a><a class="link icon github_issue" href="https://github.com/dart-lang/pub-dev/issues/new"><img class="inline-icon" src="/static/hash-o6oemknr/img/bug-report-white-96px.png" alt="bug report" width="20" height="20" title="Report an issue with this site"/></a></footer><script src="/static/hash-o6oemknr/highlight/highlight-with-init.js" defer="defer"></script></body></html>

Pages: 1 2 3 4 5 6 7 8 9 10