Flutter couldn‘t find “libflutter.so“
今天项目中遇到了一个问题,小伙伴在打包的时候发现报错 couldn't find "libflutter.so" 。在詹姆斯.刘的帮助下,把这个地方调试通了。那么我们今天就来讲一讲这个问题。以下是本期目录:
一、so是什么?
在android开发中,大家对so文件一定不陌生。在开发中,android的原生代码一般使用C、C++编写,然后编译生成一个动态链接库,就是文件后缀为.so的ElF文件。so文件是unix(一个系统的名字)的动态连接库,是一个二进制文件,作用相当于windows下的.dll文件。在andorid中调用so都是通过jni的方式调用。android中提供了相关的方法,loadLibrary
的作用就是加载这个动态链接库,这样后面的代码调用才能成功的找到对应的原生函数。大家也都知道,一般加载so的代码要写到static块中,因为静态代码块的执行时机非常早,比什么构造函数、onCreate都要早,在类加载的时候就被调用。关于so的问题,并非此文章的重点,我们以后的内容中专门在讲。
二、目前手机cpu的架构有哪些?
早期的Android系统几乎只支持ARMv5的CPU架构,目前支持七种,总体来说,Android手机大部分采用的是ARM架构的CPU。
架构 | 说明 |
armeabi | ARM架构的默认选项,支持基于 ARM* v5TE 的设备,支持软浮点运算,但不支持硬件辅助浮点运算,支持所有的 ARM* 设备。 |
armeabi-v7a | armeabi-v7a 向下兼容,在兼容 armeabi 的基础上,支持基于 ARM* v7 的设备,支持硬件 FPU 指令,支持硬件浮点运算,目前大部分机器都属于armeabi-v7a。 |
arm64-v8a | arm64-v8a向下兼容 armeabi 和 armeabi-v7a,最主要的区别在于 arm64-v8a 支持64位,在 MIPS64 架构上增加了 ARMv7 架构中已经拥有的的TrustZone技术、虚拟化技术及NEON advanced SIMD技术等特性(ARM收购MIPS)。架构中包含两个执行状态:AArch32(也就是我们常说的ARMv7)和AArch64(ARMv8),也就是说64位的ARM处理器中同时包含着32位的ARMv7和64位的ARMv8两种架构,直接导致每种架构所拥有的晶体管减半。 |
x86 | X86构架是英特尔推出的一种复杂指令集,用于控制芯片的运行的程序,目前该构架的处理器已经广泛运用在PC领域,由于X86构架的处理器芯片在性能上比较强劲,善于执行复杂工作。X86构架属于典型的CISC,指令集丰富,指令不等长,善于执行复杂工作,更强调串行性能。x86机器基本上可以使用 intel 的 libhounini 项目直接在x86机器上运行仅含armeabi的动态库代码,也就会说x86机器对armeabi也能够兼容,不过性能上会有些损耗。 |
x86_64 | 英特尔推出的64位CPU架构,向下兼容x86。 |
mips/mips64 | MIPS是一种高性能的嵌入式CPU构架,其出发点是高性能,主要用于路由器、猫等 |
三、如何查看手机的cpu架构。
查看手机的cpu信息非常简单,配置好adb之后执行。
$adb shell
$cat /proc/cpuinfo
相关参数解释:
主要参数 | 说明 |
Processor | AArch64 Processor rev 3 (aarch64) CPU架构 |
processor | 系统中逻辑处理核的编号。对于单核处理器,则认为是其CPU编号,对于多核处理器则可以是物理核、或者使用超线程技术虚拟的逻辑核 |
CPU implementer | 0x41 [ARM 架构 cpu.h] |
CPU architecture | 7表示arm-v7,8表示arm-v8 |
相关源码定义
/external/v8/src/base/cpu.h
/kernel-3.18/arch/arm64/include/asm/cputype.h
四、android打包的时候怎么指定架构?
android应用在打包的时候,会优先根据cpu的架构选择支持的so库,如果没有就使用兼容的库,比如下面的arm64-v8a如果不配置,那么arm64-v8a的机器也是可以运行的。但是,不同的cpu架构的so文件不能够混合使用,要么全部使用arm64-v8a,要么全部使用armeabi-v7a,选择了32位,就意味着丢失了64位优化过的性能。
ndk {
//选择要添加的对应cpu类型的.so库。还可以添加 'x86', 'x86_64', 'mips', 'mips64'
abiFilters 'armeabi','armeabi-v7a', 'arm64-v8a'
}
五、Flutter支持哪些cpu架构。
在Flutter官方(1.2稳定版)提供了4中CPU架构的so库,armeabi-v7a、arm64-v8a、x86和x86-64,其中x86系列只支持Debug模式,没有提供armeabi架构的库,在目前多数app使用的大量sdk都只提供了armeabi架构的库,因此开发者想到的一种方案是对engine进行修改构建。
六、couldn't find "libflutter.so"的产生
进入今天的正题,先说下问题产生的原因。这几天我们开发了一个功能,需要使用公司自己的sdk,我们的sdk只提供了armeabi-v7a这个架构的so文件,然后我使用我的一个测试机的时候发现报错。
由于使用的是debug包,所以flutter把支持的架构都打入了,这里不再分别展开了,结果就是我们的sdk只支持了armeabi-v7a,而其他架构中没有。而运行在arm64-v8a设备上的时候,找不到sdk提供的so,产生了报错。于是我们就想配置指定的arm架构打包。就像这样:
ndk {
//选择要添加的对应cpu类型的.so库。还可以添加 'x86', 'x86_64', 'mips', 'mips64'
abiFilters 'armeabi-v7a'
}
于是
今天的主题出现了,couldn't find "libflutter.so"。原地懵逼,我不是指定了平台了吗?怎么还崩溃了呢?
查看了apk文件,发现由于只打了一个平台,大小确实比上次要小很多,打开armeabi-v7a发现,确实没有flutter.so文件。但是为什么没有flutter.so文件呢?
七、解决方案
这一切要从flutter 的一个打包命令说起。
- flutter build apk --target-platform=android-arm
- flutter build apk --target-platform=android-arm64
我们看到,在打包的时候,我们可以指定一个target-platform参数,指定android-arm/android-arm64。于是我们就找到了突破的地方,我们去看下这个打包命令。文件在FlutterSDK/packages/flutter_tools/gradle/flutter.gradle。打开这个文件。
这个地方也证实了,flutter目前支持的4中cpu架构,android-arm 对应的变量名字是PLATFORM_ARM32,在PLATFORM_ARCH_MAP中,对应了armeabi-v7。
目前为止,我们找到了打包的参数了,那么在看看他的他target-platform。这里忽略查找过程,直接上代码。
private List<String> getTargetPlatforms() {
if (!project.hasProperty('target-platform')) {
return DEFAULT_PLATFORMS
}
print(project.property('target-platform'))
return project.property('target-platform').split(',').collect {
print(it)
if (!PLATFORM_ARCH_MAP[it]) {
throw new GradleException("Invalid platform: $it.")
}
return it
}
}
我们看到,如果打包的时候我们不传target-platform,就返回默认,如果传递,还要校验是否在PLATFORM_ARCH_MAP中。最后返回。我们这里输出一段日志看以下。
在执行assembleDebug task的时候,多次调用了这个方法,也识别到了我们的cpu架构arm64-v8a,但是在后面打包的时候我们又在ndk配置中使用了armeabi-v7a,于是打包的结果就是:
问题找到了,解决起来也非常的简单,就是在打包的时候,告知flutter build task 指定平台即可。找到flutter工程下的android目录,定位到app/build.gradle文件,不出意外,大家应该都张的一样。
在第23行的位置,加入
project.setProperty('target-platform', 'android-arm')
注意:必须在apply flutter.gradle 之前,否则flutter.gradle还是会读取目标设备的cpu架构。
ok,大功告成!
总结
实际上,解决的方法又很多,我们这样和flutter build apk --target-platform=android-arm命令是一个道理,也又同学可能会认为直接去修改flutter.gradle比较方便,这个问题就仁者见仁了,不做评价。最后还要感谢詹姆斯.刘的鼎力配合,不然以我的性格,早就看不下去了。今天这个部分又是遇到应急写出来的,欢迎大家阅读指正。接下来的文章还是会继续将常用Widget逐一介绍,在最后的系列中,会公开一个商业级的项目,感兴趣的小伙伴请关注。如果您在阅读过程中发现错误,请及时留言给我,我会第一时间改正。也欢迎大家一切交流,共同进步,感谢支持!
推荐阅读
-
java.lang.UnsatisfiedLinkError:dalvik.system.PathClassLoader...couldn‘t find “xxx.so“的解决方法
-
Couldn't find meta-data for provider with authority com.xxx.xxx.provider
-
Couldn't find meta-data for provider with authority com.xxx.xxx.fileprovider
-
Flutter couldn‘t find “libflutter.so“
-
java.lang.UnsatisfiedLinkError:dalvik.system.PathClassLoader...couldn‘t find “xxx.so“的解决方法
-
VUE 采坑之旅-- Mint-ui 按需引入报出Module build failed: Error: Couldn't find preset "es2015" relative to directory "C:\\phpStudy\\PHPTutorial