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

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

先决条件

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

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

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

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

预热 Play Integrity(电脑版)

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

void PrepareIntegrityToken(
  const PrepareIntegrityTokenParams & params,
  PrepareIntegrityTokenContinuation continuation
)

如果成功,系统将使用包含 RequestTokenData 的 PrepareIntegrityTokenResultValue 调用 continuation,该 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 字段来防范篡改攻击。例如,您可能想要将玩家得分报告给游戏的后端服务器,并且您的服务器想要验证此得分没有被代理服务器篡改。面向 PC 的 Play Integrity 可以在带签名的完整性响应中返回您在此字段中设置的值。如果没有 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. 请求处理完毕后,我们会通知您,届时测试用户将位于许可名单中,可以接收预定义的完整性判定结果以进行测试。