PlayIntegrity API调用:如何处理GOOGLE_SERVER_UNAVAILABLE错误
问题描述
我正在开发一款Android安全应用,决定采用PlayIntegrity API替代SafetyNet API。已完成Play控制台与Cloud控制台等必要配置步骤,但在获取token时遇到了GOOGLE_SERVER_UNAVAILABLE错误,求问该问题的可能原因及解决方案。
相关代码
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // playIntegritySetup.lol(); getToken(); } private void getToken() { String nonce = Base64.encodeToString(generateNonce(50).getBytes(), Base64.URL_SAFE | Base64.NO_WRAP | Base64.NO_PADDING); // Create an instance of a manager. IntegrityManager integrityManager = IntegrityManagerFactory.create(getApplicationContext()); // Request the integrity token by providing a nonce. Task<IntegrityTokenResponse> integrityTokenResponse = integrityManager.requestIntegrityToken( IntegrityTokenRequest.builder() .setNonce(nonce) .build()); integrityTokenResponse.addOnSuccessListener(new OnSuccessListener<IntegrityTokenResponse>() { @Override public void onSuccess(IntegrityTokenResponse integrityTokenResponse) { String integrityToken = integrityTokenResponse.token(); SplashActivity.this.doIntegrityCheck(integrityToken); Log.e("Integrity Token", "integrity token from the app" + integrityToken); } }); integrityTokenResponse.addOnFailureListener(e -> showErrorDialog("Error getting token from Google. Google said: " + getErrorText(e))); } private void doIntegrityCheck(String token) { AtomicBoolean hasError = new AtomicBoolean(false); Observable.fromCallable(() -> { OkHttpClient okHttpClient = new OkHttpClient(); Response response = okHttpClient.newCall(new Request.Builder().url("money control url" + "token from backend server" + token).build()).execute(); Log.e("Token", "token from the app" + token); if (!response.isSuccessful()) { hasError.set(true); return "Api request error. Code: " + response.code(); } ResponseBody responseBody = response.body(); if (responseBody == null) { hasError.set(true); return "Api request error. Empty response"; } JSONObject responseJson = new JSONObject(responseBody.string()); if (responseJson.has("error")) { hasError.set(true); return "Api request error: " + responseJson.getString("error"); } if (!responseJson.has("deviceIntegrity")) { hasError.set(true); } return responseJson.getJSONObject("deviceIntegrity").toString(); }) // Execute in IO thread, i.e. background thread. .subscribeOn(Schedulers.io()) // report or post the result to main thread. .observeOn(AndroidSchedulers.mainThread()) // execute this RxJava .subscribe(new Observer<String>() { @Override public void onSubscribe(Disposable d) { } @Override public void onNext(String result) { if (hasError.get()) { if (result.contains("MEETS_DEVICE_INTEGRITY") && result.contains("MEETS_BASIC_INTEGRITY")) { //Here goes my other code } } } @Override public void onError(Throwable e) { } @Override public void onComplete() { } }); } private String getErrorText(Exception e) { String msg = e.getMessage(); if (msg == null) { return "Unknown Error"; } //the error code int errorCode = Integer.parseInt(msg.replaceAll("\n", "").replaceAll(":(.*)", "")); switch (errorCode) { case IntegrityErrorCode.API_NOT_AVAILABLE: return "API_NOT_AVAILABLE"; case IntegrityErrorCode.NO_ERROR: return "NO_ERROR"; case IntegrityErrorCode.INTERNAL_ERROR: return "INTERNAL_ERROR"; case IntegrityErrorCode.NETWORK_ERROR: return "NETWORK_ERROR"; case IntegrityErrorCode.PLAY_STORE_NOT_FOUND: return "PLAY_STORE_NOT_FOUND"; case IntegrityErrorCode.PLAY_STORE_ACCOUNT_NOT_FOUND: return "PLAY_STORE_ACCOUNT_NOT_FOUND"; case IntegrityErrorCode.APP_NOT_INSTALLED: return "APP_NOT_INSTALLED"; case IntegrityErrorCode.PLAY_SERVICES_NOT_FOUND: return "PLAY_SERVICES_NOT_FOUND"; case IntegrityErrorCode.APP_UID_MISMATCH: return "APP_UID_MISMATCH"; case IntegrityErrorCode.TOO_MANY_REQUESTS: return "TOO_MANY_REQUESTS"; case IntegrityErrorCode.CANNOT_BIND_TO_SERVICE: return "CANNOT_BIND_TO_SERVICE"; case IntegrityErrorCode.NONCE_TOO_SHORT: return "NONCE_TOO_SHORT"; case IntegrityErrorCode.NONCE_TOO_LONG: return "NONCE_TOO_LONG"; case IntegrityErrorCode.GOOGLE_SERVER_UNAVAILABLE: return "GOOGLE_SERVER_UNAVAILABLE"; case IntegrityErrorCode.NONCE_IS_NOT_BASE64: return "NONCE_IS_NOT_BASE64"; default: return "Unknown Error"; } } private String generateNonce(int length) { String nonce = ""; String allowed = getNonce(); for (int i = 0; i < length; i++) { nonce = nonce.concat(String.valueOf(allowed.charAt((int) Math.floor(Math.random() * allowed.length())))); } return nonce; } public native String getNonce(); static { System.loadLibrary("all-keys"); }
可能原因及解决方案
- 临时服务器波动:Google服务器偶尔会出现短时不可用,这是最常见的诱因。可以稍后重试,建议在代码中添加指数退避重试逻辑(比如首次等待1秒,第二次2秒,最多重试3次),避免频繁请求加剧服务器压力。
- 网络环境异常:
- 设备处于不稳定网络或受限环境(如企业内网、VPN),导致无法正常连接Google服务器。可切换至稳定Wi-Fi/移动数据测试,关闭无关VPN或代理。
- 检查Google Play服务版本,旧版本可能存在兼容性问题,前往Google Play商店更新至最新版。
- 配置遗漏或错误:
- 确认Cloud控制台已正确启用Play Integrity API,且API密钥的限制规则(绑定的应用包名、SHA-1证书指纹)完全正确。
- 核对Play控制台中应用的签名证书,确保与Cloud控制台配置的证书指纹一致(包括测试签名和发布签名场景)。
- 请求频率超限:即便错误码是
GOOGLE_SERVER_UNAVAILABLE,短时间内大量请求也可能触发服务器限流。检查代码是否存在重复调用requestIntegrityToken的情况,合理调整请求频率。 - Nonce生成问题:代码中Nonce依赖JNI的
getNonce()方法,需确认该方法返回的字符串合法,且最终生成的Base64编码Nonce符合要求(无换行、采用URL安全编码)。
内容的提问来源于stack exchange,提问作者androminor
相关产品推荐
相关产品推荐

