安卓64位应用适配指南

一、应用64位适配

1.1 确定您的应用是否需要适配64位

使用了原生代码的应用才需要进行64位适配。

1.1.1 64位应用的特征

64位应用必须包含64位库。最简单的方法就是检查APK文件的结构,库文件会被打包在APK,针对ARM架构和x86架构具体目录结构如下:

平台32位库文件夹64位库文件夹
ARMlib/armeabi或者lib/armeabi-v7alib/arm64-v8a
x86lib/x86lib/x86_64

针对ARM架构,APK中库文件被打包在lib/arm64-v8a下面的应用是64位应用。

1.1.2 确定您的应用是否使用了原生代码 

如果您的应用符合以下情况,便是使用了原生代码:

  • 使用了任何 C/C++(原生)代码。
  • 与任何第三方原生库关联。
  • 通过使用原生库的第三方应用构建程序构建而成。

1.2 检验您的应用是否已经支持64位 

1.2.1 利用谷歌商店快速检查您的应用是否支持64位

要检查应用是否已满足 64 位要求,一种快速的方法是前往 Play 管理中心查看现有的版本,确定应用是否合规

如果您的草稿版本存在与 64 位要求相关的问题,Play 管理中心也会显示相应的警告。请看以下示例:

如果您看到提醒,表明您的应用是不支持64位的,需要进行相应的适配。

1.2.2 使用APK分析器查找原生库

APK分析器是一款可用于对构建的 APK 进行各方面评估的工具。针对我们目前所讨论的情况,我们将使用该工具查找原生库,以确定是否具备 64 位库。

1. 打开 Android Studio,然后打开任一项目。

2. 从菜单中依次选择 Build > Analyze APK…

3. 选择您要评估的APK。

4. 查看 lib 文件夹,您可以在其中找到“.so”文件。如果在您的应用中找不到任何“.so”文件,则说明该应用的相应库已准备就绪,您无需采取进一步措施。如果您看到 armeabi-v7a 或 x86,则说明您有 32 位库。

5. 检查是否 arm64-v8a 或 x86_64 文件夹中有类似的“.so”文件。

6. 如果您没有任何 arm64-v8a 或 x86_64 库,则需要更新构建流程以开始构建并打包APK中的这些工件。

7. 如果您看到32位和64位的库均已打包到软件包中,则可以跳至在64位硬件上测试应用。

1.2.3 通过解压缩 APK 查找原生库

APK文件的结构类似于ZIP文件,可以像ZIP文件一样解压缩。 如果您更喜欢使用命令行或任何其他解压缩工具,也可以采用解压缩APK的方法。

只需解压缩APK文件(根据您使用的解压缩工具,您可能需要将其重命名为.zip),然后按照上文中的指南浏览解压缩后的文件,即可确定您的应用是否已经为支持64位设备做好准备了。

例如,您可以从命令行中运行如下命令:

> zipinfo -1 YOUR_APK_FILE.apk | grep .so$
lib/armeabi-v7a/libmain.so
lib/armeabi-v7a/libmono.so
lib/armeabi-v7a/libunity.so
lib/arm64-v8a/libmain.so
lib/arm64-v8a/libmono.so
lib/arm64-v8a/libunity.so

请注意,此示例中存在 armeabi-v7a 库和 arm64-v8a 库,这表明该应用支持 64 位架构。

1.3 如何使用64位库构建应用

1.3.1 使用Android Studio或Gradle 进行构建

大多数Android Studio项目都使用Gradle作为底层构建系统,因此本部分适用于使用这两种工具进行构建的情况。针对原生代码进行构建很简单,只需将arm64-v8a 和/或 x86_64(视您要支持的架构而定)添加到应用

“build.gradle”文件中的 ndk.abiFilters 设置中即可:

// Your app's build.gradle
apply plugin: 'com.android.app'

