什么是设备层级定位?
借助设备层级定位,您可以根据设备的硬件向其分发同一资源的不同版本,例如不同分辨率的版本等。比方说,您可以选择将低分辨率资源分发给低端设备以提高性能,而将高分辨率资源分发给高端设备以提升图形质量。因为系统只会向用户设备分发必要的资源,所以完全不会增加整体游戏大小。这种做法采用了 Play Asset Delivery 中的资源包概念。如下文所述,您可以定义层级条件(目前可基于 RAM、特定设备型号或可用系统功能来定义),并且最多可使用 5 个层级。
与 Play Asset Delivery 一样,设备层级定位支持 API 16 (Jelly Bean 4.1) 及更高版本。不过,在 API 19 (KitKat 4.4.X) 及更低版本的设备上,无论运行的是何设备 build,系统都只会分发默认层级的资源。
开发者流程
总体而言,如需将设备层级定位集成到现有游戏中,您需要执行以下步骤:
- 将设备层级定位(以及 Play Asset Delivery)集成到您的游戏中
- 将 Play Asset Delivery 集成到您的游戏中(如果尚未集成)
- 将资源划分为资源包
- 将代码和资源打包为要上传到 Play 的最终 Android App Bundle 工件。
- 创建设备层级定位配置,告诉 Play 如何将您的资源分发给用户设备。
- 设置 Google Play Developer API(如果尚未完成此设置);此 API 用于将设备层级定位配置发送到 Play。
- 按步骤完成设备层级定位配置的创建。
- 将 AAB 文件上传到 Play,并进行测试以确保各项配置正确无误。
在第一部分中,您会发现,本指南中的某些分支取决于您使用的构建系统,而您选择的系统则取决于您使用的引擎和您的现有设置。
- Gradle(推荐用于 Java 和原生游戏):对于使用 Gradle 构建的游戏,请按照以下步骤配置构建系统,以构建支持设备层级定位的 AAB 文件。
- 如果您需要将游戏导出到 Gradle 中,然后在其中完成构建,建议您按照以下说明操作(例如,导出到 Gradle 中的 Unity 游戏)。
- Unity 插件:我们将为您提供 Unity 软件包,用于导入至您的 Unity 项目中,以便您配置和构建支持设备层级定位的 AAB 文件。
在应用内设置设备层级定位
将 Play Asset Delivery 集成到您的游戏中(如果尚未完成此集成)
借助 Play Asset Delivery (PAD),您可以在安装时或运行时动态分发游戏资源,请阅读此处的相关概览。使用设备层级定位时,Play 会根据您为不同层级的设备所设置的设备层级配置来分发资源包。建议您按照下面的指南操作并将 PAD 集成到您的游戏中(即创建资源包、在游戏中实现检索),然后修改项目代码以启用设备层级定位。
Gradle
对于使用 Gradle 构建的游戏,请先按照关于使用 Gradle 构建资源包的说明进行操作,然后按照关于在游戏中集成资源包检索的说明进行操作:
- Java
- 原生代码
- 导出到 Gradle 中的 Unity 游戏
- 通过 JNI(例如 Unity 中内置的 JNI)使用 Java 库。
Unity
对于在 Unity 中构建的游戏,您需要按照这些说明中所述,使用 AssetPackConfig
类来配置资源包。
创建设备层级专用目录
如果使用 Gradle
现在,您需要在稍后要定义的 N 个层级(最多 5 个)之间拆分资源。取上一步中创建的现有资源包目录,并在相应文件夹后添加 #tier_0、#tier_1、#tier_2 等后缀(如下所述),以此来创建设备层级定位目录。当您在游戏中使用资源包时,您无需使用后缀来处理文件夹(换言之,系统会在构建流程中自动去除后缀)。
执行完上一步操作后,目录可能如下所示:
...
.../level1/src/main/assets/character-textures#tier_2/
.../level1/src/main/assets/character-textures#tier_1/
.../level1/src/main/assets/character-textures#tier_0/
...
当您访问文件夹下的文件时,可以只使用相同的路径而不加后缀(在此示例中,我们会引用 level1/assets/character-textures/
,不加任何后缀)。
如果使用 Unity
如需添加使用设备层级定位的资源包,可以使用下面的 AssetPackConfig
方法:
/// Package the specified raw assets in the specified folders,
/// keyed by DeviceTier, in an AssetPack with the specified delivery mode.
public void AddAssetsFolders(
string assetPackName,
IDictionary<DeviceTier, string> deviceTierToAssetPackDirectoryPath,
AssetPackDeliveryMode deliveryMode)
/// Package the specified AssetBundle files, which vary only by DeviceTier,
/// in an AssetPack with the specified delivery mode.
public void AddAssetBundles(
IDictionary<DeviceTier, string> deviceTierToAssetBundleFilePath,
AssetPackDeliveryMode deliveryMode)
例如,假设您的角色具有三个详细程度不同的 AssetBundles
。
如需将这些 AssetBundles
映射到其对应的设备层级,请使用以下代码段。
var assetPackConfig = new AssetPackConfig();
var tiers = new Dictionary<DeviceTier, string>
{
{0, "Assets/LowPoly/Character"},
{1, "Assets/Mid/Character"},
{2, "Assets/Detailed/Character"}
};
assetPackConfig.AddAssetBundles(tiers, AssetPackDeliveryMode.OnDemand);
构建 Android App Bundle 文件
Gradle
在项目的 build.gradle
文件中,配置依赖项以获取 Android Gradle 插件和 bundletool 的以下版本(或更高版本):
buildscript {
dependencies {
classpath 'com.android.tools.build:gradle:4.2.0'
classpath "com.android.tools.build:bundletool:1.7.1"
...
}
...
}
您还需要将 Gradle 版本更新到 6.7.1 或更高版本。您可以在项目内的 gradle/wrapper/gradle-wrapper.properties
中进行此更新。
distributionUrl=https://services.gradle.org/distributions/gradle-6.7.1-all.zip
最后,您需要使用 Play Asset Delivery 库;如果您仍在使用单体式 Play Core 库,请将其更新到 1.8.3 或更高版本。建议您改用 Play Asset Delivery 库,并尽可能更新到最新版本。
dependencies {
implementation 'com.google.android.play:asset-delivery:2.0.1'
...
}
在主应用模块的 build.gradle
文件中,启用设备层级定位拆分:
android {
bundle {
deviceTier {
enableSplit true
}
...
}
...
}
最后,您就可以构建 Android App Bundle (AAB) 文件了。
bundletool
使用 bundletool 构建软件包,并在自定义 AAB 文件这一步中,将以下内容添加到 BundleConfig.pb
文件中。
{
...
"optimizations": {
"splitsConfig": {
"splitDimension": [
...
{
"value": "DEVICE_TIER",
"negate": false,
"suffixStripping": {
"enabled": true,
}
}],
}
}
}
Unity
完成 AssetPackConfig
配置以包含设备层级定位资源包后,您可以将该配置传入下面列出的一个方法中,以构建 AAB 文件:
// Configures the build system to use the newly created assetPackConfig when
// calling Google > Build and Run or Google > Build Android App
Bundle.AssetPackConfigSerializer.SaveConfig(assetPackConfig);
// Alternatively, use BundleTool.BuildBundle to build an App Bundle from script
BuildBundle(new buildPlayerOptions(), assetPackConfig)
本地测试
在继续下一步之前,建议您在本地测试 app bundle,确保各项设置正确无误。使用 bundletool
(1.8.0 或更高版本),您可以在本地构建和测试应用,并明确指定正确的设备层级。您需要先使用 build-apks
生成一组 .apks
文件,然后使用 install-apks
将应用部署到已连接的设备。此外,您还可以通过 device-tier 标志指定要安装的层级。如需详细了解此本地测试方法,请点击此处(请注意,此页面尚未针对设备层级定位的内容进行更新,因此缺少 device-tier
标志)。
bundletool build-apks --bundle=/path/to/app.aab --output=/path/to/app.apks --local-testing
bundletool install-apks --apks=/path/to/app.apks --device-tier=1
替代方案:您也可以使用 extract-apks
为特定设备提取一组 APK。不过,如果同时使用了 --local-testing
标志,则运用 get-device-spec
并指定该设备的设备层级这种做法会不起作用,这意味着您无法测试快速跟进式分发资源包或按需分发资源包。
bundletool get-device-spec --output=/path/to/device-spec.json --device-tier=1
bundletool extract-apks --apks=/path/to/existing_APK_set.apks --output-dir=/path/to/device_specific_APK_set.apks --device-spec=/path/to/device-spec.json
Unity
Google -> Build and Run 菜单选项将构建和运行您的游戏,并启用 --local-testing
标志。但是,它不允许您指定传入 install-apks
命令中的设备层级。
如果要指定 0 以外的设备层级,应执行以下操作:
- 使用 Google -> Build Android App Bundle 菜单选项构建 AAB 文件。
- 按照上一部分中的说明,对构建的 AAB 文件运行
bundletool
、build-apks
和install-apks
。
通过 Google Play Developer API 创建设备层级配置
开始使用 Google Play Developer API(如果尚未开始使用)
如需配置设备层级定位(例如,定义每个层级的要求),需要使用 Android Publisher API 将配置上传到 Google Play。您可以点击上面的链接详细了解该 API。若要开始使用该 API,需要按照以下几个步骤操作:
您可在此处找到 API 参考文档。稍后,如果您选择通过该 API 上传 build,需要使用 Edits 方法。此外,建议在使用该 API 之前先查看此页面。
使用 Device Tier Configuration API
您可以使用以下 API 调用来创建设备层级配置:
创建设备层级配置
HTTP 请求 | POST https://androidpublisher.googleapis.com/androidpublisher/v3/applications/{packageName}/deviceTierConfigs |
路径参数 | 不适用 |
请求正文 | 设备层级配置 |
响应正文 | 设备层级配置 |
设备层级配置对象
定义设备层级包括 2 步:
- 定义一组设备组。
- 通过为设备组分配级别来定义设备层级设置。
设备组是与您在配置中定义的选择器匹配的一组设备。
选择器可以基于设备 RAM 和设备型号来定义要求。
组由您选择的名称加以标识;允许组与组之间重叠。
接下来,您可以通过对组进行排名来定义设备层级设置:每个设备层级由其级别和一个设备组进行定义。
如果设备与多个层级匹配,系统将向其提供匹配的最高层级的内容。
{ device_groups: [ { name: string, device_selectors: [ { device_ram: { min_bytes: integer max_bytes: integer }, included_device_ids: [ { build_brand: string, build_device: string } ], excluded_device_ids: [ { build_brand: string, build_device: string } ], required_system_features: [ { name: string } ], forbidden_system_features: [ { name: string } ] } ] } ], device_tier_set: { device_tiers: [ { level: int, device_group_names: [string] } ] } }
字段:
- device_confid_id(整数):与此设备层级配置对应的 ID。
device_groups(对象):组定义
- name(字符串):设备组的名称(您定义的字符串 ID)。
- device_selectors(对象):对属于该组的设备的设备要求。
- device_ram(对象):设备 RAM 要求
- max_bytes(整数,含):最高 RAM 要求(字节)
- max_bytes(整数,不含):最高 RAM 要求(字节)
- included_device_ids(对象):此选择器中要包含的设备型号(每组最多 10000 个 device_ids)。设备需要在此列表中才能匹配该选择器。这是匹配整个选择器的必要但非充分条件(请参阅上文说明,了解如何在选择器中组合使用多项要求)。
- build_brand(字符串):设备制造商
- build_device(字符串):设备型号代码
- excluded_device_ids(对象):此选择器中要排除的设备型号(每组最多 10,000 个 device_ids)。此列表中的设备即使符合该选择器中的所有其他要求,也不会匹配该选择器。
- build_brand(字符串):设备制造商
- build_device(字符串):设备型号代码
required_system_features(对象):设备想要包含在此选择器中所需要具备的功能。(每组最多 100 项功能)。设备需要具备此列表中的所有系统功能才能匹配该选择器。这是匹配整个选择器的必要但非充分条件(请参阅上文说明,了解如何在选择器中组合使用多项要求)。
系统功能参考
- name(字符串):系统功能
forbidden_system_features(对象):设备想要包含在此选择器中就不能具备的功能(每组最多 100 项功能)。设备如果具备此列表中的任何系统功能,即使符合该选择器中的所有其他要求,也不匹配该选择器。
系统功能参考
- name(字符串):系统功能
device_tiers(对象):层级定义
- level(整数):层级的级别
- group_name(字符串数组):属于此层级的设备组的名称
您可以通过以下任一种方式,使用 Google Play 管理中心的设备目录查找设备制造商和型号代码的正确格式:
使用设备目录检查各个设备,在下例中所示的位置找到制造商和型号代码(以 Google Pixel 4a 为例,制造商为“Google”,型号代码为“sunfish”)
下载受支持的设备的 CSV 文件,build_brand 和 build_device 字段分别表示制造商和型号代码。
以下示例配置包含 3 个层级 - 层级 2 使用设备组“high”(包含 RAM 高于 7GB 并且是 Pixel 4 的所有设备),层级 1 使用设备组“medium”(包含 RAM 介于 4-7 GB 之间的所有设备),层级 0 是隐式定义的全适组。
{
device_groups: [
{
name: 'high',
device_selectors: [
{
device_ram: {
min_bytes: 7516192768
},
},
{
included_device_ids: [
{
build_brand: 'google',
build_device: 'flame'
}
],
}
]
},
{
name: 'medium',
device_selectors: [
{
device_ram: {
min_bytes: 4294967296,
max_bytes: 7516192768
},
}
]
}
],
device_tier_set: {
device_tiers: [
{
level: 1,
device_group_names: [
'medium'
]
},
{
level: 2,
device_group_names: [
'high'
]
}
]
}
}
您可以先按照以下说明验证设备定位配置,然后再将其上传到 Google Play。
按 ID 获取设备层级配置
您可以使用以下调用按 ID 检索特定的设备层级配置:
HTTP 请求 |
GET https://androidpublisher.googleapis.com/androidpublisher/v3/applications/{packageName}/deviceTierConfigs/{deviceTierConfigId}
|
路径参数 | 不适用 |
请求正文 | 不适用 |
响应正文 | 设备层级配置 |
获取设备层级配置列表
您可以通过以下调用获取最近 10 个设备层级配置(或者,最好使用 page_token 查询参数指定一组 10 个设备层级配置):
HTTP 请求 | GET https://androidpublisher.googleapis.com/androidpublisher/v3/applications/{packageName}/deviceTierConfigs |
路径参数 | 不适用 |
查询参数 | page_token(可选)- 用于指定具体的一组 10 个 DTC。如果您创建的 DTC 超过 10 个,而您希望查看在最近 10 个 DTC 之前创建的 DTC,此参数就会非常有用。 |
请求正文 | 不适用 |
响应正文 | 设备层级配置列表
page_token |
验证设备定位配置
bundletool
包含两个命令,可帮助您验证设备定位配置在上传到 Play 之前是否按预期运行。
您可以使用 bundletool print-device-targeting-config
来验证 JSON 文件的语法是否正确,并以更易于用户看懂的格式直观地呈现设备组和层级。
bundletool print-device-targeting-config --config=mydtc.json
借助 bundletool evaluate-device-targeting-config
,您可以评估哪些组和层级与特定设备匹配。您可以将目标设备连接到工作站并使用 --connected-device
标志;或者,您也可以手动编译包含设备属性的 JSON 文件,并通过 --device-properties
标志提供该文件。
bundletool evaluate-device-targeting-config --config=mydtc.json --connected-device
bundletool evaluate-device-targeting-config --config=mydtc.json --device-properties=deviceproperties.json
设备属性文件应该是遵循 DeviceProperties protobuf 结构的 JSON 文件。例如:
{
"ram": 2057072640,
"device_id": {
"build_brand":"google",
"build_device":"redfin"
},
"system_features": [
{
"name":"android.hardware.bluetooth"
},
{
"name":"android.hardware.camera"
}
]
}
将 Android App Bundle 文件上传到 Google Play
通过 API
您可以使用 Google Play Developer API 将 Android App Bundle 文件上传到 Google Play,并将特定的设备层级定位配置关联到您的 build。
此处简要介绍了 Edits 方法,还有关于如何发布到 Google Play 管理中心内不同轨道的深入示例(对于后一个链接,您需要使用适合 AAB 文件的 API,而非该页面中列出的适合 APK 的 API)。如需为 build 指定设备层级配置,需要在调用 edits.bundle.upload
方法时将配置 ID 添加到 deviceTierConfigId
查询参数中,如下所示:
https://androidpublisher.googleapis.com/upload/androidpublisher/v3/applications/{packageName}/edits/{editId}/bundles?deviceTierConfigId="{deviceTierConfigId}
通过 Google Play 管理中心
您可以按照此处的说明上传 Android App Bundle 文件。系统会将最新 DTC 配置应用于您的 App Bundle 文件。
您可以按如下方法验证您的软件包是否构建正确:依次前往 App bundle 资源管理器(已选择正确的 build)> Delivery,然后点击每个资源包。系统应当会显示您已创建 N 个层级。在以下示例中,系统显示我的资源包 main_asset 有 3 个层级 - 0、1、2。
验证分发的层级是否正确
请使用以下方法来确保仅向设备分发正确的层级
adb shell pm path {packageName} |
您应该会看到类似如下内容:
package:{...}/base.apk
package:{...}/split_config.en.apk
package:{...}/split_config.xxhdpi.apk
package:{...}/split_main_asset.apk
package:{...}/split_main_asset.config.tier_2.apk
辅助示例
快速入门:使用 curl
以下示例(使用命令行工具 curl)首先创建新的设备层级配置,接着使用 Edits API 创建新修改,上传新 AAB 文件(将其与特定设备层级配置关联),设置轨道/发布配置,然后提交修改(从而公开更改内容)。确保您有以下内容的位置:
- 与您的 API 客户端相对应的密钥
- 您的应用的软件包名称
首先,创建一个设备层级配置,并记下调用成功后收到的 deviceTierConfigId
。
curl -H "$(oauth2l header --json $HOME/{apiKey} androidpublisher)" -XPOST -H "Content-Type: application/json" -d "{ device_groups: [ { name: 'high', device_selectors: [ { device_ram: { min_bytes: 7516192768 }, }, { included_device_ids: [ { build_brand: 'google', build_device: 'flame' } ], } ] }, { name: 'medium', device_selectors: [ { device_ram: { min_bytes: 4294967296, max_bytes: 7516192768 }, } ] } ], device_tier_set: { device_tiers: [ { level: 1, device_group_names: [ 'medium' ] }, { level: 2, device_group_names: [ 'high' ] } ] } }" https://androidpublisher.googleapis.com/androidpublisher/v3/applications/{packageName}/deviceTierConfigs
开始修改 - 您将获得该修改的 ID 和过期时间。请保存该 ID,用于接下来的调用。
curl -H "$(oauth2l header --json $HOME/{apiKey} androidpublisher)" -XPOST https://androidpublisher.googleapis.com/androidpublisher/v3/applications/{packageName}/edits
上传 AAB 文件,将设备层级配置指定为查询参数 - 如果调用成功,您将看到 build 的版本号、sha1 值和 sha256 值。请保存该版本号,用于下一个调用。
curl -H "$(oauth2l header --json $HOME/{apiKey} androidpublisher)" --data-binary @$HOME/{aabFile} -H "Content-Type: application/octet-stream" -XPOST https://androidpublisher.googleapis.com/upload/androidpublisher/v3/applications/{packageName}/edits/{editID}/bundles?deviceTierConfigId="{dttConfigID}"
将 AAB 文件分配到所需轨道(出于测试目的,建议使用内部测试轨道,但您可以在此处详细了解不同的轨道),我们在这里只进行了简单发布,未提供版本说明,但您可以阅读此页面,详细了解何为分阶段发布、草稿版本和版本说明。如果这是您第一次使用 Publisher API,建议您将此创建为草稿版本,并在 Google Play 管理中心完成发布,以确保各项配置正确无误。
curl -H "$(oauth2l header --json $HOME/{apiKey} androidpublisher)" -XPUT -H "Content-Type: application/json" -d "{ releases: [{status: '{status}'</code>, <code><strong>versionCodes</strong></code>: <code>['{versionCode}']</code> <code><strong>}]}</strong></code>" <code>https://androidpublisher.googleapis.com/androidpublisher/v3/applications/{packageName}/edits/{editID}/tracks/{track}
提交更改(请谨慎操作,因为此操作会将所有更改发布到 Play 中的所需轨道)
curl -H "$(oauth2l header --json $HOME/{apiKey} androidpublisher)" -XPOST https://androidpublisher.googleapis.com/androidpublisher/v3/applications/{packageName}/edits/{editID}:commit