Android加载so库时遇到的问题,以及如何指定加载特定CPU架构的so库。

版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/flypple/article/details/79571829

近期在做人脸识别的功能,集成了虹软的人脸识别sdk,有兴趣的可以去虹软官网了解一下。
主要遇到了些什么问题呢,说来也是怪事,慢慢道来:
我的测试设备主要是两台:小米Max2手机一部,22寸安卓设备一台。
虹软给提供的支持sdk的so库只有两个:armabi和armabi-v7a。
虹软人脸识别Demo顺利编译通过,在两台设备上也正常运行,嗯,一切都很正常,后来我发现仅仅一个Demo的包就有70M左右的大小,崩溃,于是我小心翼翼的裁剪掉armabi的so库,发现两台设备也都能正常运行。。。。
好吧,我就尝试集成到自己的工程中吧,结果就栽到沟里了!!!
先吧错误日志贴出来吧:

java.lang.UnsatisfiedLinkError: dalvik.system.PathClassLoader[DexPathList[[zip file 
"/data/app/com.example.lenovo.raispaceandroid-1/base.apk", zip file 
"/data/app/com.example.lenovo.raispaceandroid-1/split_lib_dependencies_apk.apk", zip file 
"/data/app/com.example.lenovo.raispaceandroid-1/split_lib_slice_0_apk.apk", zip file 
"/data/app/com.example.lenovo.raispaceandroid-1/split_lib_slice_1_apk.apk", zip file 
"/data/app/com.example.lenovo.raispaceandroid-1/split_lib_slice_2_apk.apk", zip file 
"/data/app/com.example.lenovo.raispaceandroid-1/split_lib_slice_3_apk.apk", zip file 
"/data/app/com.example.lenovo.raispaceandroid-1/split_lib_slice_4_apk.apk", zip file 
"/data/app/com.example.lenovo.raispaceandroid-1/split_lib_slice_5_apk.apk", zip file 
"/data/app/com.example.lenovo.raispaceandroid-1/split_lib_slice_6_apk.apk", zip file 
"/data/app/com.example.lenovo.raispaceandroid-1/split_lib_slice_7_apk.apk", zip file 
"/data/app/com.example.lenovo.raispaceandroid-1/split_lib_slice_8_apk.apk", zip file 
"/data/app/com.example.lenovo.raispaceandroid-
1/split_lib_slice_9_apk.apk"],nativeLibraryDirectories=
[/data/app/com.example.lenovo.raispaceandroid-1/lib/arm64, 
/data/app/com.example.lenovo.raispaceandroid-1/base.apk!/lib/arm64-v8a, 
/data/app/com.example.lenovo.raispaceandroid-1/split_lib_dependencies_apk.apk!/lib/arm64-v8a, 
/data/app/com.example.lenovo.raispaceandroid-1/split_lib_slice_0_apk.apk!/lib/arm64-v8a, 
/data/app/com.example.lenovo.raispaceandroid-1/split_lib_slice_1_apk.apk!/lib/arm64-v8a, 
/data/app/com.example.lenovo.raispaceandroid-1/split_lib_slice_2_apk.apk!/lib/arm64-v8a, 
/data/app/com.example.lenovo.raispaceandroid-1/split_lib_slice_3_apk.apk!/lib/arm64-v8a, 
/data/app/com.example.lenovo.raispaceandroid-1/split_lib_slice_4_apk.apk!/lib/arm64-v8a, 
/data/app/com.example.lenovo.raispaceandroid-1/split_lib_slice_5_apk.apk!/lib/arm64-v8a, 
/data/app/com.example.lenovo.raispaceandroid-1/split_lib_slice_6_apk.apk!/lib/arm64-v8a, 
/data/app/com.example.lenovo.raispaceandroid-1/split_lib_slice_7_apk.apk!/lib/arm64-v8a, 
/data/app/com.example.lenovo.raispaceandroid-1/split_lib_slice_8_apk.apk!/lib/arm64-v8a, 
/data/app/com.example.lenovo.raispaceandroid-1/split_lib_slice_9_apk.apk!/lib/arm64-v8a, 
/system/lib64, /vendor/lib64]]] couldn't find "libmpbase.so"

经过如下:

一、libs和jniLibs:

一开始无脑粘贴,基本上就这样啊,但是一运行就报错了:couldn’t find “libmpbase.so”。

1. 吧Demo中的libs下文件全部原封不动粘贴到了工程中。

这里写图片描述

2. 添加依赖:

//虹软人脸识别相关依赖
    compile fileTree(include: ['*.jar'], dir: 'libs')
    compile files('libs/facedetection.jar')
    compile files('libs/facerecognition.jar')
    compile files('libs/facetracking.jar')
    compile files('libs/ageestimation.jar')
    compile files('libs/genderestimation.jar')
    compile 'com.guo.android_extend:android-extend:1.0.1'

这里写图片描述

百度了一下,都说是没有so引用上,后来发现,确实,我把so放在libs中,但是这些so库本来应该放在jniLibs中的,但是Demo中就是这么放的嘛。于是我又回去看了一眼Demo,确实是放在了libs中,但是人家的Module下的build.gradle中有这么一段,查了一下,是将libs目录指定为jniLibs的意思,这样免得再建jniLibs目录了。

sourceSets.main {
    jniLibs.srcDirs = ['libs']
}

这里写图片描述
于是,我在我的Module下的build.gradle中也添加了这段,结果我发现,额,确实,apk变大了,说明so库时打包进去了,并且确实有所改善:22寸的安卓大设备可以正常运行了;但是小米Max2手机依然报错,couldn't find "libmpbase.so"

二、关于so库和CPU架构的浅度思考:

至于为什么不是深度思考呢,很简单,我了解的太浅了,目前只是做到解决了我自己遇见的问题
回去仔细观察错误日志:发现了一个被我忽略的地方:/data/app/com.example.lenovo.raispaceandroid-1/split_lib_slice_6_apk.apk!/lib/arm64-v8a, 看见没,居然提示我arm64-v8a,也就是意味着,我运行我的app时,识别调用的是arm64-v8a下so库,我的天,虹软根本没有提供arm64-v8a架构的so库啊,而且Demo在手机上运行的好好的,也没管我要arm64-v8a的so库啊,崩溃。
胡思乱想之后,我想起在引入一个视频依赖(GSYVideoPlayer)的时候,添加了该依赖提供的arm64的so库

compile 'com.shuyu:gsyVideoPlayer-java:2.1.1'
compile 'com.shuyu:gsyVideoPlayer-armv7a:2.1.1'
compile 'com.shuyu:gsyVideoPlayer-arm64:2.1.1'

该不会是这个东西影响的吧,而且以前只引用armabi-v7a的时候,这个视频控件是不能用的,所以迫不得已才添加的arm64,现在我只好先把视频依赖中的arm64给去掉了,编译运行,发现依然报错。
为什同一台设备运行两个app的时候要求的so库的架构不一样?!运行Demo时只添加了armabi-v7a,顺利运行,而集成到我自己的工程中,却发现缺少arm64-v8a的so库。。。
后来,我已经没有心思再思考这个问题了,既然这个问题一时半会想不明白,那么,何不绕路而行呢!

三、如何指定APP加载特定CPU架构的so库。

既然这个问题一时半会想不明白CPU架构的问题,那么有一条路应该还是可以尝试走的:
既然Demo只有armabi-v7a却可以正常运行,说明,在我的小米Max2手机上,只凭现有的so库是可以正常运行的。
那么,我能不能手动指定我的app只加载armabi-v7a架构的so库呢,于是,一通搜索学习之后,我惊喜的发现,答案是:可以。
顺便给大家贴一个我参考的帖子
操作起来很简单,就是在Module中的Build.gradle中添加下面一段代码:

ndk {
    //选择要添加的对应cpu类型的.so库。   // 还可以添加 'x86', 'x86_64', 'mips', 'mips64'
    abiFilters 'armeabi-v7a' //'armeabi-v7a',  'arm64-v8a'
    moduleName "app"
}

这里写图片描述

这样:在app中就只会加载armabi-v7a下的so库了。
如果有其他的so库,则删掉它们;如果没有armabi-v7a,则把armabi下的库文件粘贴到armabi-v7a中,并删除其他架构的so库。
这样做的好处就是基本可以适配觉大多数的设备;但是缺点也很明显:在64位设备上,并不如使用arm64-v8a等64位的so库性能好。

好了,我的问题解决了,写到这里也该结束了,但是很显然,只是解决了,思考的深度上还是差得多,而且其中难免有理解错误的地方,如果发现错误,请不吝赐教。
展开阅读全文

没有更多推荐了,返回首页