
Last updated on
在 Flutter 修復 Android 的 Google 登入(google_sign_in v7.1.1)
software-development
目錄
在 Flutter 修復 Android 的 Google 登入(google_sign_in v7.1.1)
問題描述
在 Flutter 專案中,iOS 的 Google 登入運作正常,但 Android 端卻出現 GoogleSignInException.clientConfigurationError
,即便 Firebase 設定與 SHA 憑證都已正確配置。
環境:
- Flutter SDK: 3.9.0+
- google_sign_in: 7.1.1
- firebase_auth: 5.7.0
- 平台:Android
釐清的根因
1. 缺少 Android 相依套件
Android 專案的 build.gradle
少了 Google Play Services 的驗證函式庫,導致登入流程無法正確執行。
2. 錯誤的 GoogleSignIn API 使用方式
google_sign_in
套件在 v7.1.1 與舊版有相容性變更:
- 採用
GoogleSignIn.instance
的單例模式 - 初始化方式改為以
initialize()
並需要serverClientId
- 驗證流程方法名稱與行為改變
GoogleSignInAuthentication
權杖結構調整
3. 未設定 Web Client ID
Android 必須顯式設定 OAuth 2.0 的 Web Client ID(client_type=3),有別於某些 iOS 場景能在未設定下仍可運作。
解決步驟
步驟一:加入必要的 Android 相依套件
在 android/app/build.gradle.kts
:
dependencies {
implementation("com.google.android.gms:play-services-auth:21.2.0")
}
這個相依套件是 Android 端 Google 登入必不可少的基礎。
步驟二:更新 GoogleSignIn 的實作
錯誤範例(v7.1.1 不適用):
// 錯誤的初始化方式
final authRepositoryProvider = Provider<AuthRepository>((ref) {
return AuthRepository(
FirebaseAuth.instance,
googleSignIn: GoogleSignIn.instance, // 缺少必要的設定
);
});
// 錯誤的登入流程
Future<User?> signInWithGoogle() async {
// 使用不存在的方法
await googleSignIn!.initialize();
if (!googleSignIn!.supportsAuthenticate()) {
throw AuthException('Not supported');
}
final googleUser = await googleSignIn!.authenticate();
// ...
}
正確作法(v7.1.1):
// 正確:以單例並搭配初始化設定
final _googleSignIn = GoogleSignIn.instance;
bool _googleSignInInitialized = false;
final authRepositoryProvider = Provider<AuthRepository>((ref) {
return AuthRepository(
FirebaseAuth.instance,
googleSignIn: _googleSignIn,
);
});
// 正確的登入流程
Future<User?> signInWithGoogle() async {
if (googleSignIn == null) {
throw AuthException('Google Sign-In not configured');
}
try {
// 僅初始化一次,並帶入 Web Client ID
if (!_googleSignInInitialized) {
await googleSignIn!.initialize(
serverClientId: 'YOUR_WEB_CLIENT_ID.apps.googleusercontent.com',
);
_googleSignInInitialized = true;
}
// v7.1.1 使用 authenticate()
final GoogleSignInAccount googleUser = await googleSignIn!.authenticate();
// 取得權杖
final GoogleSignInAuthentication googleAuth = googleUser.authentication;
// 建立 Firebase 憑證(注意:v7.1.1 僅有 idToken,沒有 accessToken)
final credential = GoogleAuthProvider.credential(
idToken: googleAuth.idToken,
);
// 登入 Firebase
final userCredential = await _firebaseAuth.signInWithCredential(credential);
return userCredential.user;
} on GoogleSignInException catch (e) {
if (e.code == GoogleSignInExceptionCode.canceled) {
throw AuthException('Sign in cancelled by user');
}
throw AuthException('Google sign-in failed: ${e.code}');
}
}
步驟三:修正權杖使用方式
錯誤作法:
// v7.1.1 沒有 accessToken
final credential = GoogleAuthProvider.credential(
accessToken: googleAuth.accessToken, // 這個屬性不存在
idToken: googleAuth.idToken,
);
正確作法:
// v7.1.1 僅使用 idToken
final credential = GoogleAuthProvider.credential(
idToken: googleAuth.idToken,
);
步驟四:更新靜默登入(silent sign-in)
Future<User?> signInWithGoogleSilently() async {
if (googleSignIn == null) {
return null;
}
try {
// 需要時再初始化
if (!_googleSignInInitialized) {
await googleSignIn!.initialize(
serverClientId: 'YOUR_WEB_CLIENT_ID.apps.googleusercontent.com',
);
_googleSignInInitialized = true;
}
// v7.1.1 使用 attemptLightweightAuthentication 進行靜默登入
final googleUser = await googleSignIn!.attemptLightweightAuthentication();
if (googleUser == null) {
return null;
}
final GoogleSignInAuthentication googleAuth = googleUser.authentication;
final credential = GoogleAuthProvider.credential(
idToken: googleAuth.idToken,
);
final userCredential = await _firebaseAuth.signInWithCredential(credential);
return userCredential.user;
} catch (e) {
return null; // 靜默登入失敗可靈活忽略
}
}
設定檢查清單
1. Firebase 主控台設定
- 在 Authentication 啟用 Google 登入
- 新增 Android App 並填入正確 Package Name
- 下載並放置
google-services.json
至android/app/
2. SHA 憑證
- 在 Firebase Console 新增 Debug SHA-1
- 新增 Release SHA-1(正式版必填)
取得 Debug SHA-1:
keytool -list -v -keystore ~/.android/debug.keystore \
-alias androiddebugkey -storepass android -keypass android
3. OAuth 2.0 用戶端 ID
- 在 Firebase Console 或 Google Cloud Console 找到 Web Client ID(client_type=3)
- 在
initialize()
以serverClientId
帶入此 ID
google-services.json
範例:
{
"oauth_client": [
{
"client_id": "xxx.apps.googleusercontent.com",
"client_type": 3 // Android 端需要的 Web Client ID
}
]
}
google_sign_in v7.1.1 的差異重點
面向 | 舊版 | v7.1.1 |
---|---|---|
初始化 | 直接建立實例 | GoogleSignIn.instance 單例 |
設定方式 | 以建構子參數 | 以 initialize(serverClientId) |
登入方法 | signIn() | authenticate() |
靜默登入 | signInSilently() | attemptLightweightAuthentication() |
權杖 | accessToken + idToken | 僅 idToken |
平台檢查 | supportsAuthenticate() | 不需要 |
常見陷阱
- 沒加入
play-services-auth
相依 → Android 端無法運作 - 使用錯的 Client ID → Android 必須使用 Web Client ID(type 3)
- 忘記初始化 → 認證前需以
serverClientId
呼叫initialize()
- 使用已棄用/變更的方法 → 升版請檢查 API 變更
- 少填 SHA 憑證 → Debug 與 Release 都要填
測試建議
-
變更後請重新建置:
flutter clean && flutter pub get
-
優先用實機測試(模擬器可能有 Google Play 服務問題)
-
觀察詳細日誌:
flutter run --verbose
-
驗證 Firebase 設定:
flutterfire configure
結論
升級到 google_sign_in v7.1.1
需要特別留意初始化方式、登入流程方法與權杖處理。Android 端的關鍵在於補齊 Play Services 相依,並在初始化時使用 Web Client ID。