文章目录

在开发android应用时,一般都会用很多的第三方框架。有些框架会提供各个CPU的架构的SO库,比如arm、arm-v7a、x86、mips,有的甚至还提供64位的版本;而有的为了缩小应用包的体积只提供了一些常用的,比如arm,x86。如果应用中有的第三方框架提供了arm和x86的版本,而有的提供了arm,arm-v7a,x86三个版本,那么当运行在arm-v7a版本的CPU上,就会提示找不到只有arm和x86版本的SO库,这样很容易导致应用挂掉,报java.lang.UnsatisfiedLinkError错误,提示native方法找不到实现。

按道理说arm-v7a的CPU会兼容arm版本,但系统去查找SO库的时候却只会在一个目录查找,找完了arm-v7a,没找到不会再去arm目录,这样就会导致兼容性问题。解决方法有两种:

  • 一种是所有包含有SO库的第三方框架提供最新版本NDK支持的所有的CPU架构SO库,如:armeabi armeabi-v7a x86 mips arm64-v8a x86_64 mips64或者在编译时在Application.mk文件中配置APP_ABI := all。这样做一般不合适,这样会分散开发者的注意力。

  • 第二种方法是:应用中所有的包含SO库的第三方框架只能取最小的子集,这种方法比较合适集成第三方框架。

下面以facebook的fresco框架为例来说明第二种方法的操作方式。

fresco框架中提供了各个CPU架构的SO库,包括64位的,而自己的应用其他第三方带有SO库的框架A还没有使用64位的SO库,如果不做处理,应用运行在64位手机上,当使用框架A的时候应用就会闪退,因为框架A没有64位的库。那么解决办法只有将fresco库的64位SO库都删除,只保留框架A的相同目录下面的SO库。下面是gradle文件中的配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

dependencies {
compile 'com.facebook.fresco:fresco:0.8.1'
}

// 将fresco库除armeabi和x86包以外的SO库删除
def deleteSO() {
def rootPath = rootProject.getRootDir().getAbsolutePath() + '/' + project.name
delete fileTree(dir: rootPath + "/build/intermediates/exploded-aar/com.facebook.fresco/imagepipeline/" + "$FRESCO_LIB_VERSION" + "/jni/", excludes: ['**/armeabi/**', '**/x86/**'])
}

project.afterEvaluate{
// debug模式下删除SO库
tasks.getByName('prepareDebugDependencies') { // Hook prepareDebugDependencies任务
it.doLast {
// prepareDebugDependencies任务执行完成后删除SO库
deleteSO()
}
}

// 打包的时候删除SO库
tasks.getByName('prepareReleaseDependencies') {
it.doLast {
deleteSO()
}
}
}

  • 2016-08-24修改

另外还可以使用gradle中的过滤器,可以很方便过滤SO库:

1
2
3
4
5
release {
ndk {
abiFilters "armeabi", "armeabi-v7a", "x86" // 保留这三种架构的CPU
}
}

要求gradle版本不低于2.14.1(可以修改项目根目录下的gradle/wrapper/目录下的gradle-wrapper.properties文件内容,将gradle请求地址中的版本号修改),否则会提示如下错误:

1
2
3
4
Gradle DSL method not found: 'abiFilter()'
Possible causes: The project '*' may be using a version of the Android Gradle plug-in that does not contain the method (e.g. 'testCompile' was added in 1.1.0).
Fix plugin version and sync project The project '*' may be using a version of Gradle that does not contain the method.
Open Gradle wrapper file The build file may be missing a Gradle plugin. Apply Gradle plugin
文章目录