支持应用内更新(原生代码)

本指南将介绍如何使用原生代码(C 或 C++)在您的应用中支持应用内更新。我们针对实现使用 Kotlin 编程语言或 Java 编程语言以及 Unity 的情况提供了单独的指南。

原生 SDK 概览

Play Core 原生 SDK 是 Play Core SDK 系列的一部分。原生 SDK 包含一个 C 头文件 app_update.h,用于封装来自 Java Play Core SDK 的 AppUpdateManager。此头文件允许您的应用直接从原生代码调用适用于应用内更新的 API。

设置您的开发环境

如需设置您的开发环境,请按照 Play Core 库指南的原生代码部分中的设置说明进行操作。

将 Play Core 原生 SDK 集成到您的项目后,请在包含 API 调用的文件中添加下面这行代码:

#include "play/app_update.h"

初始化应用内更新 API

每当您使用应用内更新 API 时,请先调用 AppUpdateManager_init() 函数来对其进行初始化,如下面使用 android_native_app_glue.h 构建的示例所示:

void android_main(android_app* app) {
  app->onInputEvent = HandleInputEvent;

  AppUpdateErrorCode error_code =
    AppUpdateManager_init(app->activity->vm, app->activity->clazz);
  if (error_code == APP_UPDATE_NO_ERROR) {
    // You can use the API.
  }
}

检查是否有可用更新

在请求更新之前,请检查您的应用是否有可用更新。AppUpdateManager_requestInfo() 会启动一个异步请求,用于收集稍后启动应用内更新流程所需的信息。如果请求成功启动,此函数会返回 APP_UPDATE_NO_ERROR

AppUpdateErrorCode error_code = AppUpdateManager_requestInfo()

if (error_code == APP_UPDATE_NO_ERROR) {
    // The request has successfully started, check the result using
    // AppUpdateManager_getInfo.
}

您可以使用 AppUpdateManager_getInfo() 跟踪持续进行的流程和请求结果。除了错误代码之外,此函数还会返回 AppUpdateInfo 不透明结构体,用于检索有关更新请求的信息。例如,您可能希望在每个游戏循环中都调用此函数,直到它针对 info 返回非 null 结果:

AppUpdateInfo* info;
GameUpdate() {

   // Keep calling this in every game loop until info != nullptr
   AppUpdateErrorCode error_code = AppUpdateManager_getInfo(&info);

   if (error_code == APP_UPDATE_NO_ERROR && info != nullptr) {
       // Successfully started, check the result in the following functions
   }
...
}

检查更新是否已过时

除了检查是否有可用更新之外,您可能还需要检查自通过 Play 商店通知用户更新以来已经过了多长时间。这可帮助您决定应发起灵活更新还是立即更新。例如,您可能需要等待几天后再通知用户进行灵活更新,在此之后再等待几天,然后再要求用户进行立即更新。

您可以使用 AppUpdateInfo_getClientVersionStalenessDays() 检查自通过 Play 商店提供更新以来已经过了多少天:

int32_t staleness_days = AppUpdateInfo_getClientVersionStalenessDays(info);

检查更新优先级

借助 Google Play Developer API,您可以设置每项更新的优先级。这样,您的应用就可以决定以多么强烈的口吻向用户推荐更新。例如,我们考虑使用以下策略来设置更新优先级的策略:

  • 细微的界面改进:低优先级更新;既不请求灵活更新,也不请求立即更新。仅在用户没有与您的应用互动时进行更新。
  • 性能提升:中优先级更新;请求灵活更新。
  • 关键安全更新:高优先级更新;请求立即更新。

Google Play 使用 0 到 5 之间的整数值来确定优先级,其中 0 是默认值,5 代表最高优先级。如需设置更新的优先级,请使用 Google Play Developer API 中 Edits.tracks.releases 下的 inAppUpdatePriority 字段。发布版本中的所有新增版本都被视为与发布版本具有相同的优先级。只有在发布新版本时才能设置优先级,且以后无法更改。

您可以使用 Google Play Developer API 设置优先级,如 Play Developer API 文档中所述。在 Edit.tracks: update 方法中传递的 Edit.tracks 资源中指定应用内更新优先级。以下示例演示了如何发布一个版本号为 88 且 inAppUpdatePriority 为 5 的 APK:

{
  "releases": [{
      "versionCodes": ["88"],
      "inAppUpdatePriority": 5,
      "status": "completed"
  }]
}