android {
  compileSdkVersion 27
  defaultConfig {
      appId "com.google.example.64bit"
      minSdkVersion 15
      targetSdkVersion 28
      versionCode 1
      versionName "1.0"
      ndk.abiFilters 'armeabi-v7a','arm64-v8a','x86','x86_64'
// ...

1.3.2 使用CMake进行构建

如果您的应用是使用CMake构建的,那么您可以通过将 arm64-v8a 传递到“-DANDROID_ABI”参数来针对 64 位 ABI 进行构建:

    > cmake -DANDROID_ABI=arm64-v8a … or
   > cmake -DANDROID_ABI=x86_64 …

    在使用externalNativeBuild 时,此方法无效。请参阅使用Gradle进行构建部分。

1.3.3 使用ndk-build 进行构建

如果您的应用是使用 ndk-build 构建的,那么您可以使用 APP_ABI 变量修改“Application.mk”文件,从而针对 64 位 ABI 进行构建:

    APP_ABI := armeabi-v7a arm64-v8a x86 x86_64

在使用 externalNativeBuild 时,此方法无效。请参阅使用 Gradle 进行构建部分。

1.3.4 将32位代码移植到 64 位架构

如果您的代码已经可以在桌面或 iOS 平台上运行,那么您无需针对 Android 做额外的工作。如果这是第一次针对 64 位系统构建您的代码,那么您需要解决的主要问题是指针不再适合 int 这样的 32 位整数类型。您将需要更新以 int、unsigned 或 uint32_t 等类型存储指针的代码。在 Unix 系统上,long 对应的是指针大小,但在 Windows 上并非如此,因此您应该改用释意类型 uintptr_t 或 intptr_t。使用 ptrdiff_t 类型来存储两个指针之间的差异。

您应该始终选择使用 <stdint.h> 中定义的特定固定宽度整数类型,而不是 int 或 long 等传统类型,即便对于非指针也应如此。

使用以下编译器标记来捕捉代码在指针和整数之间转换不正确的情况:

    -Werror=pointer-to-int-cast
   -Werror=int-to-pointer-cast
   -Werror=shorten-64-to-32、

具有 int 字段(包含指向 C/C++ 对象的指针)的 Java 类也有同样的问题。在 JNI 源代码中搜索 jint,并确保切换到 long(Java 端)和 jlong(C++ 端)。

注意:因指针被截断而引起的崩溃将表现为 SIGSEGV,其中错误地址的前 32 位全部为零。

对于 64 位代码而言,隐式函数声明的危险性要高得多。C/C++ 假定隐式声明的函数(即编译器未检测到声明的函数)的返回值类型为 int。如果函数的实际返回值类型是指针,那么在 32 位系统上是可行的,因为在 32 位系统中指针的类型为 int,但在 64 位系统中,编译器会丢弃指针的前半部分。例如:

// This function returns a pointer:
// extern char* foo();

// If you don't include a header that declares it,
// when the compiler sees this:
char* result = foo();

// Instead of compiling that to:
result = foo();

// It compiles to something equivalent to:
result = foo() & 0xffffffff;

// Which will then cause a SIGSEGV if you try to dereference `result`.

以下编译器标记会将隐式函数声明警告变成错误,以便您能够更轻松地查找和解决此问题:-Werror=implicit-function-declaration

如果您有内联汇编程序,您需要重新编写该程序或使用普通的 C/C++ 实现。

如果您对类型大小进行了硬编码(例如,8 或 16 字节),请使用等效的 sizeof(T) 表达式(例如 sizeof(void*))来替换它们。

如果需要有条件地编译不同于 64 位的 32 位代码,则对于一般性的 32/64 差异,您可以使用 #if defined(__LP64__);对于 Android 支持的具体架构,可以使用 __arm__、__aarch64__ (arm64)、__i386__ (x86) 和 __x86_64__。

您需要调整类似 printf 或 scanf 的函数的格式字符串,因为如果使用传统的格式说明符,您无法以一种对 32 位和 64 位设备都正确的方式来指定 64 位类型。您可利用 <inttypes.h> 中的 PRI 和 SCN 宏来解决此问题,PRIxPTR 和 SCNxPTR 分别用于写入/读取十六进制指针,PRId64 和 SCNd64 分别用于以可移植的方式写入/读取 64 位值。

在移位时,您可能需要使用 1ULL 来获取要移位的 64 位常数,而不能使用仅支持 32 位的 1。

1.3.5 利用 Android App Bundle 减少大小增加量

为您的应用添加 64 位架构支持可能会导致 APK 的大小增加。我们强烈建议您利用 Android APP Bundle 功能,以尽量减小因在同一 APK 中同时包含 32 位和 64 位原生代码而对 APK 大小产生的影响。

实际上,将应用改为使用 Android App Bundle 可以缩减 APK 的大小,使其比现在更小。

1.3.6 游戏开发者

我们知道,迁移第三方游戏引擎是一个耗费人力的过程,并且需要很长的准备时间。庆幸的是,三大最常用的引擎目前都支持 64 位架构:

  • Unreal(自 2015 年起)
  • Cocos2d(自 2015 年起)
  • Unity(自 2018 年起)

1.3.7 Unity开发者

升级到支持的版本

Unity 自版本 2018.2 和 2017.4.16 开始提供 64 位支持。

如果您发现自己使用的Unity版本不支持64位架构,请确定要升级到的版本,并按照Unity提供的指南迁移您的环境,确保将您的应用升级到可构建 64位库的版本。Unity建议您升级到该编辑器的最新LTS版本,以获取最新的功能和更新。

下面的图表概述了Unity 的各个版本以及您应该采取的措施:

更改构建设置以输出 64 位库

如果您使用的 Unity 版本支持 64 位的 Android 库,那么您可以通过调整构建设置来生成 64 位版本的应用。您还需要使用 IL2CPP 后端作为 Scripting Backend(详见此处)。要为构建 64 位架构而设置 Unity 项目,请按以下步骤操作:

1.转到 Build Settings,然后确认 Unity 标志是否显示在 Platform 下的 Android 旁边,以确保您是在针对 Android 进行构建。

   a.如果 Unity 标志未显示在 Android 平台旁边,请选择 Android,然后点击 Switch Platform。

2.点击 Player Settings。

3.依次转到 Player Settings Panel > Settings for Android > Other Settings > Configuration

4.将 Scripting Backend 设为 IL2CPP。

5.依次选择 Target Architecture > ARM64 复选框。

照常构建!

请注意,针对ARM64进行构建需要您专门针对该平台构建您的所有资产。请按照 Unity 的指南来缩减 APK 大小,同时考虑利用 Android App Bundle 功能来减小大小增加量。

1.4 应用64位合规性检验

1.4.1 合并 APK 和 64 位合规性

如果您要使用 Google Play 的合并 APK 支持来发布应用,请注意在版本层面评估是否符合 64 位要求。不过,如果 APK 或 app bundle 不会分发给搭载 Android 9 Pie 或更高版本的设备,则不适用 64 位要求。

如果您的某个 APK 被标记为不合规,但该 APK 比较老旧且无法使其合规,一种策略是在该 APK 清单的 uses-sdk 元素中添加 maxSdkVersion=”27″ 属性。这样一来,此 APK 将不会被分发给搭载 Android 9 Pie 或更高版本的设备,因而也就不会再妨碍合规。

1.4.2 RenderScript和64位合规性

如果您的应用使用 RenderScript 并且是通过较低版本的 Android 工具构建的,该应用可能会存在 64 位合规性问题。使用版本低于 21.0.0 的构建工具时,编译器可能会将生成的位码放到外部 .bc 文件中。64 位架构不再支持这些旧的 .bc 文件,因此,如果您的APK 中有这类文件,就会造成合规性问题。

要解决此问题,请移除项目中的所有 .bc 文件,将环境升级到 build-tools-21.0.0 或更高版本,并将 Android Studio 中的 renderscriptTargetApi 设为 21+,以指示编译器不要生成 .bc 文件。然后,重新构建您的应用,检查是否有 .bc 文件,再将应用上传到 Play 管理中心。

二、64位应用测试

1.1 vivo远程真机调试

vivo云测平台提供Android 5.1及以后的部分真机调试,开发者可以直接通过以下链接进入远程真机进行试用体验:https://vcl.vivo.com.cn/#/home/index

vivo Android 7.0以后的大部分机器支持64位。

1.2 在64位设备上测试应用

64 位版本的应用应提供与 32 位版本相同的质量和功能集。请对您的应用进行测试,以确保使用最新的 64 位设备的用户能够在您的应用中获得优质的体验。

最简单的 APK 测试方法就是使用 adb 安装该应用。大多数情况下,您可以提供 –abi 作为参数,用以指示要将哪些库安装到设备上。这样在设备上安装该应用时便会仅包含 64 位库。

# A successful install:
> adb install --abi armeabi-v7a YOUR_APK_FILE.apk
Success

# If your APK does not have the 64-bit libraries:
> adb install --abi arm64-v8a YOUR_APK_FILE.apk
adb: failed to install YOUR_APK_FILE.apk: Failure [INSTALL_FAILED_NO_MATCHING_ABIS: Failed to extract native libraries, res=-113]

# If your device does not support 64-bit, an emulator, for example:
> adb install --abi arm64-v8a YOUR_APK_FILE.apk
ABI arm64-v8a not supported on this device

安装成功后,请照常对应用进行测试,以确保其质量与 32 位版本相同。

三、64位应用发布

如果您觉得应用已准备妥当,请照常发布。与往常一样,请继续遵循部署应用的最佳做法。也务必要先在支持 64 位的设备上进行全面测试,然后再面向更广泛的受众群体发布。

四、参考链接

(1)Google指南:支持64位架构

https://developer.android.com/distribute/best-practices/develop/64-bit?hl=zh-cn

(2) 64-bit and Data Size Neutrality

https://unix.org/whitepapers/64bit.html

(3)20 issues of porting C++ code on the 64-bit platform

https://pvs-studio.com/en/a/0004/

OPPO开放平台APP多包上传教程

OPPO开放平台APP多包上传教程

业务介绍

1、能力介绍:多包发布能力可实现为应用发布多个不同的APK,每个APK针对不同的设备CPU架构下发。
2、包体介绍:每个APK都是完整、独立的应用版本,且需共享相同的软件名称、使用相同的发布密钥进行签名。

典型应用场景

支持不同的CPU架构,分别为32位、64位。通过在不同架构设备上提供不同版本,可实现减小包体体积,一般对低端机提供32位版本,对主流机型提供64位版本优化内存使用问题。适用于对不同设备提供差异化功能的开发者。

上传多包流程

1)登录OPPO开放平台开发者帐号,进入管理中心→应用服务平台→移动应用列表→应用详情页,点击“多CPU包能力”。


2)仔细阅读操作须知,然后点击“使用多CPU包上传能力”,弹框中点击“确定”。

