Flutter 添加 armeabi-v7a 本地库出现的一些问题
作者:互联网
1. 第三方native library无法加载
由于我们的 flutter
应用中要集成第三方的 sdk
来实现一些特殊功能,该 sdk
中集成了一些 native library
,而且只有 32位
的。目前在 flutter
的 android
工程中添加了这些 library
, 如下图所示:
随后在 android
工程的 build.gradle
文件中手动指定 jniLibs
目录的路径,如下图所示:
现在正常在 flutter 工程中执行 debug 启动工程,如下图所示:
点击界面按钮,调用第三方 native library
后立马出现报错,随后 App
闪退。报错内容如下:
通过日志可以看出来,我们前面添加的 native library
没有被加载。
当时首先怀疑的是打包时是否将 native library
有打包到 apk
中,所以采用 android studio
的 analyze apk
命令分析,发现确实是已经打包到 apk
文件中了。如下图所示:
仔细回顾上面的日志,不难发现,没有被加载的原因是因为它寻找 library
的路径不对,根本没有包含我们需要的 armeabi-v7a
这个目录。如下图所示,加载的路径基本上都是 arm64
相关的目录,很显然是因为我的真机是 arm64
架构的,所以可能导致这个问题。
关于这个问题,在文章 https://medium.com/codechai/flutter-app-couldnt-find-libflutter-so-c95ad81cbccd 中有详细的说明。大体情况如下:
当apk安装时,首先会标记当前应用是32位的还是64位的,这决定了后面在哪个目录寻找本地库。
- 首先在
lib/arm64-v8a
目录中寻找是否有native libraray
,如果有就标记为64位
。(在上面的情况中,arm64-v8a文件夹中是包含有 libflutter.so 的,所以该应用被标记为 64 位)- 如果没有在 lib/arm64-v8a 中找到 native libraray,则随后在
lib/armeabi-v7a
和lib/armeabi
中寻找,有则标记为32位
。- 如果在上述目录中都没有找到
native library
则说明当前应用没有使用本地库,对 32 位还是 64位 并不敏感。此时会默认标记为64位
。
此时可以在网上找到的大多数回答是在 build.gradle
文件中指定 ndk
的 abiFilter
,如下图所示:
这个配置的意思是指定一个 filter ,让
Gradle
在打包 apk 时只添加armeabi-v7a
下的library
,其它的都不添加。
根据上面的寻找 library 的规则,这么做确实只保证armeabi-v7a
的库被加载到。
添加这项配置后,再继续执行 debug
,又抛出了 couldn't find "libflutter.so"
这个报错信息。详细内容如下所示:
E/FlutterLoader( 8399): java.util.concurrent.ExecutionException: java.lang.UnsatisfiedLinkError: dalvik.system.PathClassLoader[DexPathList[[zip file "/data/app/com.dm.pcbd-A-gAqiQOV9EjRIg7TZRvKw==/base.apk"],nativeLibraryDirectories=[/data/app/com.dm.pcbd-A-gAqiQOV9EjRIg7TZRvKw==/lib/arm, /data/app/com.dm.pcbd-A-gAqiQOV9EjRIg7TZRvKw==/base.apk!/lib/armeabi-v7a, /system/lib, /product/lib]]] couldn't find "libflutter.so"
采用 analyze apk 查看了下生成的 apk
包,发现确实没有将 libflutter.so
打包到 apk 中,如下图所示:
翻了 flutter
的很多 issue
后发现有很多类似的问题,例如这个 issue
https://github.com/flutter/flutter/issues/29710
2. debug下 libflutter.so 无法加载
根据 issue
https://github.com/flutter/flutter/issues/29710 的描述,只要 armeabi-v7a
下添加了其它库,就会出现 libflutter.so
打包不进去的问题。
经过多次尝试后,发现使用 flutter build
命令行生成出来的包中是有 libflutter.so
的,具体命令如下:
// 生成debug包
flutter build apk --debug
// 生成release包
flutter build apk --release
// 安装软件包(在生成debug或release包之后运行)
flutter install
build
生成的 debug
包中包含 libflutter.so
build
生成的 release
包中也包含 libflutter.so
但是直接使用 Android Studio
上的 debug
运行时就是不打包 libflutter.so
到 armeabi-v7a
中。
Android Studio
上的debug
等同于命令行flutter run --debug -v
说实话,到这一步时觉得 flutter
还是不太成熟,差点想弃坑了。
仔细翻阅了 https://github.com/flutter/flutter/issues/29710 这个issue,发现有网友提到命令行手动指定 target-platform
来强制指定目标平台为 arm
32位,例如:
flutter build apk --debug --target-platform=android-arm
flutter run --use-application-binary=build/app/outputs/apk/debug/app-debug.apk
但是 target-platform
这个参数在新版本的 flutter
中不能直接用在 flutter run
上(即上述的 debug 上),只能用在 flutter build
上。那这就导致平常调试时很不方便了,不能直接按 debug
按钮启动启用,得用命令行手动启动,太不方便了。
在上面的 issue
中,又有网友提到直接在 gradle
中配置 target-platform
。具体是在 settings.gradle
文件中添加配置,如下所示:
具体添加的代码如下:
gradle.beforeProject({ project->
if (project.hasProperty("target-platform") && !project.getProperty("target-platform").split(",").contains("android-arm")) {
project.setProperty("target-platform", "android-arm")
}
})
添加这段配置后,就可以 正常使用
界面上的 debug
按钮了,其生成的 apk
包中 armeabi-v7a
文件夹下确实是包含了 libflutter.so
。
3. Release下出现闪退问题
上面解决 debug
正常后,为了看下 release
下的效果,随即用命令行 flutter build apk --release
生成了 release
包,安装后点击按钮访问第三方sdk内容时出现闪退。
这就出现了 release 下和 debug 下行为不一致的问题
这种直接安装 apk
的方式,出现闪退或报错等问题,在 Android Studio
中看不到任何日志,非常不利于问题的排查。
这里可以采用 flutter run --release -v
的方式来启动 release
包,这样在控制台至少可以看到一些日志。flutter run --release -v
在界面上也可以配置出来,如下图所示:
再点击界面上的 Run
或 debug
按钮就可以启动这个 release
包了。(此时 debug 或 Run 按钮不影响运行方式)
通过这种方式运行后,得到 Release包闪退
的报错信息如下:
E/AndroidRuntime(22800): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.dm.pcbd/com.micropattern.sdk.ext.MPFaceQualityDetectActivity}: android.content.res.Resources$NotFoundException: Resource ID #0x0
E/AndroidRuntime(22800): at .................省略一些无关的日志
E/AndroidRuntime(22800): Caused by: android.content.res.Resources$NotFoundException: Resource ID #0x0
E/AndroidRuntime(22800): at android.content.res.ResourcesImpl.getValue(ResourcesImpl.java:292)
E/AndroidRuntime(22800): at android.content.res.Resources.loadXmlResourceParser(Resources.java:2390)
........... 省略一些无关的日志
com.android.internal.policy.HwPhoneWindow.setContentView(HwPhoneWindow.java:342)
E/AndroidRuntime(22800): at android.app.Activity.setContentView(Activity.java:2941)
E/AndroidRuntime(22800): at com.micropattern.sdk.ext.MPFaceQualityDetectActivity.onCreate(Unknown Source:36)
E/AndroidRuntime(22800): at android.app.Activity.performCreate(Activity.java:7458)
E/AndroidRuntime(22800): at android.app.Activity.performCreate(Activity.java:7448)
E/AndroidRuntime(22800): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1286)
E/AndroidRuntime(22800): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3409)
E/AndroidRuntime(22800): ... 11 more
出现这个问题,猜测是release打包时 shrink
压缩导致的问题。首先考虑到可能是 flutter官方文档中提到的 Shrinking your code with R8
导致的问题,遂在命令行打包时尝试关闭 shrinking
,命令如下所示:
flutter build apk --release --no-shrink
不过这个包打出来后,还是存在上面的资源问题。
上面那个是 android
中获取资源的问题,那么有可能是 Gradle
打包时出现的问题,所以考虑应该直接在 Gradle
中关闭 shrink
。具体操作如下,在 build.gradle
中添加如下配置
关于shrink,官方文档中有详细介绍: https://developer.android.com/studio/build/shrink-code?utm_source=android-studio#shrink-resources
到这里,再 Release
后就可以正常使用本地库了。
4. 总结
解决这个问题耗了一整天,基于上都是停留在各种尝试中。经过这一番折腾,确实了解到 flutter
这个坑有些大.......
- 第一次为了解决
libflutter.so
无法加载的问题,甚至尝试过手动将libflutter.so
拷贝到armeabi-v7a
文件夹下。这样确实解决了debug
下的问题,但是最后做出来的release
包一直卡在空白界面。在这里浪费了很多时间。 - 目前
flutter
并不是特别成熟,关于这个问题在issue
中说法有很多,这也导致了各种尝试,花费了很多时间。
经过这次折腾,也确实了解到了很多东西,例如:
- ndk abiFilter 配置
- 对 native library 加载机制有些许了解
- flutter工程和android工程的关系也终于弄明白了一些
5. 关于作者
作者是一个热爱学习、开源、分享,传播正能量,头发还很多的程序员-。-
热烈欢迎大家关注、点赞、评论交流!
- csdn: https://blog.csdn.net/u010920692
- 掘金: https://juejin.cn/user/3237392838298663
- 博客园: https://www.cnblogs.com/zhangzhxb/
标签:Flutter,armeabi,v7a,apk,so,debug,release,android,flutter 来源: https://www.cnblogs.com/zhangzhxb/p/14493600.html