in Flutter apps. This plugin supports in-app purchases (IAP) through an underlying store, which can be the App Store (on iOS and macOS) or Google Play (on Android). • Features ◦ Use this plugin in your Flutter app to: ◦ Show in-app products that are available for sale from the underlying store. Products can include consumables, permanent upgrades, and subscriptions. ◦ Load in-app products that the user owns. ◦ Send the user to the underlying store to purchase products. ◦ Present a UI for redeeming subscription offer codes. (iOS 14 only) 20
Githubのサンプルコード if (Platform.isAndroid) { // NOTE: If you are making a subscription purchase/upgrade/downgrade, // we recommend you to verify the latest status of you your subscription // by using server side receipt validation and update the UI accordingly. // The subscription purchase status shown inside the app may not be accurate. final GooglePlayPurchaseDetails? oldSubscription = _getOldSubscription(productDetails, purchases);
Githubのサンプルコード if (Platform.isAndroid) { // NOTE: If you are making a subscription purchase/upgrade/downgrade, // we recommend you to verify the latest status of you your subscription // by using server side receipt validation and update the UI accordingly. // The subscription purchase status shown inside the app may not be accurate. final GooglePlayPurchaseDetails? oldSubscription = _getOldSubscription(productDetails, purchases); 要約: サーバー上で保持してそれを取得すべき
/// Google Play上の現在購入中アイテム情報 [GooglePlayPurchaseDetails]を取得保持 final iapGoogleOwnedPurchaseProvider = FutureProvider.autoDispose( (ref) async { if (!Platform.isAndroid) return null; final platformAddition = inAppPurchase.getPlatformAddition() as InAppPurchaseAndroidPlatformAddition; final response = await platformAddition.queryPastPurchases(); return response.pastPurchases.firstOrNull; }, );
Android専用なのでPlatformAddition経由 final platformAddition = inAppPurchase.getPlatformAddition() as InAppPurchaseAndroidPlatformAddition; final result = await platformAddition.consumePurchases( purchase: purchaseDetail, );
PurchaseDetails { final String? purchaseID; final String productID; final PurchaseVerificationData verificationData; final String? transactionDate; PurchaseStatus status; 59
that this [PurchaseDetails] is currently on. PurchaseStatus status; /// Status for a [PurchaseDetails]. enum PurchaseStatus { pending, purchased, error, restored, canceled, }
compleat: (flow) { switch (flow) { case InAppPurchaseFlow.purchase: /// or restore or planUpgrade /// 購入/復元/アップグレード表示 case InAppPurchaseFlow.planDowngrade: /// ダウングレード表示
the /// [`SKPaymentQueueDelegate`] (https://developer.apple.com/documentation/storekit/skpaymentqueuedelegate?language=objc). /// The payment queue delegate can be implemented to provide information needed to complete transactions. class ExamplePaymentQueueDelegate implements SKPaymentQueueDelegateWrapper { /// https://developer.apple.com/documentation/storekit/skpaymentqueuedelegate/3242935-paymentqueue @override bool shouldContinueTransaction( SKPaymentTransactionWrapper transaction, SKStorefrontWrapper storefront, ) => true; /// https://developer.apple.com/documentation/storekit/skpaymentqueue/3521327-showpriceconsentifneeded @override bool shouldShowPriceConsent() => false; } 99
the /// [`SKPaymentQueueDelegate`] (https://developer.apple.com/documentation/storekit/skpaymentqueuedelegate?language=objc). /// The payment queue delegate can be implemented to provide information needed to complete transactions. class ExamplePaymentQueueDelegate implements SKPaymentQueueDelegateWrapper { /// https://developer.apple.com/documentation/storekit/skpaymentqueuedelegate/3242935-paymentqueue @override bool shouldContinueTransaction( SKPaymentTransactionWrapper transaction, SKStorefrontWrapper storefront, ) => true; /// https://developer.apple.com/documentation/storekit/skpaymentqueue/3521327-showpriceconsentifneeded @override bool shouldShowPriceConsent() => false; } 100
platformAddition = inAppPurchase.getPlatformAddition() as InAppPurchaseStoreKitPlatformAddition; final verificationData = await platformAddition.refreshPurchaseVerificationData(); final receipt = verificationData?.serverVerificationData; 103
SKRequestMaker().startRefreshReceiptRequest(); try { final String receipt = await SKReceiptManager.retrieveReceiptData(); return PurchaseVerificationData( localVerificationData: receipt, serverVerificationData: receipt, source: kIAPSource); } catch (e) { print( 'Something is wrong while fetching the receipt, this normally happens when the app is ' 'running on a simulator: $e'); return null; } } 104
await SKRequestMaker().startRefreshReceiptRequest(); try { final String receipt = await SKReceiptManager.retrieveReceiptData(); return PurchaseVerificationData( localVerificationData: receipt, serverVerificationData: receipt, source: kIAPSource); } catch (e) { print( 'Something is wrong while fetching the receipt, this normally happens when the app is ' 'running on a simulator: $e'); return null; } } 105