美文网首页
More than one file was found wit

More than one file was found wit

作者: tsia | 来源:发表于2019-03-09 16:10 被阅读0次

    最近在编译一个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工程》

    相关文章

      网友评论

          本文标题:More than one file was found wit

          本文链接:https://www.haomeiwen.com/subject/aoispqtx.html