如何为 Android 不同平台打包原生预建库

Posted

技术标签:

【中文标题】如何为 Android 不同平台打包原生预建库【英文标题】:How to package native prebuilts libraries for Android different platforms 【发布时间】:2021-05-09 16:18:45 【问题描述】:

为了编译原生预建库,我们使用 NDK 工具链和这两个选项 -Dandroid_ABI-DANDROID_PLATFORM,所以如果我们支持 android-28android-29 平台和 armeabi-v7aarm64-v8ax86 , x86_6 ABIs 我们将要生成的库集:

.
├── android-28
│   ├── arm64-v8a
│   │   └── libMy.so
│   ├── armeabi-v7a
│   │   └── libMy.so
│   ├── x86
│   │   └── libMy.so
│   └── x86_64
│       └── libMy.so
└── android-29
    ├── arm64-v8a
    │   └── libMy.so
    ├── armeabi-v7a
    │   └── libMy.so
    ├── x86
    │   └── libMy.so
    └── x86_64
        └── libMy.so

我们可以很容易地在Android cmake中使用这些获得的预编译,因为它支持$ANDROID_PLATFORM$ANDROID_ABI变量,例如CMakeLists.txt:

...
list(APPEND CMAKE_FIND_ROOT_PATH $THIRDPARTY_PREBUILT_DIR/$ANDROID_PLATFORM/$ANDROID_ABI/mylib)
...

但是我似乎不清楚将这些预构建的内容打包到 APK 中,因为 app/src/main/jniLibs 不支持平台层次结构,只支持 ABI:

.
└── jniLibs
    ├── arm64-v8a
    │   └── libMy.so
    ├── armeabi-v7a
    │   └── libMy.so
    ├── x86
    │   └── libMy.so
    └── x86_64
        └── libMy.so

在输出 app-debug.apk/lib 中也是相同的结构。

所以问题:为什么我们在工具链和Android cmake 选项中有不同平台的选项,但原生库(jni 库)的打包却忽略了它们?

我使用Android Studio 3.6.3Gradle 5.6.4

【问题讨论】:

您是否需要为这两个平台级别提供单独的库,或者您可以将它们组合成一个库?如果它们确实需要单独的库,那么您可能需要为不同的最低 API 级别构建单独的应用程序包/APK(参见例如developer.android.com/studio/build/…)。 @Michel:感谢您的评论。我需要构建一些第三方库,然后像 Android 应用程序项目中的预建库一样使用它们,但是为了编译它们,NDK 工具链需要我指定 -DANDROID_PLATFORM 参数,但这些库不依赖于特定的 Android API(28 或 29 或其他)只有应用程序需要支持 28 和 29。所以我会像 @Dan Albert 回答的那样做 - 将应用最旧的版本来编译第三方库。 【参考方案1】:

您可以选择平台作为构建的一部分,因为这决定了您的代码将与哪些设备兼容。如果您的目标是 21,则不能保证您的代码可以在比 Lollipop 更早的任何设备上运行。

不过,应用程序是向前兼容的,因此如果您构建 21 版,您将在 Lollipop 和之后的所有内容上运行(极少数例外,只要您坚持公共 API 的定义行为,就非常罕见)。这就是为什么您不需要为每个平台打包库,只需要为您支持的最旧的平台打包。

【讨论】:

以上是关于如何为 Android 不同平台打包原生预建库的主要内容,如果未能解决你的问题,请参考以下文章

如何为 SceneKit 预编译 PBR 着色器?

如何为原生安卓浏览器开发插件

K8s 平台可以如何处理 Pod 预授权问题

跨平台:如何在 UWP 中设置不同的递增内部版本号并保持版本名称,如 iOS/Android

跨平台应用开发进阶(二十九) :uni-app 实现Android原生APP-云打包集成神策详细教程

如何为 Android 软键盘添加自定义功能