将 Play Integrity for PC 集成到您的应用中

Play Integrity for PC 可帮助您检查游戏事件和服务器请求,确认它们是否来自正版 PC 设备上的正版 Google Play 游戏电脑版实例。通过检测可能存在风险的设备和未知模拟器,游戏的后端服务器可以采取适当的措施来防范作弊、未经授权的访问、欺诈性流量和滥用行为。

先决条件

第 1 步:确定在游戏中如何使用 Play Integrity for PC

确定何时调用 Play Integrity for PC 以获取有关环境的完整性判定结果。例如,您可以在游戏打开时、玩家登录时或玩家加入多人游戏时请求判定结果。然后,确定如何处理不同的完整性响应。例如,您可以:

  • 收集响应而不采取任何强制措施,并在内部分析数据,以了解它是否是滥用的有用信号。
  • 收集响应并在后端服务器上实现逻辑,以允许通过完整性判定的设备正常玩您的游戏,同时质疑或拒绝来自可疑环境的流量的访问。
  • 收集响应并在后端实现逻辑,以将通过完整性检查的设备上的玩家与来自可疑环境的流量进行匹配。

第 2 步:在游戏中请求完整性令牌

预热 Play Integrity for PC

准备(或“预热”)Play Integrity for PC,这样一来,Google Play 便可以智能地在设备上缓存部分证明信息,以在您发出请求以获取完整性判定结果时缩短关键路径上的延迟时间。您可以在游戏打开后立即异步执行此操作,以便在需要时按需发出完整性请求。

void PrepareIntegrityToken(
  const PrepareIntegrityTokenParams & params,
  PrepareIntegrityTokenContinuation continuation
)

成功后,系统将使用 PrepareIntegrityTokenResultValue调用延续,其中包含应用于请求 完整性令牌的 RequestTokenData。此数据应在内存中缓存,并在应用会话的 持续时间内重复使用,以用于对 RequestIntegrityToken的调用。

只有当应用确定有必要完全重新评估 完整性判定结果时,才应调用 PrepareIntegrityToken

详细信息
参数 params:包含 Google Cloud 项目编号的参数。
continuation:用于将完整性令牌提供程序返回到的异步回调。

以下代码段展示了应如何调用 PrepareIntegrityToken 操作:

google::play::integrity::IntegrityClient client_;

google::play::integrity::PrepareIntegrityTokenResult
IntegrityInterface::PrepareIntegrityToken(int64_t cloud_project_number) {
  google::play::integrity::PrepareIntegrityTokenParams params;
  params.cloud_project_number = cloud_project_number;

  auto promise = std::make_shared<
      std::promise<google::play::integrity::PrepareIntegrityTokenResult>>();
  client_.PrepareIntegrityToken(
      params,
      [promise](
          google::play::integrity::PrepareIntegrityTokenResult result) {
        promise->set_value(std::move(result));
      });

  return promise->get_future().get();
}

请求完整性令牌

完整性令牌是游戏验证设备是否被篡改的一种机制。每当您的游戏发出您要检查真实性的服务器请求时,您都可以请求完整性令牌,然后将其发送到游戏的后端服务器,以便进行解密和验证。

使用 Play Integrity API for PC 检查应用中的用户操作时,您可以利用 RequestIntegrityTokenParams::request_hash 字段来防范篡改攻击。例如,您可能想要将玩家得分报告给游戏的后端服务器,并且您的服务器想要验证此得分没有被代理服务器篡改。Play Integrity for PC 会在带签名的完整性响应中返回您在此字段中设置的值。如果没有 requestHash,完整性令牌将仅绑定到设备,而不会绑定到特定请求(这可能会导致遭到攻击)。

void RequestIntegrityToken(
  const RequestIntegrityTokenParams & params,
  RequestIntegrityTokenContinuation continuation
)

为了降低遭到攻击的可能性,在您请求完整性判定时:

  • 计算正在发生的用户操作或服务器请求中的所有相关请求参数(例如,稳定请求序列化的 SHA256)的摘要。
  • RequestIntegrityTokenParams::request_hash 字段设置为 摘要。
详细信息
参数 params:包含准备好的 RequestTokenData 和完整性检查请求哈希值的参数。
continuation:用于将数据返回到的异步回调。

