Flutter for Android の ABI (armeabi-v7a と arm64-v8a)
Flutterはエンジンの低レイヤの部分はC++で書かれています。Androidでは、C/C++部分はlibflutter.soとしてアプリ内に含まれます。Flutter SDKにはビルド済みのlibflutter.soファイルが含まれており、これがそのまま使われるようにアプリはビルドされるため、アプリのビルド時にはNDKは必要ありません。
さて、FlutterでAndroid向けにAPKファイルをビルドする際、ある特定のABIのlibflutter.soファイルのみがAPKファイルに含まれます。デフォルトでは armeabi-v7a です。armeabi-v7a は32bitでも64bitでも実行できるので、多くのAndroidデバイスで実行できます。
一方で、複数のABIを含むユニバーサルなAPKを作ることが、現時点ではできません。
- https://github.com/flutter/flutter/issues/10728
- https://github.com/flutter/flutter/issues/23055
- https://github.com/flutter/flutter/issues/24534
しかし Google Play Store は64bit対応を強く推進しており、64bitの arm64-v8a を使いたい(publishしたい)というニーズもあります。
※念のために書いておきますと armeabi-v7a でも64bit CPUのAndroid端末で実行できます
target-platform
この場合は —target-platform
というオプションを使います。
armeabi-v7a をビルド(デフォルト):
flutter build apk —target-platform=android-arm
※指定しない場合のデフォルトですが、明示しています
arm64-v8a をビルド:
flutter build apk —target-platform=android-arm64
APKの中身を見ると、たしかに arm64-v8a に libflutter.so が入っています。
<img width="287" alt="スクリーンショット 2019-02-19 19.36.14.png" src="/posts/qiita-3e2914d007e990af947c/1.png">
※NDKを使わないアプリでは libflutter.so のみになります。スクリーンショットで他の .so があるのはNDKを使っているため。
このようにして、それぞれのAPKファイルができるので、これをPlay Storeに公開すればよいです。
Makefileで以下のようにしておくと、楽だと思います。
android: android-arm android-arm64
android-arm:
flutter build apk --target-platform=android-arm
cp build/app/outputs/apk/release/app-release.apk ~/Downloads/myapp-release-arm.apk
android-arm64:
flutter build apk --target-platform=android-arm64
cp build/app/outputs/apk/release/app-release.apk ~/Downloads/myapp-release-arm64.apk
ただし、それらのAPKファイルのversionCodeは違っている必要があることは留意してください。gradle内でこのオプションの値を project.property('target-platform')
で取得できるので、それで分岐させるとよいと思います。
abiFilters
※これより下が必要になるのはNDKを使っている場合に必要なabiFiltersのための処理についてです。NDKなしでFlutterを使っている場合には不要かもしれません。
CARTUNEではOpenCVを使うためにNDKを使っており、ndkのabiFiltersをFlutterのオプションと揃える必要があるため、gradleファイルで以下のように分岐させています。
versionCode 10203000
versionName "1.2.3"
ndk {
if (!project.hasProperty('target-platform'))
abiFilters 'x86'
else switch (project.property('target-platform')) {
case 'android-arm64':
abiFilters 'arm64-v8a'
versionCode += 2
break
case 'android-arm':
abiFilters 'armeabi-v7a'
versionCode += 1
break
default:
abiFilters 'x86'
break
}
}
※x86があるのは、開発中の flutter run
コマンドでエミュレータで起動するため
versionCodeの下一桁をABIのために空けておき、target-platformの分岐で += して切り替えています。
IntelliJ
また、コマンドではなく IntelliJ でアプリを実行する際に、このtarget-platformの切り替えを行うためには、メインメニューの「Run」>「Edit Configurations...」で表示される以下のダイアログでAdditional argumentsに設定しておきます。
<img width="973" alt="2019-02-1813-169a6b89-a622-4de9-bace-4a8fb5bdb5f7.17.27.png" src="/posts/qiita-3e2914d007e990af947c/2.png">
エミュレータ用と実機用で別のConfigurationを用意しておいて、実行時にプルダウンから切り替えて使います。
splits
ちなみにGradleのsplitsで複数のAPKを作ろうとすると、flutter build
コマンドは失敗します。
これは、flutterコマンドが出来上がったAPKファイルの有無をチェックしており、splitsでアーキテクチャ名がファイル名に入ることと相性が悪いためです。
buildディレクトリ以下にAPKファイルが生成されるところまでは行くので、エラーを無視してAPKファイルを使うというのはありかもしれません。
この記事はQiitaの記事をエクスポートしたものです
Discussion