將電腦版 Play Integrity 整合至應用程式

電腦版 Play Integrity 可協助您檢查遊戲事件和伺服器要求,確認來源是正版電腦裝置上正規的 Google Play 遊戲電腦版執行個體。偵測到有潛在風險的裝置和不明模擬器後,遊戲的後端伺服器就能採取適當因應行動,防範作弊、未經授權的存取、詐欺流量和濫用情形。

先決條件

步驟 1:決定在遊戲中使用 Play Integrity for PC 的方式

決定何時呼叫 Play Integrity for PC,以取得環境的完整性判定結果。舉例來說,您可以在遊戲開啟、玩家登入或加入多人遊戲時要求判定結果。然後決定如何處理不同的完整性回應。例如,你可以執行下列動作:

  • 收集回覆內容,但不採取任何強制措施,並在內部分析資料,瞭解這是否為有用的濫用信號。
  • 收集回應,並在後端伺服器上實作邏輯,允許通過完整性判定結果的裝置正常執行遊戲,同時對來自可疑環境的流量提出質疑或拒絕存取。
  • 收集回應並在後端實作邏輯,將通過完整性檢查的裝置上的玩家配對在一起,同時將來自可疑環境的流量配對在一起。

步驟 2:在遊戲中要求完整性權杖

為電腦版 Play Integrity 服務預熱

準備 (或「暖機」) 電腦版 Play Integrity,讓 Google Play 能夠在裝置上智慧快取部分認證資訊,進而在您索取完整性判定結果時,縮短關鍵路徑上的延遲時間。您可以在遊戲開啟後立即非同步執行這項操作,以便在需要時提出完整性要求。

void PrepareIntegrityToken(
  const PrepareIntegrityTokenParams & params,
  PrepareIntegrityTokenContinuation continuation
)

成功時,系統會使用包含 RequestTokenDataPrepareIntegrityTokenResultValue 呼叫續傳,該資料應做為要求完整性權杖的依據。這項資料應快取在記憶體中,並在應用程式工作階段期間重複使用,以呼叫 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 檢查電腦版應用程式中的使用者動作時,您可以利用 RequestIntegrityTokenParams::request_hash 欄位應對竄改攻擊。舉例來說,您可能要向遊戲後端伺服器回報玩家分數,而您的伺服器想驗證 Proxy 伺服器未竄改分數,在此情況下,就適合使用上述欄位。電腦版 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 欄位應與原始要求的值相符。因此,請確認 requestPackageNamerequestHash 與原始要求中傳送的值相符,藉此驗證 JSON 酬載的 requestDetails 部分,如下列程式碼片段所示:

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 Integrity 檢查的電腦上執行 (即 MEETS_PC_INTEGRITY 回應)。accountDetails 欄位包含單一值 appLicensingVerdict。您可以使用這個值判斷使用者是否已透過 Google Play 取得授權。遊戲的後端伺服器可以收集這項資訊,並據此判斷遊戲應採取哪些行動,例如允許遊戲事件繼續進行,或拒絕存取高風險流量。

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

裝置完整性判定結果

deviceRecognitionVerdict 的值可能如下:

MEETS_PC_INTEGRITY
遊戲是在正版電腦環境中執行,且未偵測到任何裝置端竄改行為。
空白 (空白值)
執行遊戲的裝置可能遭受攻擊 (例如掛接 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. 要求處理完畢後,系統會通知您,並將測試使用者加入允許清單,讓他們接收預先定義的完整性判定結果以進行測試。