在移动设备开发领域,随着技术的发展,对不同CPU架构的支持变得日益重要。特别是对于基于Intel架构的设备,如Dell Venue 8 7840、Nokia n1、Google Nexus Player等,支持x86架构已成为许多中间件软件提供商的必备条件。本文将介绍如何在Android开发中支持Intel架构,包括x86和x86_64,并探讨如何为不同的CPU架构打包APK。
自2011年以来,x86支持已成为Android的一部分。随着越来越多的旗舰产品基于Intel架构,中间件软件提供商需要支持x86设备,以确保最终应用的兼容性。在选择第三方中间件时,公司会仔细考虑支持的CPU架构,因为这将直接影响最终应用的兼容性,可能决定交易的成功与否。
在许多情况下,支持x86是必要的。但请注意,这只对实际使用架构特定二进制文件(通常是打包到最终APK中的.so文件)的中间件有意义。可以使用Zip归档查看器、aapt dump badging命令或Native Libs Monitor来检查APK中是否存在.so文件。
截至NDK r10d,Android支持以下CPU架构(ABI):armeabi、armeabi-v7a、x86、x86_64、arm64-v8a、mips和mips64。添加x86/x86_64支持的方式完全取决于开发者手中拥有的内容(源代码?库?工具链?服务?)。通常,添加此类支持是通过遵循Android最佳开发实践来完成的。
由于Android最初只支持ARM,一些提供商没有重视支持其他平台。为了解决这个问题,Intel提供了在Intel设备上运行时转换ARM二进制文件的能力,并且效果良好。然而,中间件提供商应该为Intel架构提供原生支持。
本文概述了在库/引擎级别需要做什么以更好地支持Intel平台。主要有两种情况:
在这两种情况下,都应该向客户提供文档和示例项目,这当然会导致正确打包和包含x86/x86_64库在最终应用中。
包含原生组件的库和引擎可以以不同的形式分发:几个.jar文件、一个.aar、一个NDK项目、一个Android项目等。如果库由一个Java库和.so文件组成,应该将其分发为一个.aar,而不是伴随.so文件的.jar文件。AAR是扩展了Android的.jar文件,允许包含资源和原生库。一旦上传到Maven中央仓库/jCenter,Android开发者可以轻松地包含AAR。
应该在.aar下的./jni/
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := yourlib
LOCAL_SRC_FILES := prebuilts/$(TARGET_ARCH_ABI)/libYourLib.so
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/prebuilts/includes
include $(PREBUILT_SHARED_LIBRARY)
还要在Application.mk文件中设置所有支持的架构,如下所示:
APP_ABI := all # 也可以是:armeabi-v7a x86 x86_64 arm64-v8a…
如果库/引擎通过完整的Android项目分发,.so文件必须包含在正确的位置:在Eclipse/Apache Ant项目中,将它们放置在libs/
sourceSets.main { jniLibs.srcDir 'src/main/libs' }
当提供完整的服务和/或软件处理APK打包时,需要正确生成兼容的APK。推荐(也是默认)的方式是打包一个APK,并在APK下的lib/
如果.so文件太大,无法嵌入多个版本的这些库,可以为每个架构打包一个APK。唯一的要求是生成一个包含不同集合的.so文件的APK,并放置在正确的lib/
当使用gradle时,可以通过添加以下代码到build.gradle来无缝实现所有这些(一次构建中生成所有适当的APK):
android {
...
splits {
abi {
enable true
reset()
include 'x86', 'x86_64', 'armeabi-v7a', 'arm64-v8a', 'universalApk'
}
}
// 映射version code
project.ext.versionCodes = [
'armeabi': 1,
'armeabi-v7a': 2,
'arm64-v8a': 3,
'mips': 5,
'mips64': 6,
'x86': 8,
'x86_64': 9
]
applicationVariants.all { variant ->
// 为每个输出分配不同的version code
variant.outputs.each { output ->
output.versionCodeOverride =
project.ext.versionCodes.get(output.abiFilter, 0) * 1000000 +
android.defaultConfig.versionCode
}
}
...
}