More|More than one file was found with OS independent path 'lib/armeabi/**.so'分析和解决
【More|More than one file was found with OS independent path 'lib/armeabi/**.so'分析和解决】最近在编译一个JNI项目遇到了这样的错误:
Execution failed for task ':app:transformNativeLibsWithMergeJniLibsForRelease'.
> More than one file was found with OS independent path 'lib/armeabi/libJniTest.so'
首先想到的依赖的多个aar库中包含了冲突的so文件,这种情况可以通过配置packagingOptions解决。但工程中并未依赖其他库,问题是如何出现的呢?
一、APK会打包哪些so?
首先先了解下APK中的so通常来自哪里:
1. 自身构建的native库 如果工程自身包含native代码,并使用CMake等工具构建,会生成对应架构的so库:
android {
...
externalNativeBuild {
cmake {
...
abiFilters 'armeabi', 'armeabi-v7a'
}
}
}
...
externalNativeBuild {
cmake {
path "CMakeLists.txt"
}
}
}
CMake工作目录在
app/.externalNativeBuild/cmake/debug/armeabi
下,我们在CMakeCahe.txt
中可以看到,CMAKE_LIBRARY_OUTPUT_DIRECTORY
默认值为:CMAKE_LIBRARY_OUTPUT_DIRECTORY:UNINITIALIZED=/Users/tsia/xxx/xxx/app/build/intermediates/cmake/debug/obj/armeabi
则工程构建完之后,该目录下就会输出对应架构的so:
文章图片
CMake输出目录 这些so会打包到APK中。
2.指定的外部库 如果我们依赖了一个外部的so,编译时我们可以通过
add_library
添加外部库依赖,如果我们希望打包的时候能一起带进来,需要在gradle中配置jniLibs的路径:android {
...
sourceSets {
main {
jniLibs.srcDirs = ["mylibs"]
}
}
}
mylibs和gradle文件在同一目录下,是相对的路径。
jniLibs.srcDirs
就是告诉gradle那个目录下的so库要打到包中。文章图片
上图我们可以看到,mylibs目录下的so并未被打到包中,但二级目录和二级目录下的so文件都被打进去了,二级目录名称除了架构目录也可以自定义,非.so后缀的文件不会被打进去。(当然,这里没有设置ndk.abiFilters)
3. compile的外部库 如果通过compile方式依赖一个外部aar库,其中的so会被打包到APK中。
二、问题分析
我的项目中只包含自己构建的native库,唯一不同的是我在CMakeLists.txt中指定了构建产物的输出目录:
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI})
于是在
src/main/jniLibs/${ANDROID_ABI}
下也输出了一份so库:文章图片
我们没有指定jniLibs库,为什么会有冲突呢?
虽然我们没有设置,但jniLibs.srcDir有默认值,通过
println "jniLibs.srcDirs= ${android.sourceSets.main.jniLibs.srcDirs}"
打印发现:
jniLibs.srcDirs= [/Users/tsia/Documents/xxx/xxx/app/src/main/jniLibs]
CMake输出目录和jniLibs指向同一个目录,下面的so会被打包两次产生冲突,原来如此!
三、如何解决
方法1 jniLibs目录设为空,如指向其他目录也行,只要不要和CMake输出目录重合。
android {
...
sourceSets {
main {
jniLibs.srcDirs = []
}
}
}
方法2 中配置打包规则,有冲突选择就第一个最为打包内容:
packagingOptions {
pickFirst "**/libJniTest.so"
}
相关链接:
《使用CMake构建Android JNI工程》
推荐阅读
- (六)Component初识组件
- performSelectorOnMainThread:withObject:waitUntilDone:参数设置为NO或YES的区别
- The|The ideal servant
- iPhone手机这些使用指南|iPhone手机这些使用指南 你知道多少()
- thanks|thanks leslie
- 青岛机情派iPhone5s指纹识别修复
- 每日一词|每日一词 101 | pioneer
- 我与press|我与press one的缘分
- 2018-04-28|2018-04-28 ag better than grep
- vue项目+wxjssdk,config配置解决iPhone端签名错误的问题