以下代码段展示了如何调用 RequestIntegrityToken 操作:

absl::StatusOr<google::play::integrity::RequestIntegrityTokenResult>
IntegrityInterface::RequestIntegrityToken(
    const google::play::integrity::PrepareIntegrityTokenResult&
        prepare_integrity_token_result,
    const std::string& request_hash) {
  // Check if the prepare_integrity_token_result is OK
  if (!prepare_integrity_token_result.ok()) {
    return absl::FailedPreconditionError(
        absl::StrCat("PrepareIntegrityTokenResult is not OK. Error code: ",
                     prepare_integrity_token_result.error_code));
  }

  google::play::integrity::RequestIntegrityTokenParams params{
      .request_token_data =
          prepare_integrity_token_result.request_token_data,
      .request_hash = request_hash};

  auto promise = std::make_shared<std::promise<
      google::play::integrity::RequestIntegrityTokenResult>>();
  client_.RequestIntegrityToken(
      params,
      [promise](google::play::integrity::RequestIntegrityTokenResult result) {
        promise->set_value(std::move(result));
      });

  return promise->get_future().get();
}

第 3 步:接下来,在游戏的后端服务器上解密并验证完整性令牌

解密完整性令牌

在您请求完整性判定后,Play Integrity API 会提供加密的响应令牌。如需获取设备完整性判定,您必须在 Google 服务器上解密完整性令牌:

  1. 在与您的应用关联的 Google Cloud 项目中创建一个服务账号。
  2. 在应用服务器上,使用 playintegrity 范围从服务账号凭据中提取访问令牌,然后发出以下请求:

    playintegrity.googleapis.com/v1/<var>PACKAGE_NAME</var>:decodePcIntegrityToken -d \
     '{ "integrity_token": "<var>INTEGRITY_TOKEN</var>" }'
    
  3. 读取 JSON 响应。

生成的载荷是包含完整性判定结果和详细信息以及开发者提供的信息的纯文本令牌。解密后的完整性令牌如下所示:

{
  "requestDetails": {
    "requestPackageName": "com.your.package.name",
    "requestTime": "2025-08-29T13:10:37.285Z",
    "requestHash": "your_request_hash_string"
  },
  "deviceIntegrity": {
    "deviceRecognitionVerdict": [
      "MEETS_PC_INTEGRITY"
    ]
  },
  "accountDetails": {
    "appLicensingVerdict": "LICENSED"
  }
}

验证完整性令牌

解码后的完整性令牌的 requestDetails 字段包含与请求相关的信息,其中包括 requestHash 中由开发者提供的信息。

requestHashpackageName 字段应与原始请求中的字段相符。因此,请验证 JSON 载荷的 requestDetails 部分,确保 requestPackageNamerequestHash 与原始请求中发送的内容相符,如以下代码段所示:

const auto& request_details = json_payload["requestDetails"];

if (request_details.value("requestPackageName", "") != <YOUR_PACKAGE_NAME>) {
  // Don't trust the verdicts.
}

// Check for the existence of the request_hash.
// If you set a request hash in the request and it's not present, you shouldn't
// trust the verdicts.
if (!request_details.contains("requestHash")) {
    // Don't trust the verdicts.
}


// The requestHash from request_details needs to match the request hash your
// app provided.
if (request_details.value("requestHash", "") != <PROVIDED_REQUEST_HASH>) {
    // Don't trust the verdicts.
}

// You can read the rest of payload's fields.

第 4 步:根据完整性判定结果确定要采取的操作

deviceIntegrity 字段可以包含单个值 deviceRecognitionVerdict。您可以使用此值来确定您的游戏是否在通过 Play 完整性检查的 PC 上运行(即 MEETS_PC_INTEGRITY 响应)。accountDetails 字段包含单个值 appLicensingVerdict。您可以使用此值来确定用户是否已从 Play 获得许可。游戏的后端服务器可以收集此信息,并使用它来确定游戏应采取的操作,例如允许游戏事件继续进行或拒绝访问有风险的流量。

"deviceIntegrity": {
  "deviceRecognitionVerdict": ["MEETS_PC_INTEGRITY"]
}
"accountDetails": {
  "appLicensingVerdict": "LICENSED"
}