3)进入发布应用或版本升级页面,按照提示分别上传32位和64位APK包。

4)如需从多包上传转换为普通包上传,请进入应用详情页→多CPU包能力→使用普通包上传能力。后续转换能力需要联系在线客服并由人工审核,请慎重操作

使用限制

1)软件包名和签名必须一致;

2)支持拆分维度:CPU架构;

3)多包应用的软件包作为整体发布,所有包审核通过才通过;

4)新版本上架后,上一版本所有软件包下架;

5)新增或更新多包时,32位包版本号≤64位包版本号。

FAQ

1)什么是32/64位兼容安装包?
A:32/64位兼容安装包指既能支持32位手机系统又同时支持64位手机系统的安装包。

2)同时上传32/64位安装包需要注意什么?

A:同时上传32位、64位安装包需要在多包入口进行上传,且需要保障32位、64位安装包包名、签名一致,同时32位包版本号≤64位包版本号,软件商店会对两个包体独立进行审核。具体操作详见多包上传流程。

3)适配后,用户在软件商店搜索是否会出现2个同样的应用?

A:双包上传后,用户不会在软件商店搜索到2个同样的应用,商店对每个APK会针对不同的设备CPU架构进行下发,即32位应用下发32位CPU架构设备,64位应用下发64位CPU架构设备。

