Edited at

kotlin + coroutine + リサイン(resign)

最近はkotlin + coroutineが主流になってきているので流れに乗っかって開発をしていたときに踏んだ地雷です。

同じ地雷を踏んだ方の参考になれば幸いです。


起きた問題

・リリース用apkを出力後、リサインを行った場合に100%クラッシュが発生していた。

・手元の端末(Pixel3 OS: 9)でリサインされる前のリリース用のapkをインストールした場合は正常に動作する。

ログに出力されたエラーは以下の通り(一部抜粋)

IllegalStateException: Module with the Main dispatcher is missing. e.g. 'kotlinx-coroutines-android'


proguardについて

以下の内容は記載済み


proguard-rules.pro

-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


理由

MainDispatcherLoaderServiceLoaderを使用していて、ServiceLoaderMETA-INF/servicesディレクトリ内にある情報を取りに行き、リサイン後は署名ファイルだけの状態になっていて必要な情報がなくなっているため。

■参考

https://medium.com/@hanru.yeh/quick-note-kotlin-coroutine-dispatcher-gets-android-main-dispatcher-by-serviceloader-29b88cb0df8b


対処方法


  • リサインを行う際にMETA-INFディレクトリは削除せず署名ファイルだけを削除して追加し直す。(おそらく一番ベスト)

  • META-INFディレクトリは削除するがリサイン前に中身を一旦別ディレクトリへ退避して、リサイン後に必要な情報(署名ファイル以外)をMETA-INFディレクトリへ追加する(申し訳ないのですが試していないので出来るかどうかは不明)

  • リサインを行わない。

  • coroutineを使わない。


  • ServiceLoaderMETA-INF/servicesへ情報を取りに行く箇所を洗い出してリサインされても大丈夫なように処理を作る。

最後3つは現実的ではないので難しいところですね。。。

coroutineが流行ってて導入してるのにcoroutineを使わないって。。。

こんな方法で解決したよ!!なんて方がいれば教えていただけますと幸いです。