设备完整性判定

deviceRecognitionVerdict 的值可能如下:

MEETS_PC_INTEGRITY
游戏正在正版 PC 环境中运行,未检测到设备上存在篡改行为。
空(空白值)
运行游戏的设备存在遭受攻击(如 API 挂接)或系统被入侵(如设备运行篡改后的 Google 桌面服务版本)的迹象,或者不是实体设备(如未通过 Google Play 完整性检查的模拟器)。

账号详情判定

appLicensingVerdict 的值可能如下:

LICENSED
用户拥有应用使用权。换句话说,用户在其设备上从 Google Play 安装或更新了您的应用。
UNLICENSED
用户没有应用使用权。例如,当用户旁加载了您的应用,或未从 Google Play 获取您的应用时,就会发生这种情况。
UNEVALUATED
未评估许可详情,因为缺少必要的要求。 这可能是由多种原因造成的,包括以下原因:
  • 设备不够可信。
  • 设备上安装的应用是 Google Play 未知的版本。
  • 用户未登录 Google Play。

第 5 步:处理错误代码

如果您的游戏发出 Play Integrity for PC 请求,并且调用失败,则您的游戏会收到错误代码。这些错误可能是由多种原因造成的,例如环境问题(如网络连接不良)、API 集成问题或恶意活动和主动攻击。

可重试错误代码

这些错误有时是由于暂时性情况造成的,因此您应使用指数退避算法策略重试调用。

IntegrityError 错误说明 错误代码
kNetworkError 设备上的网络连接问题。 5
kTooManyRequests 设备发出的请求过多。 6
kClientTransientError 客户端存在暂时性问题。 7

如需了解有关重试策略的更多建议,请点击此处。

不可重试错误代码

在这些情况下,自动重试不太可能有帮助。但是,如果用户解决了导致问题的情况,手动重试可能会有所帮助。

IntegrityError 错误说明 错误代码 推荐操作
kError SDK 操作期间出现严重错误。 1 在重试之前,请验证您的 API 实现。
kCloudProjectNumberIsInvalid Cloud 项目编号无效。 2 验证您的云项目编号是否在 Google Cloud 控制台上正确配置,以及请求是否使用正确的云项目编号发出。
kRequestHashTooLong 请求哈希值过长。 3 生成的请求哈希值过长。请确保它们少于 500 个字符。
kNoValidPreparedTokenFound 在发出令牌请求之前,没有准备好的令牌。 4 在发出 [RequestIntegrityToken][request-integrity-token] 调用之前,请先调用 [PrepareIntegrityToken][prepare-token] 操作。
kSdkRuntimeUpdateRequired 需要更新 Play for Native SDK。 8 确保设备上的 Google Play 服务客户端是最新的,并且您使用的是最新版本的 Play for Native PC SDK。

在应用中测试不同的 Play Integrity API 响应

您可以创建测试以评估 Play Integrity API 与应用的互动方式。

  1. 设置一个(或多个)包含用户电子邮件地址的 Google 群组。您可以选择这些用户应在您的应用中通过 Google Play 服务器获取的完整性判定结果或错误代码。这样,您就可以测试您的应用对所有可能出现的响应和错误作何反应。

  2. 点击此处创建工单,并报告哪个 Google 群组将 获得哪个 API 响应。每个群组都分配为接收以下选项之一:

    通过许可判定 未通过许可判定 无法评估许可判定
    通过设备完整性 ALLOWLIST_CONFIG_MEETS_PC_INTEGRITY_LICENSED ALLOWLIST_CONFIG_MEETS_PC_INTEGRITY_UNLICENSED ALLOWLIST_CONFIG_MEETS_PC_INTEGRITY_LICENSING_UNEVALUATED
    未通过设备完整性 不适用 不适用 ALLOWLIST_CONFIG_NO_PC_INTEGRITY_LICENSING_UNEVALUATED
    如果您未通过设备完整性判定,许可判定将始终返回 UNEVALUATED。

  3. 请求处理完毕后,您会收到通知,并且测试用户会加入许可名单,以接收预定义的完整性判定结果进行测试。