【问题标题】:Shared library bundled in the apk is not found at runtime在运行时找不到捆绑在 apk 中的共享库
【发布时间】:2018-09-20 13:16:09
【问题描述】:

我做一些涉及 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 的设备(Android 7.0+)上使用这个精确的 APK。

问题:当我切换到 API 级别 21 设备(Android 5.1-,我怀疑我会在 Android 6.0 上遇到同样的问题)时,程序在加载时立即崩溃 libmynativelibrary.so .

由于libcrypto.solibmynativelibrary.so 的依赖项,因此程序会尝试加载它。它实际上在 API 级别 24+ 上运行良好,但在 API 级别 23- 上崩溃。这是因为加载的库不是我的.apk 中的库,而是系统中的库。 And such libraries seem to not be available below API level 24.

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

提前致谢。

【问题讨论】:

    标签: android-ndk android-gradle-plugin


    【解决方案1】:

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

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

    因此,最好的选择是将 OpenSSL 构建为静态库,并将 libmynativelibrary.so 静态链接到它。这样你就有了一个不依赖于其他人的单一二进制文件。

    如果您无法学习本课程,则应使用名称混乱的 OpenSSL 库构建 OpenSSL 库,例如libmyssl.so 和 libmycrypto.so。这可能有助于避免与系统库的简单名称冲突。

    更好的是,按照 NDK 的示例,为您的 SSL API 提供一个唯一的命名空间。

    不要指望从 ApplicationInfo.nativeLibraryDir 的解压缩位置显式加载库会是一个可靠的解决方案:正如我之前所寻找的那样,系统库可能会碰巧之前加载到您的地址空间中。

    请注意,在 Lollipop 之前,您以正确的顺序手动加载所有非系统依赖项。

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

    【讨论】:

    • 您好,感谢您的广泛回答,现在更有意义了。我已经重新编译为armeabi-v7a 并将 OpenSSL 库作为静态交叉编译,它现在就像一个魅力!它也没有给apk 增加那么多重量,我有点害怕它的大小。
    猜你喜欢
    • 2011-06-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-10
    • 2017-06-18
    • 2013-10-27
    • 2014-06-23
    • 2011-04-14
    相关资源
    最近更新 更多