Android端Google Identity授权:如何获取刷新令牌?
解决Android端Google Drive后台同步的令牌过期问题
你当前使用的AuthorizationClient仅能获取短期访问令牌,不提供刷新令牌,这是因为它设计用于临时授权场景,无法满足后台无交互同步的需求。要实现持久化的后台同步,需要切换到Google Sign-In客户端或Google推荐的新APICredential Manager,这两者都能持久化用户授权状态并自动处理令牌刷新,无需用户重复操作(除非权限被撤销)。
方案一:使用Google Sign-In客户端(传统稳定方案)
1. 配置Google Sign-In客户端
首先在项目中添加Google Sign-In依赖,并在Google Cloud Console配置应用的OAuth 2.0客户端ID(需包含Android和Web客户端ID,用于令牌刷新)。
初始化Sign-In客户端:
GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN) .requestScopes(new Scope(DriveScopes.DRIVE_APPDATA)) .requestEmail() .build(); GoogleSignInClient mGoogleSignInClient = GoogleSignIn.getClient(this, gso);
2. 发起用户授权流程
首次登录时引导用户授权:
Intent signInIntent = mGoogleSignInClient.getSignInIntent(); startActivityForResult(signInIntent, RC_SIGN_IN);
3. 处理授权结果并构建Drive客户端
在onActivityResult中获取授权账户,后续可持久化该账户信息:
@Override public void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == RC_SIGN_IN) { Task<GoogleSignInAccount> task = GoogleSignIn.getSignedInAccountFromIntent(data); handleSignInResult(task); } } private void handleSignInResult(Task<GoogleSignInAccount> completedTask) { try { GoogleSignInAccount account = completedTask.getResult(ApiException.class); // 构建支持自动刷新的Drive客户端 GoogleCredentials credentials = GoogleCredentials.create( new AccessToken(account.getIdToken(), null)) .createScoped(Collections.singleton(DriveScopes.DRIVE_APPDATA)); Drive drive = new Drive.Builder( GoogleNetHttpTransport.newTrustedTransport(), GsonFactory.getDefaultInstance(), new HttpCredentialsAdapter(credentials)) .build(); // 持久化账户信息,用于后台同步 saveGoogleSignInAccount(account); // 执行首次同步 performDriveSync(drive); } catch (ApiException | IOException e) { Log.e(TAG, "授权失败: " + e.getMessage()); } }
4. 后台无交互同步
使用silentSignIn在后台自动获取有效令牌(无需用户操作):
private void syncInBackground() { mGoogleSignInClient.silentSignIn() .addOnSuccessListener(account -> { try { GoogleCredentials credentials = GoogleCredentials.create( new AccessToken(account.getIdToken(), null)) .createScoped(Collections.singleton(DriveScopes.DRIVE_APPDATA)); Drive drive = new Drive.Builder( GoogleNetHttpTransport.newTrustedTransport(), GsonFactory.getDefaultInstance(), new HttpCredentialsAdapter(credentials)) .build(); performDriveSync(drive); } catch (IOException e) { Log.e(TAG, "构建Drive客户端失败: " + e.getMessage()); } }) .addOnFailureListener(e -> { // 仅当权限被撤销、用户登出时失败,此时需引导用户重新授权 Log.e(TAG, "后台同步失败,需重新授权: " + e.getMessage()); // 可发送通知提示用户重新登录 }); }
方案二:使用Credential Manager(Google推荐新API)
Credential Manager是Google推出的统一凭据管理API,替代旧的Sign-In客户端,更简洁且支持多平台凭据类型。
1. 初始化Credential Manager并获取凭据
CredentialManager credentialManager = CredentialManager.create(context); // 构建获取已授权凭据的请求 GetCredentialRequest getRequest = new GetCredentialRequest.Builder() .addCredentialOption(new GoogleIdTokenCredentialOption.Builder() .setFilterByAuthorizedAccounts(true) .setServerClientId(getString(R.string.web_client_id)) // 需配置Web客户端ID .setScopes(Collections.singletonList(DriveScopes.DRIVE_APPDATA)) .build()) .build(); credentialManager.getCredentialAsync(getRequest, ContextCompat.getMainExecutor(context)) .addOnSuccessListener(result -> { GoogleIdTokenCredential credential = (GoogleIdTokenCredential) result.getCredential(); // 构建Drive客户端 GoogleCredentials googleCredentials = GoogleCredentials.create( new AccessToken(credential.getIdToken(), credential.getExpirationTime())) .createScoped(Collections.singleton(DriveScopes.DRIVE_APPDATA)); Drive drive = new Drive.Builder( GoogleNetHttpTransport.newTrustedTransport(), GsonFactory.getDefaultInstance(), new HttpCredentialsAdapter(googleCredentials)) .build(); performDriveSync(drive); }) .addOnFailureListener(e -> { // 无已授权账户,引导用户授权 CreateCredentialRequest createRequest = new CreateCredentialRequest.Builder() .addCredentialOption(new GoogleIdTokenCredentialOption.Builder() .setServerClientId(getString(R.string.web_client_id)) .setScopes(Collections.singletonList(DriveScopes.DRIVE_APPDATA)) .build()) .build(); credentialManager.createCredentialAsync(createRequest, ContextCompat.getMainExecutor(context)) .addOnSuccessListener(createResult -> { // 授权成功后执行同步 GoogleIdTokenCredential newCredential = (GoogleIdTokenCredential) createResult.getCredential(); // 构建Drive客户端并同步 }) .addOnFailureListener(createError -> { Log.e(TAG, "授权失败: " + createError.getMessage()); }); });
关键说明
AuthorizationClient仅适用于一次性临时授权,不支持持久化令牌刷新,因此不适合后台同步场景。- 上述两种方案均会自动处理令牌过期问题:GoogleCredentials会在令牌失效时自动调用刷新接口获取新令牌,无需手动干预。
- 仅当用户撤销应用权限或登出Google账号时,后台同步才会失败,此时需引导用户重新授权。
内容的提问来源于stack exchange,提问作者Renaud Cerrato
相关产品推荐
相关产品推荐

