/
支持 64 位架构
自 2019 年 8 月 1 日起,您在 Google Play 上发布的应用必须支持 64 位架构。 64 位 CPU 能够为您的用户提供更快、更丰富的体验。添加 64 位的应用版本不仅可以提升性能、为未来创新创造条件,还能针对仅支持 64 位架构的设备做好准备。
本指南介绍了如何确保 32 位应用为支持 64 位设备做好准备,供您随时采用。
评估您的应用
如果您的应用仅使用以 Java 编程语言或 Kotlin 编写的代码(包括所有库或 SDK),那么就表示该应用已经能支持 64 位设备。如果您的应用使用了任何原生代码,或者您不确定应用是否使用了这类代码,那么您需要评估应用并采取措施。
快速状态检查
要检查应用是否已满足 64 位要求,一种便捷的方法是前往 Play 管理中心查看现有的版本,确定应用是否合规:
如果您的草稿版本存在与 64 位要求相关的问题,Play 管理中心也会显示相应的警告。请看以下示例:
如果您看到提醒,请按照提醒下面的步骤操作,让应用做好支持 64 位的准备。
您的应用是否使用了原生代码?
首先需要检查您的应用是否使用了任何原生代码。 如果您的应用符合以下情况,便是使用了原生代码:
- 使用了任何 C/C++(原生)代码。
- 与任何第三方原生库关联。
- 通过使用原生库的第三方应用构建程序构建而成。
应用是否包含 64 位库?
若要确定应用是否包含 64 位库,最简单的方法就是检查 APK 文件的结构。在构建时,APK 会与应用所需的所有原生库打包在一起。原生库会根据 ABI 存储在不同的文件夹中。您的应用不一定要支持所有 64 位架构,但对于支持的每种原生 32 位架构,应用都必须包含相应的 64 位架构。
对于 ARM 架构,32 位库位于 armeabi-v7a 中。 对应的 64 位库则位于 arm64-v8a 中。
对于 x86 架构,32 位库位于 x86 中,64 位库则位于 x86_64 中。
首先要确保这两个文件夹中都有原生库。总结如下:
平台 | 32 位库文件夹 | 64 位库文件夹 |
---|---|---|
ARM | lib/armeabi-v7a | lib/arm64-v8a |
x86 | lib/x86 | lib/x86_64 |
请注意,每个文件夹中的一套库可能完全相同,也可能不完全相同,这取决于应用的具体情况。您应达到的目标是确保您的应用能够在仅支持 64 位架构的环境中正常运行。
通常情况下,同时针对 32 位和 64 位架构构建的 APK 或软件包会具有这两种 ABI 的文件夹,每个文件夹中都有一套相应的原生库。如果您的应用不支持 64 位架构,那么您很可能会看到 32 位 ABI 文件夹,但没有 64 位文件夹。
使用 APK 分析器查找原生库
APK 分析器是一款可用于对所构建的 APK 进行各方面评估的工具。针对我们目前所讨论的情况,我们将使用该工具查找原生库,以确定是否具备 64 位库。
- 打开 Android Studio,然后打开任一项目。
-
从菜单中依次选择 Build > Analyze APK…
-
选择您要评估的 APK。
-
查看 lib 文件夹,您可以在其中找到“.so”文件。如果在您的应用中找不到任何“.so”文件,则说明该应用已支持 64 位架构,您无需采取进一步措施。如果您看到 armeabi-v7a 或 x86,则说明您有 32 位库。
-
检查是否 arm64-v8a 或 x86_64 文件夹中有类似的“.so”文件。
-
如果您没有任何 arm64-v8a 或 x86_64 库,则需要更新构建流程以开始构建并打包 APK 中的这些工件。
-
如果您看到 32 位和 64 位的库均已打包到软件包中,则可以跳至在 64 位硬件上测试应用。
通过解压缩 APK 查找原生库
APK 文件的结构类似于 ZIP 文件,可以像 ZIP 文件一样解压缩。 如果您更喜欢使用命令行或任何其他解压缩工具,也可以采用解压缩 APK 的方法。
只需解压缩 APK 文件(根据您使用的解压缩工具,您可能需要将其重命名为 .zip),然后按照上文中的指南浏览解压缩后的文件,即可确定您的应用是否已经为支持 64 位设备做好准备了。
例如,您可以从命令行中运行如下命令:
:: Command Line
> 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 位架构。
使用 64 位库构建应用
下面针对构建 64 位库做出了相关的说明。不过,需要指出的是,以下内容仅介绍了如何构建在源代码的基础上可构建的代码和库。
如果您使用任何外部 SDK 或库,请确保按照上文所述的步骤使用 64 位版本。如果没有 64 位版本可用,请与相应 SDK 或库的所有者联系,并在规划支持 64 位设备的方案时将这一点考虑在内。
使用 Android Studio 或 Gradle 进行构建
大多数 Android Studio 项目都使用 Gradle 作为底层构建系统,因此本部分适用于使用这两种工具进行构建的情况。针对原生代码进行构建很简单,只需将 arm64-v8a 和/或 x86_64(视您要支持的架构而定)添加到应用的“build.gradle”文件中的 ndk.abiFilters 设置中即可:
// Your app's build.gradle plugins { id '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' // ...
使用 CMake 进行构建
如果您的应用是使用 CMake 构建的,那么您可以通过将 arm64-v8a 传递到“-DANDROID_ABI”参数来针对 64 位 ABI 进行构建:
:: Command Line
> cmake -DANDROID_ABI=arm64-v8a … or
> cmake -DANDROID_ABI=x86_64 …
在使用 externalNativeBuild
时,此方法无效。请参阅使用 Gradle 进行构建部分。
使用 ndk-build 进行构建
如果您的应用是使用 ndk-build 构建的,那么您可以使用 APP_ABI
变量修改“Application.mk”文件,从而针对 64 位 ABI 进行构建:
APP_ABI := armeabi-v7a arm64-v8a x86 x86_64
在使用 externalNativeBuild
时,此方法无效。请参阅使用 Gradle 进行构建部分。
将 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
。
利用 Android App Bundle 减少大小增加量
为您的应用添加 64 位架构支持可能会导致 APK 的大小增加。我们强烈建议您利用 Android APP Bundle 功能,以尽量减小因在同一 APK 中同时包含 32 位和 64 位原生代码而对 APK 大小产生的影响。
实际上,将应用改为使用 Android App Bundle 可以缩减 APK 的大小,使其比现在更小。
游戏开发者
我们知道,迁移第三方游戏引擎是一个耗费人力的过程,并且需要很长的准备时间。庆幸的是,三大最常用的引擎目前都支持 64 位架构:
- Unreal(自 2015 年起)
- Cocos2d(自 2015 年起)
- Unity(自 2018 年起)
Unity 开发者
升级到支持的版本
Unity 自版本 2018.2 和 2017.4.16 开始提供 64 位支持。
如果您发现自己使用的 Unity 版本不支持 64 位架构,请确定要升级到的版本,并按照 Unity 提供的指南迁移您的环境,确保将您的应用升级到可构建 64 位库的版本。Unity 建议您升级到该编辑器的最新 LTS 版本,以获取最新的功能和更新。
下面的图表概述了 Unity 的各个版本以及您应该采取的措施:
Unity 版本 | 版本是否支持 64 位? | 建议采取的措施 |
---|---|---|
2020.x | ✔️ | 确保您的构建设置能够输出 64 位库。 |
2019.x | ✔️ | 确保您的构建设置能够输出 64 位库。 |
2018.4 (LTS) | ✔️ | 确保您的构建设置能够输出 64 位库。 |
2018.3 | ✔️ | 确保您的构建设置能够输出 64 位库。 |
2018.2 | ✔️ | 确保您的构建设置能够输出 64 位库。 |
2018.1 | ➖ | 提供实验性的 64 位支持。 |
2017.4 (LTS) | ✔️ | 自 2017.4.16 开始支持。 确保您的构建设置能够输出 64 位库。 |
2017.3 | ✖️ | 升级到支持 64 位的版本。 |
2017.2 | ✖️ | 升级到支持 64 位的版本。 |
2017.1 | ✖️ | 升级到支持 64 位的版本。 |
<=5.6 | ✖️ | 升级到支持 64 位的版本。 |
更改构建设置以输出 64 位库
如果您使用的 Unity 版本支持 64 位的 Android 库,那么您可以通过调整构建设置来生成 64 位版本的应用。您还需要使用 IL2CPP 后端作为 Scripting Backend(详见此处)。要为构建 64 位架构而设置 Unity 项目,请按以下步骤操作:
- 转到 Build Settings,然后确认 Unity 标志是否显示在 Platform 下的 Android 旁边,以确保您是在针对 Android 进行构建。
- 如果 Unity 标志未显示在 Android 平台旁边,请选择 Android,然后点击 Switch Platform。
-
点击 Player Settings。
-
依次转到 Player Settings Panel > Settings for Android > Other Settings > Configuration
-
将 Scripting Backend 设为 IL2CPP。
-
依次选择 Target Architecture > ARM64 复选框。
-
照常构建!
请注意,针对 ARM64 进行构建需要您专门针对该平台构建您的所有资产。请按照 Unity 的指南来缩减 APK 大小,同时考虑利用 Android App Bundle 功能来减小大小增加量。
合并 APK 和 64 位合规性
如果您要使用 Google Play 的合并 APK 支持来发布应用,请注意在版本层面评估是否符合 64 位要求。不过,如果 APK 或 app bundle 不会分发给搭载 Android 9 Pie 或更高版本的设备,则不适用 64 位要求。
如果您的某个 APK 被标记为不合规,但该 APK 比较老旧且无法使其合规,一种策略是在该 APK 清单的 uses-sdk
元素中添加 maxSdkVersion="27"
属性。这样一来,此 APK 将不会被分发给搭载 Android 9 Pie 或更高版本的设备,因而也就不会再妨碍合规。
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 位硬件上测试应用
64 位版本的应用应提供与 32 位版本相同的质量和功能集。请对您的应用进行测试,以确保使用最新的 64 位设备的用户能够在您的应用中获得优质的体验。
要开始测试您的应用,您要有支持 64 位架构的设备。时下有很多支持 64 位架构的热门设备,例如 Google 的 Pixel 以及其他旗舰设备。
最简单的 APK 测试方法就是使用 adb 安装该应用。大多数情况下,您可以提供 --abi
作为参数,用以指示要将哪些库安装到设备上。这样在设备上安装该应用时便会仅包含 64 位库。
:: Command Line
# 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 位的设备上进行全面测试,然后再面向更广泛的受众群体发布。
相关内容
BLOG
Moving Android Studio and Android Emulator to 64-bit versions
With Project Marble, the Android Studio team focused our efforts on making the fundamental features and flows of the Integrated Development Environment (IDE) rock-solid. Performance is an underlying tenant to delivering a high quality IDE. To this
BLOG
Get your apps ready for the 64-bit requirement
Starting August 1, 2019:
/
为所有屏幕开发游戏
在为 Android 开发游戏时,重要的是要预测各种可能的玩家体验并保持适应玩家的实时交互需求。通过支持不同的玩家体验,您可以增加游戏的灵活性,帮助您扩大游戏的影响范围。
玩家体验的具体差异包括以下内容:
- 设备外形:虽然手机提供了传统的 Android 设备体验,但也可以与其他外形的游戏进行交互。Chrome OS 设备可以运行一个 Android 容器来显示您的游戏。可以运行 Android 的平板电脑支持多个不同级别的保真度。Android TV 设备支持细节更丰富、更身临其境的体验。玩家可以使用显示扩展工具模拟多窗口环境。在使用可折叠设备时,玩家可以在游戏过程中更改屏幕大小。
- 交互方式:玩家可以通过触摸设备的屏幕来提供输入,但他们也可以使用鼠标、触摸板、键盘或控制器来代替。此外,显示扩展工具和可折叠设备的可用性允许玩家在更大的屏幕上体验您的游戏,从而使更长的游戏会话和更复杂的界面更加可行。
- 硬件支持:一些基于 Android 的设备没有手持设备中更典型的硬件,例如后置摄像头、GPS 和网络连接。您的游戏应该适应可用的硬件,并优雅地处理某些功能不可用的情况。
本指南介绍了与为不同类型的屏幕和用户交互开发游戏相关的最佳实践。本指南还提供有关设计游戏和制定有效测试策略的建议。
游戏设计最佳实践
在规划游戏的设计和架构时,请遵循以下部分中描述的最佳实践。
手动响应配置更改
当 Android 系统检测到配置变化时,例如屏幕大小、屏幕方向或输入法的变化,系统默认重启当前活动。为了在应用程序或游戏中保留状态,活动默认 onSaveInstanceState() 在重新启动之前和重新启动 onRestoreInstanceState() 之后调用。但是,此过程需要活动重新加载所有关联的服务和资源。要了解有关此默认行为的更多信息, 请参阅处理配置更改指南。
一个典型的游戏会话会经历几个配置更改。如果您的游戏让系统处理每个配置更改,您的游戏场景就会被破坏并一遍又一遍地重新启动,从而降低游戏的性能。因此,我们强烈建议您在游戏中自行处理这些配置更改。
要了解如何将此配置更改逻辑添加到您的游戏中,请参阅有关如何创建自定义配置更改处理程序的部分。
创建灵活的架构
要在尽可能多的设备上添加对您的游戏的支持,请遵循以下最佳做法:
- 部署 Android App Bundle 而不是单独的 APK。 Android App Bundle允许您将不同分辨率和不同架构模型(例如 x86、ARM)的工件打包到单个工件中。更好的是,Android App Bundles 支持更高的游戏大小限制;每个基本 APK 可以大到 150 MB,而捆绑包本身可以有很多 GB。
- 添加对 x86 架构的支持。此步骤可提高您的游戏在不支持 ARM 的设备上的性能,因为这些设备现在可以执行指令而无需先翻译它们。
添加对 Vulkan 的支持
通过支持Vulkan,您的游戏可以获得更高的图形性能。大多数设备都支持此图形 API。
创建自定义配置更改处理程序
要声明游戏自行处理的配置更改类型,请将android:configChanges 属性添加到<activity>
清单中表示屏幕或复杂界面的每个元素。
以下代码片段演示了如何声明您的游戏负责屏幕大小、屏幕方向和输入法更改:
<span style="color:var(--devsite-code-color)"><span style="color:var(--devsite-code-keywords-color)"><activity</span> ...
<strong><span style="color:var(--devsite-code-types-color)">android:configChanges</span>=<span style="color:var(--devsite-code-strings-color)">"screenSize|orientation|keyboard|keyboardHidden"</span></strong><span style="color:var(--devsite-code-keywords-color)">></span>
<span style="color:var(--devsite-code-keywords-color)"></activity></span>
</span>
当声明的配置更改发生时,系统现在调用不同的方法, onConfigurationChanged(). 在此方法中,添加更新游戏 UI 的逻辑:
- 更新屏幕的比例因子和方向。请记住,出于性能目的,有时最好只在一个维度上缩放游戏的 UI。
- 确定玩家使用的最佳输入法。
处理屏幕配置更改
只要您在 属性中分别 包含screenSize
和值,您的游戏就会手动处理屏幕大小和屏幕方向的更改。您可以使用这些新值来更新场景的内容和玩家输入区域。有关如何设计游戏布局以使其更易于更新的指导,请参阅支持不同屏幕尺寸的指南。orientation
android:configChanges
在您的游戏实现中onConfigurationChanged()
,使用传入的 Configuration对象和窗口管理器的Display对象分别确定屏幕大小和屏幕方向的更新值。
注意:显示器的旋转值取决于设备的默认硬件方向。因此,值0
表示某些设备上的纵向和其他设备上的横向。
以下代码片段显示了如何获取游戏更新后的屏幕尺寸和方向:
override fun onConfigurationChanged(newConfig: Configuration) { super.onConfigurationChanged(newConfig) val density: Float = resources.displayMetrics.density val newScreenWidthPixels = (newConfig.screenWidthDp * density).toInt() val newScreenHeightPixels = (newConfig.screenHeightDp * density).toInt() // Get general orientation; either Configuration.ORIENTATION_PORTRAIT or // Configuration.ORIENTATION_LANDSCAPE. val newScreenOrientation: Int = newConfig.orientation // Get general rotation; one of: ROTATION_0, ROTATION_90, ROTATION_180, // or ROTATION_270. val newScreenRotation: Int = windowManager.defaultDisplay.rotation }
请注意,即使您的应用在全屏模式下运行,更改可折叠设备的姿势也会更改配置。因此,如果用户在游戏运行时折叠或展开设备,您的应用程序可能必须处理屏幕尺寸或像素密度的变化。
特定于游戏的屏幕质量
以下部分描述了如何根据游戏质量调整游戏对屏幕尺寸或屏幕方向变化的反应:
全屏模式
在某些平台上,例如 Chrome OS,Android 应用程序和游戏默认可以窗口化和调整大小。如果您的游戏应始终以全屏模式运行,您可以将 android:resizeableActivity 属性设置false
为您的<activity>
元素之一,如以下代码片段所示:
<span style="color:var(--devsite-code-color)"><span style="color:var(--devsite-code-keywords-color)"><activity</span> ...
<strong><span style="color:var(--devsite-code-types-color)">android:resizeableActivity</span>=<span style="color:var(--devsite-code-strings-color)">"false"</span></strong><span style="color:var(--devsite-code-keywords-color)">></span>
<span style="color:var(--devsite-code-keywords-color)"></activity></span>
</span>
注意:该android:resizeableActivity
属性仅在运行 Android 7.0(API 级别 24)或更高版本的设备上影响您的游戏。
您还可以将android:resizeableActivity
属性设置为false
以防止发生基于大小的配置更改。但是,除非您的游戏始终以全屏模式运行,否则您应该将此属性添加为仅用于测试目的的临时修复。
屏幕方向
如果您的游戏依赖于具有特定方向的设备传感器, android:screenOrientation请在游戏的活动中指定一个值,如以下代码片段所示。此设置有助于防止游戏中的场景意外颠倒。
<span style="color:var(--devsite-code-color)"><span style="color:var(--devsite-code-keywords-color)"><activity</span> ...
<strong><span style="color:var(--devsite-code-types-color)">android:screenOrientation</span>=<span style="color:var(--devsite-code-strings-color)">"landscape"</span></strong><span style="color:var(--devsite-code-keywords-color)">></span>
<span style="color:var(--devsite-code-keywords-color)"></activity></span>
</span>
设备特定的屏幕质量
以下部分描述了如何处理给定某些设备具有的特定品质的基于屏幕的配置更改。
纵横比
一些设备支持不同的纵横比。例如,可折叠设备设计为在折叠状态下支持 21:9 的纵横比。要处理这种潜在的纵横比变化,请至少执行以下操作之一:
- 面向 Android 8.0(API 级别 26)或更高版本。
- 使您的游戏场景和界面可调整大小。在运行 Android 7.0(API 级别 24)及更高版本的设备上设置 android:resizeableActivity 为。
true
-
声明支持的最大纵横比。在 <meta-data>与您的游戏关联的属性中,设置
android.max_aspect
为2.4
,如以下代码片段所示。但是请记住,大于您指定的宽高比会导致游戏在显示器中显示为 信箱 。<span style="color:var(--devsite-code-color)"><span style="color:var(--devsite-code-keywords-color)"><application></span> <strong><span style="color:var(--devsite-code-keywords-color)"><meta-data</span> <span style="color:var(--devsite-code-types-color)">android:name</span>=<span style="color:var(--devsite-code-strings-color)">"android.max_aspect"</span> <span style="color:var(--devsite-code-types-color)">android:value</span>=<span style="color:var(--devsite-code-strings-color)">"2.4"</span> <span style="color:var(--devsite-code-keywords-color)">/></span></strong> <span style="color:var(--devsite-code-keywords-color)"></application></span> </span>
多个活动同时可见
许多现代设备支持各种屏幕布局,包括分屏、画中画和大显示区域。当使用其中一种布局时,系统可以同时显示多个活动。
在运行 Android 9(API 级别 28)或更高版本的设备上,可以同时恢复所有最重要的可见活动。但是,为了使此行为起作用,您的游戏和设备的 OEM 都需要选择启用该功能。您可以通过在游戏清单中设置 android.allow_multiple_resumed_activities
为来true
在游戏中添加支持,如以下代码段所示:
<span style="color:var(--devsite-code-color)"><span style="color:var(--devsite-code-keywords-color)"><application></span>
<strong><span style="color:var(--devsite-code-keywords-color)"><meta-data</span> <span style="color:var(--devsite-code-types-color)">android:name</span>=<span style="color:var(--devsite-code-strings-color)">"android.allow_multiple_resumed_activities"</span>
<span style="color:var(--devsite-code-types-color)">android:value</span>=<span style="color:var(--devsite-code-strings-color)">"true"</span> <span style="color:var(--devsite-code-keywords-color)">/></span></strong>
<span style="color:var(--devsite-code-keywords-color)"></application></span>
</span>
然后,您可以在不同的设备上测试您的游戏,看看哪些设备提供了使多重恢复正常运行所需的 OEM 支持。
注意:如果没有您的游戏和设备 OEM 的支持,唯一恢复的活动是最近收到玩家输入的活动;所有其他可见活动都处于已启动或已暂停状态。
有关将游戏配置为多窗口显示的一部分的更多信息,请参阅有关如何添加多窗口支持的指南。
处理不同类型的交互模型
只要您在属性中分别 包含keyboard
和值,您的游戏就会手动处理键盘存在和键盘可用性 。您可以使用这些新值来更新游戏的主要输入法。keyboardHidden
android:configChanges
在配置您的游戏以支持多种类型的用户输入时,请记住以下几点:
- 检测输入法而不是单个设备。这种心态可以更轻松地改善玩家体验,而无需过多关注玩家可能拥有的特定设备。
keyboardHidden
在手动处理的配置更改列表中包含该属性。这样,您的游戏可以跟踪键盘何时物理连接到设备但无法使用。-
确定当前可用的输入法。为此,请 getInputDeviceIds() 在游戏启动时和每次配置更改后调用。
您通常可以根据玩家首选的输入设备确定玩家计划如何与您的游戏互动:
- 玩家通常使用键盘或游戏控制器来执行快速按钮序列。
- 玩家通常使用触摸屏或触摸板来执行更复杂的手势。
- 玩家通常使用鼠标来执行更高精度的输入。
注意:当玩家与您的游戏互动时,输入法的可用性可能会不稳定。例如,他们可能会在玩游戏时断开键盘并插入控制器。
以下部分提供了特定类型输入设备的最佳实践。
键盘
在为您的游戏创建键盘布局时,请考虑玩家如何在给定场景中导航以及他们如何与您的游戏设置进行交互。
WASD 键或箭头键通常最适合控制角色移动。最好为可控角色在游戏中可以执行的每个重要动作或技能分配一个特定的键。为了最大限度地提高玩家体验,请考虑在游戏中添加对自定义键绑定的支持。
玩家还应该能够打开游戏的菜单并使用键盘浏览它们。Esc
关键是用于暂停场景和显示游戏菜单的通用映射。
注意:即使玩家更频繁地使用鼠标或触摸板与您的游戏互动,添加键盘支持以作为具有辅助功能需求的玩家的替代输入方法也很重要。
有关在游戏中支持键盘输入的更多信息,请参阅如何支持键盘导航的指南以及如何处理键盘操作的指南。
游戏控制器
有关在游戏中处理控制器输入的更多信息,请参阅如何支持游戏控制器的指南。
鼠标或触摸板
如果您的游戏支持来自鼠标或触摸板的玩家输入,请记住玩家与设备的交互方式与玩游戏不同。请务必注意,通过请求指针捕获,所有鼠标输入都指向您的游戏。因此,在您的游戏获得所需信息后,释放指针捕获功能,以便玩家重新获得对其设备的标准鼠标控制。
在运行 Android 8.0(API 级别 26)及更高版本的设备上,您可以使用鼠标捕获 API 来协助指针捕获过程。在对高精度输入做出反应的游戏中,您可以通过调用getX()和 getY()方法获取指针的当前坐标。
有关在游戏中添加对鼠标输入和触摸板输入的支持的更多信息,请参阅有关如何跟踪触摸和指针移动的指南以及有关如何处理多点触控手势的指南。
测试你的游戏
在启动您的游戏之前,通过完成以下部分中描述的步骤来测试它如何响应配置更改。
更新您的测试计划
验证游戏功能时,请包括以下测试用例:
- 最小化和最大化包含您的游戏的窗口。(如果您的游戏始终处于全屏模式,则不适用。)
- 更改屏幕大小。
- 更改屏幕方向。(如果您的游戏有固定方向,则不适用。)
- 连接和断开输入设备,例如键盘和鼠标。
- 如果您的游戏支持,请执行多简历。
此外,请考虑更新游戏的质量控制系统,以便您可以针对更广泛的玩家体验进行优化。
有关测试游戏的最佳实践,请参阅测试基础指南。
使用测试和调试工具
您可以使用平台支持的各种工具执行测试:
-
模拟器,包括Android 模拟器和 Firebase 测试实验室。
-
系统跟踪。
-
Chrome OS Performance Analyzer,在运行 Chrome OS M75 或更高版本时可用。
游戏模式
游戏模式 API和 游戏模式干预允许您通过根据用户设置或游戏特定配置优先考虑特性(例如性能或电池寿命)来优化游戏玩法。
从Android 12开始,游戏模式 API 和干预措施可 在选定设备上使用。
使用游戏模式 API 进行优化
您可以使用Game Mode API来识别用户选择的当前游戏模式,然后根据他们的选择优化您的游戏以获得最佳性能或电池寿命。
了解如何设置、优化和发布您的游戏以支持标准、性能和电池模式。
游戏模式干预
游戏模式干预是原始设备制造商 (OEM) 设置的游戏特定优化,旨在提高开发人员不再更新的游戏的性能。
了解如何使用性能和电池模式为您的游戏设置、测试和提交干预措施。
重要提示:每个游戏都可以实现游戏模式 API 行为,向 OEM 建议游戏模式干预设置,或明确选择退出游戏模式干预。
警告:OEM 可以选择在没有开发人员反馈的情况下实施游戏模式干预。
游戏模式 API
当用户选择相应的游戏模式时,游戏模式 API 允许您优化游戏以获得最佳性能或最长的电池寿命。
或者,您可以提交 游戏模式干预请求,以提高开发人员不再更新的游戏的性能。
游戏模式 API 和干预可在部分 Android 12设备上使用。
重要提示:每个游戏都可以实现游戏模式 API 行为,向 OEM 建议游戏模式干预设置,或明确选择退出游戏模式干预。
警告:OEM 可以选择在没有开发人员反馈的情况下实施游戏模式干预。
设置
要在游戏中使用 Game Mode API,请执行以下操作:
-
下载并安装 Android 12 Preview SDK。
-
在AndroidManifest.xml文件中,通过设置元素appCategory中的属性将 您的应用声明为游戏 :<application>
<span style="color:var(--devsite-code-color)"><code>android:appCategory="game"
</code></span>
- 通过将其添加到您的主要活动来查询当前游戏模式:
// Only call this for Android 12 devices if ( Build.VERSION.SDK_INT >= Build.VERSION_CODES.S ) { // Get GameManager from SystemService GameManager gameManager = Context.getSystemService(GameManager.class); // Returns the selected GameMode int gameMode = gameManager.getGameMode(); }
支持的游戏模式 | 描述 |
---|---|
不支持 | 游戏未声明对游戏模式 API 的支持,也不支持游戏模式干预。 |
标准 | 用户没有选择游戏模式或用户选择了标准模式。 |
表现 | 提供最低的延迟帧速率,以换取电池寿命和保真度的降低。 |
电池 | 提供尽可能长的电池寿命,以换取降低的保真度或帧速率。 |
重要提示:省电模式是特定于游戏的,不会影响系统级 Android 省电模式的行为。
-
在onResume函数中添加查询游戏模式状态的代码 :
重要提示:在恢复暂停的进程时,您的应用程序必须始终查询 getGameMode() 方法。有关详细信息,请参见上图。
最佳实践
如果您的游戏已经支持多个保真度和帧速率目标,您应该确定性能和节电模式的适当设置:
-
要始终如一地实现最大设备帧速率:考虑稍微降低保真度以实现更高的帧速率。
-
要延长电池寿命:考虑选择较低的显示刷新率(例如 30Hz 或 60Hz)并使用帧步调来瞄准降低的刷新率。
对于第一人称射击游戏、多人在线战斗竞技场 (MOBA) 和角色扮演游戏 (RPG) 等高保真游戏,您应该专注于实现高一致的帧速率,以最大限度地提高用户沉浸感。
对于高保真游戏和休闲游戏,您应该支持省电模式,以通过降低峰值帧速率来延长游戏时间。
测试
通过 adb设置游戏模式状态来尝试新的游戏行为:
adb shell cmd game mode [standard|performance|battery] <PACKAGE_NAME>
出版
要启用游戏模式 UI,请将以下内容添加到 <application>AndroidManifest.xml 文件中的元素。
<span style="color:var(--devsite-code-color)"><code><span style="color:var(--devsite-code-keywords-color)"><application></span>
<span style="color:var(--devsite-code-comments-color)"><!-- default is false --></span>
<span style="color:var(--devsite-code-keywords-color)"><meta-data</span>
<span style="color:var(--devsite-code-types-color)">android:name</span>=<span style="color:var(--devsite-code-strings-color)">"com.android.app.gamemode.performance.enabled"</span>
<span style="color:var(--devsite-code-types-color)">android:value</span>=<span style="color:var(--devsite-code-strings-color)">"true"</span><span style="color:var(--devsite-code-keywords-color)">/></span>
<span style="color:var(--devsite-code-comments-color)"><!-- default is false --></span>
<span style="color:var(--devsite-code-keywords-color)"><meta-data</span>
<span style="color:var(--devsite-code-types-color)">android:name</span>=<span style="color:var(--devsite-code-strings-color)">"com.android.app.gamemode.battery.enabled"</span>
<span style="color:var(--devsite-code-types-color)">android:value</span>=<span style="color:var(--devsite-code-strings-color)">"true"</span><span style="color:var(--devsite-code-keywords-color)">/></span>
...
<span style="color:var(--devsite-code-keywords-color)"></application></span>
</code></span>
重要提示:游戏模式 UI 仅适用于部分 Android 12 设备,不适用于 Android 12 Beta 版本。
下一个
当无法提供游戏更新时,请阅读游戏模式干预以提高游戏性能。
//
游戏模式干预
游戏模式干预是原始设备制造商 (OEM) 设置的游戏特定优化,旨在提高开发人员不再更新的游戏的性能。例如:
- WindowManager 后备缓冲区调整大小。
- 使用 ANGLE 而不是本机 GLES 驱动程序。
或者,如果可以更新游戏,您可以使用 Game Mode API优化性能和电池。
游戏模式 API 和干预可在部分 Android 12设备上使用。
重要提示:每个游戏都可以实现游戏模式 API 行为,向 OEM 建议游戏模式干预设置,或明确选择退出游戏模式干预。
警告:OEM 可以选择在没有开发人员反馈的情况下实施游戏模式干预。
WindowManager 后台缓冲区调整大小
WindowManager backbuffer resize 干预可以减少设备的 GPU 负载。当游戏以目标帧速率进行时,它还可以减少电池消耗。
启用调整大小后,最多可降低 30% 的 GPU 功率和 10% 的系统功率。结果可能会因使用的设备、环境条件和其他因素(例如同时处理)而异。
受 GPU 限制的无节奏游戏可能会在减少 GPU 负载期间体验更高的帧速率。但是,我们强烈建议所有游戏都保持 良好的节奏,因为不均匀的帧速率会显着影响用户对性能的看法。
评估
要自行评估 WindowManager 后缓冲调整大小干预,请使用以下adb命令。90% 的调整大小几乎可以忽略不计,而 50% 则意义重大。
adb shell cmd game downscale [0.5|0.6|0.7|0.8|0.9|disable] <PACKAGE_NAME>
警告:在 Android 12 中,子进程的大小可能无法正确调整。应特别注意查看 toast/弹出窗口的 UI。或者,我们建议您将调整大小设置限制为 70%。
设置模式
您应该验证对性能和电池模式的干预,如下所述。
支持的游戏模式 | 描述 |
---|---|
表现 | 提供最低的延迟帧速率,以换取电池寿命和保真度的降低。 |
电池 | 提供尽可能长的电池寿命,以换取降低的保真度或帧速率。 |
要验证每种模式的干预, 请在AndroidManifest.xml文件中的<application>元素 下启用这些模式。
-
启用性能模式:
<span style="color:var(--devsite-code-color)"><code><span style="color:var(--devsite-code-comments-color)"><!-- default is false --></span> <span style="color:var(--devsite-code-keywords-color)"><meta-data</span> <span style="color:var(--devsite-code-types-color)">android:name</span>=<span style="color:var(--devsite-code-strings-color)">"com.android.app.gamemode.performance.enabled"</span> <span style="color:var(--devsite-code-types-color)">android:value</span>=<span style="color:var(--devsite-code-strings-color)">"true"</span><span style="color:var(--devsite-code-keywords-color)">/></span> </code></span>
-
启用电池模式:
<span style="color:var(--devsite-code-color)"><code><span style="color:var(--devsite-code-comments-color)"><!-- default is false --></span> <span style="color:var(--devsite-code-keywords-color)"><meta-data</span> <span style="color:var(--devsite-code-types-color)">android:name</span>=<span style="color:var(--devsite-code-strings-color)">"com.android.app.gamemode.battery.enabled"</span> <span style="color:var(--devsite-code-types-color)">android:value</span>=<span style="color:var(--devsite-code-strings-color)">"true"</span><span style="color:var(--devsite-code-keywords-color)">/></span> </code></span>
测试你的游戏
分配不同的调整大小值以查看您的游戏如何受到 WindowManager 后备缓冲区调整大小干预的影响:
adb shell device_config put game_overlay <PACKAGE_NAME>
mode=2,downscaleFactor=0.7:mode=3,downscaleFactor=0.8
重要提示:在上面的示例中,mode=2
是“性能”并且mode=3
是“省电模式”。该downscaleFactor
值指定为适用于调整大小设置的百分比(0.7 为 70%,0.8 为 80%)。
向 OEM 提交干预措施
对于 Android 12,每次干预都必须由设备 OEM 设置。 对于 Pixel 设备,请提交您的请求并提供以下信息:
-
游戏包名。
-
设备和型号详细信息。
-
请求模式的干预值。
退出干预
或者,您可以通过选择退出来控制是否对您的游戏应用干预。每个干预都有自己的退出设置。
-
要禁用 WindowManager 后缓冲调整大小干预,请将以下内容添加到<application> AndroidManifest.xml 文件中的元素。
<span style="color:var(--devsite-code-color)"><code><span style="color:var(--devsite-code-keywords-color)"><meta-data</span> <span style="color:var(--devsite-code-types-color)">android:name</span>=<span style="color:var(--devsite-code-strings-color)">"com.android.graphics.intervention.wm.allowDownscale"</span> <span style="color:var(--devsite-code-types-color)">android:value</span>=<span style="color:var(--devsite-code-strings-color)">"false"</span><span style="color:var(--devsite-code-keywords-color)">/></span> </code></span>
-
重建并重新提交您的游戏以选择退出。
重要提示:默认情况下,原始设备制造商 (OEM) 可以设置干预,除非您明确选择退出游戏。
资源
有关测量和优化游戏性能的更多信息:
-
System Profilers - 分析 CPU 使用率和图形调用。
-
Android GPU Inspector - Android 上的配置文件图形。
-
Android Frame Pacing Library - 帮助 OpenGL 和 Vulkan 游戏实现流畅的渲染和正确的帧节奏。
-
Android Performance Tuner - 大规模测量和优化 Android 设备的帧速率和图形。
-
Energy Profiler - 查找您的应用在哪些地方使用了不必要的能源。
//
///