問題
Kotlinで実装されている既存アプリにFlutterを追加した所、デバッグビルドしたapkを端末にインストールできないことが起きるようになった。頻度は10回に1回くらい。
2020-12-01 16:09:54.960 1578-2005/? W/ziparchive: Zip: inflate zerr=-3 (nIn=0xb40000787007ebda aIn=25638 nOut=0xb40000787006ebc0 aOut=24608)
2020-12-01 16:09:54.960 1578-2005/? W/zipro: ExtractToMemory failed with Zlib error
2020-12-01 16:09:54.960 1578-2005/? E/NativeLibraryHelper: Failed uncompressing libflutter.so to /data/app/vmdl854882831.tmp/lib/arm64/tmp.hVakYp
...
--------- beginning of system
2020-12-01 16:09:54.961 1578-2005/? W/NativeHelper: Failure copying native libraries [errorCode=-18]
原因
apkのビルド時にlibflutter.soを圧縮しているが、それが正常できないのが原因。
問題が起きる時のapkからlibflutter.soを取り出してみると、サイズが約200KBになっている。libflutter.soは、正常時なら10MB以上ある。
回避策
libflutter.soの圧縮に問題があるので、libflutter.soの圧縮をしないことで問題は回避できる模様。
AndroidManifestのextractNativeLibsにfalseを設定することで、実現できる1。
<manifest>
<application
android:extractNativeLibs="false" >
...
</application>
</manifest>
ただし、libflutter.soを圧縮しなくなる分、アプリのサイズは増大するので注意。
問題が起きていたアプリでは、サイズが120MBから230MBに増えた。
基本、Wifi環境下でしかダウンロードしないのでよいが、そうでないなら、別の対処を考えた方が良い。
同じアプリでも、aabをReleaseビルドする場合は問題が起きたことがない。なので、デバッグビルド固有の設定に問題がありそうである。
補足
原因詳細
エラーログの「Zip: inflate zerr=-3」の部分に着目。エラーコードの定義箇所を見ると、 kInvalidFileというエラーで、意味は「入力ファイルを zip アーカイブとして処理できません。通常、小さすぎたり、大きすぎたり、有効な署名がないために処理できません」。
ということでlibflutter.soが破損しているということが分かる。
問題が起きるとき、MacのFinderからそのapkファイルを解凍しようとするとエラーが起きるので、Android OSの解凍処理には問題ないことが分かる。shellのunzipコマンドならapkファイルの解凍できる。解凍後、libflutter.soのサイズを見ると、約200KBになっていることが分かる。
Firebase Test Labでのエラーの見え方
この問題に気づいたのは、CIでFlutte入りのアプリをデバッグビルドし、Firebase Test LabでE2Eテストを実行しようとしたとき。
「The app APK is not a valid Android application.」というエラーが表示される。
以下、エラーログを示す[^2]。
sudo gcloud firebase test android run \
--app "${DEBUG_APP_APK_PATH}" \
--test "${TEST_APK_PATH}" \
--test-targets "user bot2" \
--device model=NexusLowRes,version=28 \
--use-orchestrator \
--environment-variables clearPackageData=true,coverage=true,coverageFile="/sdcard/coverage.ec" \
--directories-to-pull /sdcard \
--results-bucket ${TEST_RESULTS_BUCKET}
Have questions, feedback, or issues? Get support by visiting:
https://firebase.google.com/support/
Uploading [app/build/outputs/apk/*******/debug/app-*******-debug.apk] to Firebase Test Lab...
Uploading [app/build/outputs/apk/androidTest/*******/debug/app-*******-debug-androidTest.apk] to Firebase Test Lab...
Raw results will be stored in your GCS bucket at [https://console.*******ers.google.com/storage/browser/*****************************/2020-12-01_04:15:54.367295_CwcV/]
Test [matrix-2dcbutvhf7ld6] has been created in the Google Cloud.
Firebase Test Lab will execute your instrumentation test on 1 device(s).
ERROR: (gcloud.firebase.test.android.run)
Matrix [matrix-2dcbutvhf7ld6] failed during validation: The app APK is not a valid Android application.
Exited with code exit status 1
CircleCI received exit code 1
-
英語のリファレンスを読むと、Android Gradle Plugin 3.6.0以上だとデフォルトfalseとのこと。ただ、問題のアプリはextractNativeLibsの設定に対応していないAndroid 4.4が最小サポートOSのせいか、trueの動作になっていた。 ↩