Flutter app: couldn’t find “libflutter.so” (Fix)

And how I managed to fix the issue

Recently I was working on a Flutter app, that used Realm.io. And as expected quickly a very cool prototype was ready for testing. So I released app over Playstore’s internal test channel for test users. And as expected, unexpected happened!!

Suddenly found few of devices could not even start the application. Little more digging and I found out that devices with 64bit architecture were unable to run the application (x86_63 & arm64_v8a to be more specific).

Exception stack

java.lang.UnsatisfiedLinkError: dalvik.system.PathClassLoader[DexPathList[[zip file "/data/app/com.codesphere.bol-2/base.apk"],nativeLibraryDirectories=[/data/app/com.codesphere.bol-2/lib/arm64, /data/app/com.codesphere.bol-2/base.apk!/lib/arm64-v8a, /vendor/lib64, /system/lib64]]] couldn't find "libflutter.so"
at java.lang.Runtime.loadLibrary(Runtime.java:367)
at java.lang.System.loadLibrary(System.java:1076)
at io.flutter.view.FlutterMain.startInitialization(FlutterMain.java:172)
at io.flutter.view.FlutterMain.startInitialization(FlutterMain.java:149)
at io.flutter.app.FlutterApplication.onCreate(FlutterApplication.java:22)
at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1014)
at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4722)
at android.app.ActivityThread.access$1600(ActivityThread.java:153)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1412)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5438)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:738)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:628)

Root cause:

When I viewed app’s apk file in Andorid Studio’s APK analyzer, I found in my application, I had used realm.io packages which had “librealm-jni.so” native library. And as we can see in the screenshot below, “libreal-jni.so” is present in all sub-folders of “lib”, for all the android device architectures. But, Flutter’s “libflutter.so” was only present under “armeabi-v7a” folder.

App’s APK analyzer screenshot

Little more RnD and from stackoverflow answer I came to know:

When the APK is installed, the installer checks if the package contains libraries in the official directories, and marks the activity as 32 or 64 bit depending on the outcome.
If it finds libraries in lib/arm64-v8a within the APK (normally taken from the directory libs/arm64-v8a in the build directory), it will be marked as 64 bit, and will ignore all other directories. If it finds libraries in lib/armeabi-v7a or lib/armeabi in the APK, the process is marked as 32 bit. If there's no native libraries in any of these, the installer assumes that the application doesn't use native code at all and is free to run it in either mode, in practice in 64 bit mode.

So, since my generated apk had folders for 64bit devices present, so installer marked it as 64bit app, and when running the app linker tried to find all the native libraries in 64bit flavored directories. And since it did not contain “libflutter.so” the above exception was thrown.

Reading much of discussions on flutter’s git issues pages, I realized that flutter is not shipping “libflutter.so” in 64bit mode (at least for now, may be the will provide it soon, as google promoting 64bit apps on stores). So few alternative options were suggested as building application with following command

flutter build apk --target-platform android-arm64

But, doing so gave me this apk structure:

App’s APK analyzer screenshot when ran with “ — target-platform android-arm64”

Now, we have both “libflutter.so” and “librealm-jni.so” present under “arm64-v8a” folder but “armeabi-v7a” has only “librealm-jni.so” .

So, devices with 64bit architecture were able to run the app, but now 32bit devices were unable to run the application. :(
So, either we are going to generate two apk files targeted for 32bit & 64bit devices separately or we need to find another solution which should work for both type of architectures.

The Solution

In the stackoverflow’s answer it says:

Yes, arm64-v8a devices can also run armeabi-v7a code.

So, if our apk has only “armeabi-v7a” libraries present and if we could stop generation of other architecture directories in our apk, both 32bit & 64bit devices would be able to run application.

ABI Filters

Gradle provides a feature to select specific binary to package in generated apk

abiFilters: Specifies the Application Binary Interfaces (ABI) that Gradle should build outputs for and package with your APK.

Now using “abiFilters” option we can select only “arm64-v8a” specific binaries to go in our generated apk with following configuration (shown in bold) in our ‘anroid/app/build.gradle’:

android {
defaultConfig {
....
....
ndk {
abiFilters 'armeabi-v7a'
}
}
  ....
....
....
}

With this configuration, we are telling gradle to package libraries only for “armeabi-v7a” architecture. After adding this, generate apk using following command:

flutter build apk

Analyze the newly generated apk in your Android studio.

App’s APK analyzer screenshot after adding gradle configuration

As seen in above screenshot, now apk contains only “armeabi-v7a” folder and none of other architecture specific folders, so running apk on 64bit device won’t find any folders for 64bit specific libraries, and installer will mark it as 32bit application and will look for libraries under “armeabi-v7a” folder, and it contains both the libraries required by app. :)

Happy coding!!!


The Flutter Pub is a medium publication to bring you the latest and amazing resources such as articles, videos, codes, podcasts etc. about this great technology to teach you how to build beautiful apps with it. You can find us on Facebook, Twitter, and Medium or learn more about us here. We’d love to connect! And if you are a writer interested in writing for us, then you can do so through these guidelines.

Like what you read? Give GP a round of applause.

From a quick cheer to a standing ovation, clap to show how much you enjoyed this story.