FlutterでAndroidネイティブライブラリを取り込む時の注意点


はじめに

FlutterでAndroid開発中に特定のライブラリを導入すると、ビルドは通るのにアプリ起動時にこんなエラーで強制終了することがあるかもしれません。

couldn't find "libflutter.so"
        at java.lang.Runtime.loadLibrary0(Runtime.java:1011)
        at java.lang.System.loadLibrary(System.java:1657)

要はFlutterのライブラリが見つからない、ということですが、これはFlutterに限らずですが、JNIを使ったライブラリを取り込むときに注意する点です。

原因

Flutterはネイティブライブラリであるsoファイルとしてアプリ上で動作します。その際、別のライブラリでもネイティブライブラリを使っていた場合、必要なsoファイルがapk内に取り込まれずに強制終了しています。
順を追って説明していきます。

Flutterから生成されるsoファイル

まず他のライブラリを入れる前の状態でアプリをビルドしてapkの中身を見ると以下のようになっています。

このように3つのディレクトリにそれぞれlibflutter.soが配置されています。

2019/1/17 修正:
flutterの現時点の最新1.1.9では、armeabi-v7aのサポートが終了し、arm64-v8aへ以降したため、記述を変更しました。キャプチャは古いままですのでご注意ください。(すみません、詳細確認中です)

  • arm64-v8a
  • x86
  • x86_64

それぞれの詳細については公式参照:ABI管理

他のライブラリを入れた場合

私の場合、Google VR SDKを導入したため発生しました。
Google VR SDKの場合、下記の3つが用意されていました。

  • arm64-v8a
  • armeabi-v7a
  • x86

参考:https://github.com/googlevr/gvr-android-sdk/blob/master/samples/ndk-hellovr/build.gradle#L47
その結果、lib配下には4つのディレクトリが生成され、それぞれの構成は以下のようになりました

  • arm64-v8a
    • Flutter(libflutter.so)
    • Google VR(libgvr.so, liboanorenderer.so)
  • armebi-v7a
    • Google VR(libgvr.so, liboanorenderer.so)のみ
  • x86
    • Flutter(libflutter.so)
    • Google VR(libgvr.so, liboanorenderer.so)
  • x86_64
    • Flutter(libflutter.so)のみ



何が起こるのか?

lib配下のsoファイルは、端末のハードによってどのディレクトリが使用されるか決まります。今回の場合、armebi-v7aとx86であれば両方のsoファイルが格納されているため、問題なく起動できます。
一方、arm64-v8aやx86_64を使用する端末で起動した場合どうなるでしょう?ディレクトリ内に必要なsoファイルが揃っていないため、loadLibrary時にcouldn't findと言われてしまうわけです。

どうすれば良いのか?

結論からいうと、gradleでabiFilterを指定する必要があります。

build.gradle
android {
  ...
  defaultConfig {
    ...
    ndk {
      // Specifies the ABI configurations of your native libraries Gradle should build and package with your APK.
      abiFilters "x86", "arm64-v8a"
    }
  }
  ...
}

今回の場合、Google VRとFlutter両方が用意されているのは、x86とarmebi-v7aの二つのみなので、その二つをabiFiltersで指定します。
これにより、apkに取り込まれるsoファイルはabiFiltersで指定されたx86とarmebi-v7aのみとなり、それ以外のx86_64およびarm64-v8aはディレクトリが生成されなくなります。

まとめ

Flutterもネイティブライブラリを使用していることを忘れずに、soファイルが見つからないと強制終了した場合はabiFilterの見直しを検討してみてください。
また、クラッシュは端末のハードに依存するため、Play Consoleのリリース前レポートを利用して確認しておくのがよいかと思います。