4)若应用仅支持64位包,如何操作?

A:若为第一次在软件商店上传该应用,则暂不支持64位包;若非第一次在软件商店上传该应用,则走多包上传入口,仅传64位包即可。为保障用户体验,建议提供32位CPU架构用户可使用的包。

5)若使用多包后,后续不想用多包能力进行上传了怎么操作?

A:在多包上传界面有申请转普通包上传的入口,第一次申请无需审核,可秒转普通包上传;第二次及以后申请变为多包上传需走申请,申请通过后方可再变换上传方式。

小米开放平台32/64分包上传说明

应用32/64位安装包上传须知

1、目的

为更好地提升APP性能体验,降低APP功耗影响,同时保证APP在手机上的运行效率和兼容性;小米应用商店将针对不同机型下发合适的包体,推进国内安卓生态对64位架构的支持。

开发者可以在了解本文档描述的规则后,选择适合您的传包模式。

2、安装包要求

  • 同一应用的包名、应用名称、签名需相同,每种安装包为独立且完整的apk文件;
  • 双包应用上传或更新时,需保证双包同时审核通过才可上线;
  • 双包上传时,两个包体的md5值不能相同;
  • 支持从cpu架构维度拆分。

3、单包上传规则

  • 2022年5月6日后新上传的应用,单包上传入口仅支持上传32/64位兼容包和64位架构包,不支持32位架构包;
  • 2022年5月6日前的在架包更新时,单包上传入口支持上传32位、64位安装包或32/64位兼容包。

