サブスクの課金機能を実装予定として、調査しています。
単回課金も大きな違いはなく、実装できると思われます。
各ストアにサブスクアイテムの作成・登録
購入履歴のチェック用サーバーの設定
AppStore(iOS)とGooglePlayConsole(Android)で、それぞれ購入品を登録する必要があります。
AppStoreは、課金アイテムにも審査があります。
iOSの課金テストには、実機が必要です。
アンドロイドの場合は、アルファもしくはベータにバイナリ(アプリのデータ)をGoogle Play Consoleにアップロードして審査を通過してからでないと、課金のテストができません。
AppStore(iOS)とGooglePlayConsole(Android)の操作については、
こちらのドキュメントが参考になると思われます。
https://www.revenuecat.com/docs/ios-products
https://www.revenuecat.com/docs/android-products
アプリ側の実装としては、購入可能な課金アイテムのIdのSetが必要になります。
これをハードコーディングするのか、課金アイテムは変動するので、API経由でIdの配列を返す形で実装するのかは、決めていただく必要があると思います。
アプリ側の実装は下記の流れで実装します。
課金アイテムのIDのSetを引数に渡して、ProductDetailsのListを取得します。
const Set<String> _kIds = <String>['product1', 'product2'].toSet();
final ProductDetailsResponse response =
await InAppPurchase.instance.queryProductDetails(_kIds);
if (response.notFoundIDs.isNotEmpty) {
// Handle the error.
}
final List<ProductDetails> products = response.productDetails;
購入するアイテムのProductDetailsを引数に渡して、購入処理を行います。
final PurchaseParam purchaseParam = PurchaseParam(productDetails: productDetails);
if (_isConsumable(productDetails)) {
InAppPurchase.instance.buyConsumable(purchaseParam: purchaseParam);
} else {
InAppPurchase.instance.buyNonConsumable(purchaseParam: purchaseParam);
}
ユーザーの購入処理の状況を監視し、購入処理が完了した時点でレシートを検証APIに渡します。
@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();
}
void _listenToPurchaseUpdated(List<PurchaseDetails> 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) {
// レシートの検証
final bool valid = await _verifyPurchase(purchaseDetails);
if (valid) {
_deliverProduct(purchaseDetails);
} else {
_handleInvalidPurchase(purchaseDetails);
}
}
if (purchaseDetails.pendingCompletePurchase) {
await InAppPurchase.instance
.completePurchase(purchaseDetails);
}
}
});
}
iOSでは、上記に加えてStoreKitと連携するための処理を追加する必要があります。
if (Platform.isIOS) {
final InAppPurchaseStoreKitPlatformAddition iosPlatformAddition =
_inAppPurchase
.getPlatformAddition<InAppPurchaseStoreKitPlatformAddition>();
await iosPlatformAddition.setDelegate(ExamplePaymentQueueDelegate());
}
@override
void dispose() {
if (Platform.isIOS) {
final InAppPurchaseStoreKitPlatformAddition iosPlatformAddition =
_inAppPurchase
.getPlatformAddition<InAppPurchaseStoreKitPlatformAddition>();
iosPlatformAddition.setDelegate(null);
}
_subscription.cancel();
super.dispose();
}
アプリ内課金のSaasでRevenueCatというサービスがあります。
こちらは、バックエンドで行うレシートの検証を代行してくれるサービスになります。
料金体型はこちらです。https://www.revenuecat.com/pricing/
https://qiita.com/YuKiO-OO/items/a0fe8e0a256afbb69fc7
Flutter公式パッケージ:https://pub.dev/packages/in_app_purchase
RevenueCatのパッケージ:https://pub.dev/packages/purchases_flutter
https://zenn.dev/moga/books/flutter_revenuecat/viewer/2-about-revenuecat