分发使用 NDK 构建的中间件会引发应用开发者无需担心的其他问题。预构建库会将其某些实现选择强加给用户。
选择 API 级别和 NDK 版本
您的用户无法使用低于您指定的 minSdkVersion。如果用户的应用需要在 API 21 上运行,则您不能针对 API 24 构建。您可以为比用户更低的 API 级别构建库。您可以针对 API 16 构建,并保持与您的 API 21 用户的兼容性。
NDK 版本在很大程度上相互兼容,但有时会发生破坏兼容性的更改。如果您知道所有用户都使用相同版本的 NDK,最好使用与他们相同的版本。否则,请使用最新版本。
使用 STL
如果您正在编写 C++ 并使用 STL,那么在libc++_shared
和 libc++_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_OnLoad
的 registerNatives
来确保暴露最小的 ABI 接口并最大限度地减少库加载时间。