在运行时找不到捆绑在apk中的共享库

时间:2018-09-20 13:16:09

标签: android-ndk android-gradle

我进行了一些涉及OpenSSL的原生Android开发。

我使用Android NDK独立工具链针对armeabi(32b)进行交叉编译。我交叉编译本机C库,将OpenSSL /本机库.so文件复制到我的libs/文件夹中,我的gradle以此方式引用了该文件:

sourceSets {
    main {
        jniLibs.srcDir(file("libs/"))
    }
}

无论如何,最终结果是我的.apk看起来像这样:

 - > classes.dex
 - > lib/
     -> armeabi/
        -> libcrypto.so
        -> libssl.so
        -> libmynativelibrary.so
 - > res/ (...)
 - > resources.arsc
 - > META-INF/ (...)
 - > kotlin/ (...)
 - > AndroidManifest.xml

共享库是正确的32位ARM ELF文件。我一直在API级别24设备上使用此确切的APK,并取得了巨大的成功(Android 7.0+)。

问题:当我切换到API级别21设备(Android 5.1-,我怀疑我在Android 6.0上也会遇到同样的问题)时,程序在加载{{1 }}。

由于libmynativelibrary.solibcrypto.so的依赖项,因此程序尝试加载它。实际上,它在API级别24+上可以正常工作,但在API级别23-上崩溃。这是因为加载的库不是我的libmynativelibrary.so中的那个库,而是系统中的那个。 And such libraries seem to not be available below API level 24.

我的问题:如何明确告诉Android首先在.apk文件中查找该库,而不是常规系统库目录?

谢谢。

1 个答案:

答案 0 :(得分:1)

在Nogut之前,系统库未受到用户应用程序的保护。名称冲突是有问题的,它们导致Google为Android NDK的C ++共享运行时库发明了一个单独的命名空间。

OpenSSL库也被广泛使用,超出了您的控制范围。它们甚至可能在您没有机会加载自己的libssl之前被加载到您的进程中。

因此,最好的选择是将OpenSSL构建为静态库,并将libmynativelibrary.so静态链接到该库。这样,您便拥有了一个不依赖于其他程序的整体二进制文件。

如果您不能遵循本课程,则应使用名称乱码的OpenSSL库,例如libmyssl.so和libmycrypto.so。这可能有助于避免与系统库的简单名称冲突。

更好的是,遵循NDK的示例,并为您提供SSL API的唯一名称空间。

不要期望从ApplicationInfo.nativeLibraryDir的未压缩位置显式加载库将是一个可靠的解决方案:正如我之前所搜索的那样,系统库可能恰好在之前加载到了您的地址空间中。

请注意,在Lollipop之前,您也必须以适当的顺序手动加载所有非系统依赖项。

此外,新的NDK删除了 armeabi ,因此请考虑切换到 armeabi-v7a