在应用的代码中,您可以使用 AppUpdateInfo_getPriority() 检查给定更新的优先级:

int32_t priority = AppUpdateInfo_getPriority(info);

启动更新

在确认有可用更新后,您可以使用 AppUpdateManager_requestStartUpdate() 请求更新。在请求更新之前,请获取最新的 AppUpdateInfo 对象并创建 AppUpdateOptions 对象以配置更新流程。AppUpdateOptions 对象定义了应用内更新流程的选项,包括更新应为灵活更新还是立即更新。

以下示例针对灵活更新流程创建了 AppUpdateOptions 对象:

// Creates an AppUpdateOptions configuring a flexible in-app update flow.
AppUpdateOptions* options;
AppUpdateErrorCode error_code = AppUpdateOptions_createOptions(APP_UPDATE_TYPE_FLEXIBLE, &options);

以下示例针对立即更新流程创建了 AppUpdateOptions 对象:

// Creates an AppUpdateOptions configuring an immediate in-app update flow.
AppUpdateOptions* options;
AppUpdateErrorCode error_code = AppUpdateOptions_createOptions(APP_UPDATE_TYPE_IMMEDIATE, &options);

AppUpdateOptions 对象还包含 AllowAssetPackDeletion 字段,可用于指定是否允许更新在设备存储空间有限的情况下清除资源包。此字段默认设置为 false,但您可以使用 AppUpdateOptions_setAssetPackDeletionAllowed() 方法将其设置为 true

bool allow = true;
AppUpdateErrorCode error_code = AppUpdateOptions_setAssetPackDeletionAllowed(options, allow);

在获取最新的 AppUpdateInfo 对象且正确配置 AppUpdateOptions 对象后,请调用 AppUpdateManager_requestStartUpdate() 以异步方式请求更新流程,从而传入 Android activity jobject 作为最后一个参数。

AppUpdateErrorCode request_error_code =
AppUpdateManager_requestStartUpdate(info, options, app->activity->clazz);

如需释放资源,请分别调用 AppUpdateInfo_destroy()AppUpdateOptions_destroy() 以释放不再需要的 AppUpdateInfoAppUpdateOptions 的实例。

AppUpdateInfo_destroy(info);
AppUpdateOptions_destroy(options);

对于立即更新流程,Google Play 会显示一个用户确认页面。用户接受请求后,Google Play 会自动在前台下载并安装更新,然后在安装成功后重启应用以使用更新后的版本。

对于灵活更新流程,您可以不断请求最新的 AppUpdateInfo 对象,以便在用户继续与应用互动时跟踪当前的更新状态。在下载成功完成后,您必须调用 AppUpdateManager_requestCompleteUpdate() 以触发更新完成,如下例所示:

AppUpdateStatus status = AppUpdateInfo_getStatus(info);
if (status == APP_UPDATE_DOWNLOADED) {
    AppUpdateErrorCode error_code = AppUpdateManager_requestCompleteUpdate();
    if (error_code != APP_UPDATE_NO_ERROR)
    {
      // There was an error while completing the update flow.
    }
}

在您的应用使用完 API 后,请调用 AppUpdateManager_destroy() 函数来释放资源。

错误处理

本部分介绍了针对一些常见错误(由 AppUpdateErrorCode 值指示)的解决方案:

  • 错误代码为 -110, APP_UPDATE_INITIALIZATION_NEEDED,这表示 API 尚未成功初始化。请调用 AppUpdateManager_init() 以初始化 API。
  • 错误代码为 -4, APP_UPDATE_INVALID_REQUEST,这表示更新流程请求的某些参数的格式不正确。请进行检查以确保 AppUpdateInfoAppUpdateOptions 对象不为 null 且格式正确。
  • 错误代码为 -5, APP_UPDATE_UNAVAILABLE,这表示没有可用的适用更新。请确保目标版本具有相同的软件包名称应用 ID签名密钥。如果有可用的更新,请清除应用的缓存并再次调用 AppUpdateManager_requestAppUpdateInfo() 以刷新 AppUpdateInfo
  • 错误代码为 -6, APP_UPDATE_NOT_ALLOWED,这表示 AppUpdateOption 对象指明的更新类型是不允许的。在启动更新流程之前,请检查 AppUpdateInfo 对象是否指明允许相应更新类型。

后续步骤

测试应用的应用内更新,以验证您的集成是否正常运行。