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()の中に入れることになります。
こんな感じです。
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でしか呼べない
BillingClient.queryPurchasesAsync()を使える様にする
このコミットで自分のやりたいことはとりあえずできました。
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