设备层级定位

什么是设备层级定位?

借助设备层级定位,您可以根据设备的硬件向其分发同一资源的不同版本,例如不同分辨率的版本等。比方说,您可以选择将低分辨率资源分发给低端设备以提高性能,而将高分辨率资源分发给高端设备以提升图形质量。因为系统只会向用户设备分发必要的资源,所以完全不会增加整体游戏大小。这种做法采用了 Play Asset Delivery 中的资源包概念。如下文所述,您可以定义层级条件(目前基于 RAM、特定设备型号或可用系统功能),并且最多可使用 5 个层级。

与 Play Asset Delivery 一样,设备层级定位支持 API 16 (Jelly Bean 4.1) 及更高版本。不过,在 API 19 (KitKat 4.4.X) 及更低版本的设备上,无论运行的是何设备 build,系统都只会分发默认层级的资源。

开发者流程

总体而言,如需将设备层级定位集成到现有游戏中,您需要执行以下步骤:

  1. 将设备层级定位(以及 Play Asset Delivery)集成到您的游戏中
    • 将 Play Asset Delivery 集成到您的游戏中(如果尚未集成)
    • 将资源划分为资源包
    • 将代码和资源打包为要上传到 Play 的最终 Android App Bundle 工件。
  2. 创建设备层级定位配置,告诉 Play 如何将您的资源分发给用户设备。
    • 设置 Google Play Developer API(如果尚未完成此设置);此 API 用于将设备层级定位配置发送到 Play。
    • 按步骤完成设备层级定位配置的创建。
  3. 将 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 构建资源包的说明进行操作,然后按照关于在游戏中集成资源包检索的说明进行操作:

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 以外的设备层级,应执行以下操作:

  1. 使用 Google -> Build Android App Bundle 菜单选项构建 AAB 文件。
  2. 按照上一部分中的说明,对构建的 AAB 文件运行 bundletoolbuild-apksinstall-apks

通过 Google Play Developer API 创建设备层级配置

开始使用 Google Play Developer API(如果尚未开始使用)

如需配置设备层级定位(例如,定义每个层级的要求),需要使用 Android Publisher API 将配置上传到 Google Play。您可以点击上面的链接详细了解该 API。若要开始使用该 API,需要按照以下几个步骤操作

  1. 创建(如果需要)API 项目并将其关联到 Google Play 管理中心
  2. 设置 API 访问客户端

您可在此处找到 API 参考文档。稍后,如果您选择通过该 API 上传 build,需要使用 Edits 方法。此外,建议在使用该 API 之前先查看此页面

使用 Device Tier Configuration API

您可以使用以下 API 调用来创建设备层级配置:

创建设备层级配置

HTTP 请求 POST https://androidpublisher.googleapis.com/androidpublisher/v3/applications/{packageName}/deviceTierConfigs
路径参数 不适用
请求正文 设备层级配置
响应正文 设备层级配置
设备层级配置对象

定义设备层级包括 2 步:

  1. 定义一组设备组
  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”)

    设备目录中的 Pixel 4a 页面

    设备目录中的 Pixel 4a 页面

  • 下载受支持的设备的 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