在运行时加载多个共享库在Android

时间:2017-10-11 23:19:03

标签: android cmake java-native-interface shared-libraries

我正在使用cmake在Android Studio中创建我的共享库。库正确构建和链接,我能够在lib / armeabi-v7a下的Apk中查看我的所有库。

图书馆链接如下:

  • LIB1
    • LIB2
      • LIB3
        • LIB4
        • Lib5

我通过拨打System.loadLibrary("lib1");

来加载我的Lib1

我能够调用Lib1,但是一旦Lib1尝试访问Lib2,我收到一条传播消息,说Lib2没有被加载。

然后我想我必须加载其他库,所以我进行了以下调用,但结果是相同的传播消息" Lib2未加载"。

System.loadLibrary("lib5");
System.loadLibrary("lib4");
System.loadLibrary("lib3");
System.loadLibrary("lib2");
System.loadLibrary("lib1");

为什么Lib1无法调用Lib2?是否在导致库加载失败的位置解压缩了其他共享库?

我想请注意,在切换到使用cmake之前,我已正确加载了libs。我相信我之前手动编译我的lib并将它们存储在我的Android Studio项目的/ jniLibs和/ assets目录中,但那是不久之前所以我的内存不清楚细节。

2 个答案:

答案 0 :(得分:3)

由于您的更改似乎正在生效,我猜这不会像将二进制文件放在错误的位置那样意外。 (我自己有时上传到jniLibs/armeabi-v7a然后意识到我正在测试依赖jniLibs/arm64-v8a的64位APK。或者反过来在32位Android设备上安装双架构apk时。)

我想我们也可以在加载时排除未解析的符号,因为它通常会在adb logcat

中告诉您这个问题。

我记得在过去看到这个问题时,它通常被证明是lib2的 soname 的问题。虽然PC Linux可以使用liblib2.so.1之类的东西,但Android似乎要求所有的sonames都以.so

结尾

要检查lib2上的soname,请运行readelf -a liblib2.so。如果我的描述看起来不正确,请重新启动您的NDK版本并确保在链接时添加-Wl,-soname,liblib2.so

此外,运行readelf -a liblib1.so并确保其对liblib2.so的引用使用新的soname,例如(NEEDED) Shared Library: [liblib2.so]。您可能还需要重新链接liblib1.so。

  

我想请注意,在切换到使用cmake之前,我已正确加载了libs。

我假设CMake用于构建的NDK阶段,而不是Java,这可以解释soname的变化。

注意:你添加一个额外的" lib"有点令人困惑。在每个图书馆的名字中。如果您使用了System.loadLibrary("1")System.loadLibrary("2")

的示例,那么沟通可能会更容易

答案 1 :(得分:0)

取决于您的Gradle文件,这可能是因为AS仅执行externalNativeBuild语句中列出的最后一个cmake文件。

您可以查看APK内部的内容,以检查实际上是在构建和捆绑哪些库。如果将apk扩展名更改为.zip,然后解压缩并查看lib目录,则会发现一个构建目录列表,其中包含.so文件。如果看不到与System.loadLibrary(<libName>);调用相对应的.so,则将收到运行时错误。

一个引起类似问题的问题对我来说是我试图通过在应用程序的Gradle版本中使用externalNativeBuild来使用与要包含的每个库相对应的多个cmake文件像这样的文件:

externalNativeBuild {
    cmake {
        path "CMakeLists1.txt"
        path "CMakeLists2.txt"
    }
}

我注意到,只有该语句中列出的最后一个CMakeLists.txt 被执行。这导致仅一个.so文件输出到我的APK的lib目录中,而不是两个都输出。我相信AS的意图是在该语句中仅引用一个cmake文件。如果您像我一样引用了更多内容,则可能只是构建了最后一个,因此其他(在您的情况下,“ lib1”之后的所有内容)都将丢失。

相关问题