最近はkotlin + coroutineが主流になってきているので流れに乗っかって開発をしていたときに踏んだ地雷です。
同じ地雷を踏んだ方の参考になれば幸いです。
起きた問題
・リリース用apkを出力後、リサインを行った場合に100%クラッシュが発生していた。
・手元の端末(Pixel3 OS: 9)でリサインされる前のリリース用のapkをインストールした場合は正常に動作する。
ログに出力されたエラーは以下の通り(一部抜粋)
IllegalStateException: Module with the Main dispatcher is missing. e.g. 'kotlinx-coroutines-android'
proguardについて
以下の内容は記載済み
-keepnames class kotlinx.coroutines.internal.MainDispatcherFactory {}
-keepnames class kotlinx.coroutines.CoroutineExceptionHandler {}
-keepnames class kotlinx.coroutines.android.AndroidExceptionPreHandler {}
-keepnames class kotlinx.coroutines.android.AndroidDispatcherFactory {}
-keepclassmembernames class kotlinx.** {
volatile <fields>;
}
原因
リサインする際にapkファイルが保持しているMETA-INF
ディレクトリを丸ごと削除しているのが原因。
(META-INF
の内容を確認したい場合は、apkファイルの拡張子を.zip
へ変更後、コマンドからunzip test.zip
を行えば確認することができます)
■参考
・https://github.com/mozilla-mobile/reference-browser/issues/591
・https://docs.oracle.com/javase/8/docs/api/java/util/ServiceLoader.html
理由
MainDispatcherLoader
がServiceLoader
を使用していて、ServiceLoader
はMETA-INF/services
ディレクトリ内にある情報を取りに行き、リサイン後は署名ファイルだけの状態になっていて必要な情報がなくなっているため。
対処方法
- リサインを行う際にMETA-INFディレクトリは削除せず署名ファイルだけを削除して追加し直す。(おそらく一番ベスト)
- META-INFディレクトリは削除するがリサイン前に中身を一旦別ディレクトリへ退避して、リサイン後に必要な情報(署名ファイル以外)をMETA-INFディレクトリへ追加する(申し訳ないのですが試していないので出来るかどうかは不明)
- リサインを行わない。
- coroutineを使わない。
-
ServiceLoader
がMETA-INF/services
へ情報を取りに行く箇所を洗い出してリサインされても大丈夫なように処理を作る。
最後3つは現実的ではないので難しいところですね。。。
coroutineが流行ってて導入してるのにcoroutineを使わないって。。。
こんな方法で解決したよ!!なんて方がいれば教えていただけますと幸いです。