Flutter(Android) 定期購入詳細なテスト

前提

キャンセルしても有効期限までは使える

Integrate the Google Play Billing Library into your app

払った分のお金を日割りで返すわけじゃないので、正しいと言える。

日割りで返す場合はどうすればいいのか?今回の要件にはないからとりあえずは考えない。

価格がいきなり変更になったらどうするのか?アイテムが増えたら?

価格変更でpurchaseStreamが動いてる様子はなし

価格を変更するときにplay consoleで表示される

f:id:ta_watanabe:20210805142746p:plain

細かいステータスの変更はpub/subで通知されるようです

https://developer.android.com/google/play/billing/rtdn-reference

既存システムとの連携での懸念

今回の要件で、既存システムの会員はそのシステムのID, passを使ってログインできるというのがあるのですが、 既存のシステムで使ってるメールアドレスでAndroidにログインしたくない人もいそう。。。

verifyPurchaseが実行される前にhandlePlayStoreServerEventが実行されることがある

初回登録時は必ずそうなります。

予想ですが、購入ボタンでbuyNonConsumable()するときに、 handlePlayStoreServerEventに通知が行き、purchaseStreamが動き出してverifyが実行されているような気がします。

で、handlePlayStoreServerEventはverifyした直後にまた通知(pub/sub)がいくので問題ないようです。

また、

play-billing-samples/TvMainActivity.kt at f9ae2d55c3699474e26ca0185a5ff38afb9df153 · android/play-billing-samples · GitHub

Google Play Billing Library をアプリに統合する  |  Google Play の課金システム

この辺りの実装を見ても、listenerにverifyするための処理を登録している(or する)ようなので、 同じ結果になりそう。

ストアからの再度定期購入

定期購入を販売する  |  Google Play の課金システム  |  Android Developers

「アプリ外での購入と見なされる」のでかなり厄介

この場合は、アプリを開かないと、verifyができない(= purchaseStreamが動かない)のでfirestoreのdocumentは作られません。 それでも、その間ユーザには定期購入が続きます。

ただ、ユーザは明示的に再度定期購入ボタンを押しているので、 問題なさそうですが、これを人に説明するのが厄介そう。

そして、本当はこの場合は、 https://developer.android.com/google/play/billing/integrate?hl=ja#fetch で書かれている通り、queryPurchasesAsync()を実行するみたいですが、 v4から追加されたメソッドになるようで、

https://developer.android.com/google/play/billing/release-notes?hl=ja#4-0

でもflutterのpluginはv3

plugins/build.gradle at master · flutter/plugins · GitHub

ということで使えませんが、purchaseStream(裏はPurchasesUpdatedListener?) でも自分が検証した感じ(今回の要件内)だと、問題なく同期は取れてるみたいです。

そもそも有料コンテンツを実際にアプリ上で使えるかどうかの判定を、 firestoreで行う場合はそこまで気にする必要がないかもしれません。
この場合は、functionsでusersの様なcollectionを更新して最新のsubscriptionの状態を記録しておくというような方法になると思います。

InAppPurchase.purchaseStreamってそもそも裏側はどうなってるの?

ソースを見たところ、StreamControllerに適宜addしている様に見えて、

インスタンス化するとき
plugins/in_app_purchase_android_platform.dart at 1a4cee78a1fd2eb9eb7377239399678115de437a · flutter/plugins · GitHub

restorePurchases()した時
plugins/in_app_purchase_android_platform.dart at 1a4cee78a1fd2eb9eb7377239399678115de437a · flutter/plugins · GitHub

の二箇所しか見つけられない。

また、restorePurchases()は内部ではqueryPurchases()を実行している様子 https://github.com/flutter/plugins/blob/1a4cee78a1fd2eb9eb7377239399678115de437a/packages/in_app_purchase/in_app_purchase_android/lib/src/in_app_purchase_android_platform.dart#L184

_inAppPurchase.restorePurchases()するボタンをつけてみたけど、 解約してから押しても変化なし(定期購読中のまま)。 単純にアプリを起動しなおした方がいい。

(その他)アプリで定期購入してすぐアプリを閉じるとplay storeでエラーが表示される

次の更新までにアプリを開かないと期限切れになる。この辺りもお問い合わせのポイントとしてはそこそこありそう。 この時、google playの購入履歴は「払い戻し済み」になる。