Flutter in_app_purchase をPlay Billing Library 4 で書き換える

Flutterのplugin の in_app_purchaseのandroidの方の実装をPlay Billing Library 4で書き換えました。

GitHub - na8esin/migrate_flutter_in_app_purchase_to_play_billing4

※本文はまだ中途半端

まずはソースダウンロード

DownGitだと何故か落とせなかったので、 svn checkout https://github.com/flutter/plugins/trunk/packages/in_app_purchase

メインのプロジェクトのpubspec.yamlにpathで書く

https://dart.dev/tools/pub/dependencies#path-packages

pathで参照されてるpluginの javaのコードを変更した時は、flutter runを停止してもう一度起動すれば反映されます。

plugin側のpubspec.ymlのversionを変更してflutter pub upgradeなどをする必要はありません。

dartのコードであれば、plugin側のソースでもhot restartでいけます。

それと、pathでなくても、githubにおいても、packageとして公開してもいいと思います。

削除されたメソッドなどを書き換える

この辺りをよく読む
Google Play Billing Library リリースノート  |  Google Play の課金システム

background threads で動くようになったものはrunOnUiThread()で囲む

Android Billing 4.0.0 - No purchase result querySkuDetailsAsync() - Stack Overflow

自分が気づいたものは、上記のquerySkuDetailsAsync()とBillingClientStateListener#onBillingSetupFinished()です。 これはflutter側をデバックしてもわかりづらいので気付くのが結構難しいです。

上記の2つは下記で呼ばれるので、

plugins/MethodCallHandlerImpl.java at master · flutter/plugins · GitHub

activity.runOnUiThread()の中に入れることになります。

こんな感じです。

migrate_flutter_in_app_purchase_to_play_billing4/MethodCallHandlerImpl.java at 217badf8b3c59eb20ff098a2402c9046e62e124e · na8esin/migrate_flutter_in_app_purchase_to_play_billing4 · GitHub

LiveDataでメインスレッドに持ってきてみる

runOnUiThread()だと
プロセスとスレッドの概要  |  Android デベロッパー  |  Android Developers

操作が複雑になるにつれて、この種類のコードも複雑化してメンテナンスが難しくなります。

とのことなので、LiveDataを使ってみます。

バックグラウンド スレッドでの Android タスクの実行  |  Android デベロッパー  |  Android Developers

コードがバックグラウンド スレッドで実行されている場合は、MutableLiveData.postValue() を呼び出して UI レイヤと通信できます。

ということなので。

でもjava.lang.IllegalStateException: Reply already submittedが発生。 このエラーはObserverに複数回通知がいくからです。

対応方法としては、SingleLiveEventなコードにすればいいと思いますが、 そこまでするか?と思ったのでLiveDataは使わない方向で。

断念したところのコミット
GitHub - na8esin/migrate_flutter_in_app_purchase_to_play_billing4 at toLiveData

蛇足

observeの引数には、LifecycleOwnerが必要ですが、
https://developer.android.com/topic/libraries/architecture/lifecycle?hl=ja#implementing-lco

サポート ライブラリ 26.1.0 以降のフラグメントとアクティビティには、すでに LifecycleOwner インターフェースが実装されています。

ということですが、AndroidXを有効にしてるので問題なし。

蛇足2

https://developer.android.com/guide/components/processes-and-threads?hl=ja

↑を見るとAsyncTaskが最善と書いてますが、AsyncTaskのリファレンスを見ると

This class was deprecated in API level 30. Use the standard java.util.concurrent or Kotlin concurrency utilities instead.

となってる。

Executorsはjava.util.concurrentパッケージ。

蛇足3 ViewModelProviderを使うためのviewModelStoreの取得方法がわからなかった

普通のAndroidアプリだとAppCompatActivityから取れるんで問題ないですが、 ActivityAwareからは取れません。

時間に余裕がある時にまた調べたい。

蛇足4 onMethodCallはUiThreadでしか呼べない

https://github.com/flutter/engine/blob/master/shell/platform/android/io/flutter/plugin/common/MethodChannel.java#L152

BillingClient.queryPurchasesAsync()を使える様にする

queryPurchases() -> queryPurchasesAsync · na8esin/migrate_flutter_in_app_purchase_to_play_billing4@eece491 · GitHub

このコミットで自分のやりたいことはとりあえずできました。

queryPurchasesAsyncに変えると、アプリが起動したままで定期購入の有効期限が切れた場合に flutter側から呼び出すことで最新の情報が取得できました。

余談

registerWith()

registerWith()を使うのが古いみたいだけど
https://medium.com/flutter/modern-flutter-plugin-development-4c3ee015cf5a

最近はflutte createしてもregisterWith()は生成されない

Reply already submitted with simultaneous method calls

LiveDataを使ってみた時にこれが発生して下記のissueに辿り着きましたが、 今は同じ様にやっても再現できなかったです。

https://github.com/flutter/flutter/issues/29092

参考

ClassyTaxiのbilling libraryをv4に変えたとき
https://github.com/android/play-billing-samples/commit/27fbd2e113cf74c446a01e2f3b700d0380bd281d