:“单包上传”的32位架构包入口,仅为给开发者提供过渡期选择,近期将会关闭。为避免应用分发受影响,建议开发者尽快完成64位适配。

4、双包上传规则

  • 首次使用“双包上传”,或从“单包上传”更换为“双包上传”时:必须同时上传32位、64位架构包;
  • 双包同时上传时,两个包体的versioncode需保持一致,且两个包体需要同时审核通过后才可上架。

操作方法/路径

1、应用创建

1.1 登录小米应用商店开发者站官网,点击“创建应用”,开始应用首次创建。

图:创建应用

1.2 进入创建应用页面,在此页面您需要填写语言、操作系统、应用名称、应用包名等信息(注:后续应用创建流程请参考应用创建操作指南)。

图:输入应用基本信息

1.3 创建包名后,进入到完善资料页,完成应用安装包的上传,在该页面可选择APK上传方式为“单包上传”或“双包上传”。

  • 单包上传:支持上传64位安装包或32/64位兼容包;
  • 双包上传:需同时上传32位和64位两个安装包。
图:选择上传安装包类型

如果您选择的是单包上传,目前不支持上传32位安装包。当上传的apk包是32位时,会出现弹窗错误提示并同时清空上传的安装包。

图:单包上传32位安装包错误提示

2、应用更新

2.1 进入应用管理界面,点击“管理”按钮进入应用详情页。

图:管理应用

2.2 点击应用详情页“更新版本”按钮,进入完善资料-测试审核-发布上线的流程。

图:版本更新

2.3 根据您的安装包适配情况上传新的应用安装包。

  • 单包上传:支持上传32位、64位安装包或32/64位兼容包;
  • 双包上传:需同时上传32位和64位两个安装包。
图:选择上传安装包类型

2.4 应用更新后续流程请参考应用更新、修改操作指南

应用适配常见问题

1、应用如何适配64位,是否有适配技术文档?

A:请参考小米应用商店支持 64 位架构适配文档

2、什么是32/64位兼容安装包?

A:32/64位兼容安装包指既能支持32位手机系统又同时支持64位手机系统的安装包。

3、同时上传32/64位安装包需要注意什么?

A:同时上传32位、64位安装包需要在正确入口进行上传,且需要保障32位、64位安装包包名、版本、签名一致,应用商店会对两个包体同时进行审核。

4、32/64位双包上传,是否会影响原广告账号投放?

A:不会影响原广告账号投放。

5、适配后,用户在应用商店搜索是否会出现2个同样的应用?

A:双包上传后,用户不会在小米应用商店搜索到2个同样的应用,商店对每个APK会针对不同的设备CPU架构进行下发,即32位应用下发32位CPU架构设备,64位应用下发64位CPU架构设备。

6、除包体适配外,是否还需其他材料适配?

A:仅需做64位应用包体适配,无需重新制作其他物料。

以上是应用32/64位安装包上传的相关内容,如您仍有问题,可进入问题工单系统,与我们取得联系。