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逐一介绍,在最后的系列中,会公开一个商业级的项目,感兴趣的小伙伴请关注。如果您在阅读过程中发现错误,请及时留言给我,我会第一时间改正。也欢迎大家一切交流,共同进步,感谢支持!

猜你喜欢

转载自blog.csdn.net/z2008q/article/details/108621188