面向中间件供应商的建议

分发使用 NDK 构建的中间件会引发应用开发者无需担心的其他问题。预构建库会将其某些实现选择强加给用户。

选择 API 级别和 NDK 版本

您的用户无法使用低于您指定的 minSdkVersion。如果用户的应用需要在 API 21 上运行,则您不能针对 API 24 构建。您可以为比用户更低的 API 级别构建库。您可以针对 API 16 构建,并保持与您的 API 21 用户的兼容性。

NDK 版本在很大程度上相互兼容,但有时会发生破坏兼容性的更改。如果您知道所有用户都使用相同版本的 NDK,最好使用与他们相同的版本。否则,请使用最新版本。

使用 STL

如果您正在编写 C++ 并使用 STL,那么在libc++_sharedlibc++_static 之间进行选择会影响您分发共享库时对用户的影响。如果您分发共享库,则必须使用 libc++_shared 或确保您的库不会公开 libc++ 的符号。最好的方法是使用 版本脚本 明确声明您的 ABI 表面。

另一种不太稳健的方法是在链接时使用 -Wl,--exclude-libs,libc++_static.a -Wl,--exclude-libs,libc++abi.a。这种方法不太稳健,因为它只会隐藏明确命名的库中的符号,并且不会报告未使用的库的诊断信息(库名称中的拼写错误不是错误,用户有责任保持库列表最新)。这种方法也不会隐藏您自己的实现细节。

在 AAR 中分发原生库

Android Gradle 插件可以导入 AAR 中分发的原生依赖项。如果您的用户使用的是 Android Gradle 插件,这将是他们使用您的库最简单的方法。

原生库可以通过 AGP 打包到 AAR 中。如果您的库已由 externalNativeBuild 构建,这将是最简单的选择。

非 AGP 构建可以使用 ndkports,或者按照 Prefab 文档进行手动打包,以创建 AAR 的 prefab/ 子目录。

包含 JNI 库的 Java 中间件

包含 JNI 库的 Java 库(换句话说,包含 jniLibs 的 AAR)需要注意,其中包含的 JNI 库不会与用户应用中的其他库冲突。例如,如果 AAR 包含 libc++_shared.so,但版本与应用使用的 libc++_shared.so 版本不同,则只会将其中一个安装到 APK 中,这可能会导致不可靠的行为。

最可靠的解决方案是 Java 库最多包含 **一个** JNI 库(这对应用来说也是一个好建议)。所有依赖项(包括 STL)都应该静态链接到实现库中,并且应该使用版本脚本强制执行 ABI 接口。例如,包含 JNI 库 libfooimpl.so 的 Java 库 com.example.foo 应该使用以下版本脚本

LIBFOOIMPL {
global:
    JNI_OnLoad;
local:
    *;
};

此示例使用 JNI 提示 中描述的通过 JNI_OnLoadregisterNatives 来确保暴露最小的 ABI 接口并最大限度地减少库加载时间。