Flutter Web中google_sign_in的renderButton登录流程卡顿问题排查
Flutter Web Google Sign In卡在gsi/transform页面的解决方法
针对你遇到的选择谷歌账号后卡在https://accounts.google.com/gsi/transform页面,且控制台报Uncaught TypeError: Cannot read properties of null (reading "postMessage')的问题,结合你的代码和已做的配置,以下是可能的遗漏点及解决方法:
1. 未绑定renderButton的登录回调逻辑
renderButton仅负责渲染谷歌登录按钮,不会自动处理完整的登录流程。你需要手动绑定onPressed回调,触发GoogleSignIn的登录方法,并处理后续的凭证交换(尤其是结合Firebase Auth时)。
修正代码:
在renderButton中添加onPressed参数,绑定自定义登录方法:
renderButton( configuration: GSIButtonConfiguration( shape: GSIButtonShape.pill, size: GSIButtonSize.medium, logoAlignment: GSIButtonLogoAlignment.center, ), onPressed: _handleSignIn, )
添加登录处理方法:
Future<void> _handleSignIn() async { setState(() { isLoading = true; _status = "正在登录..."; }); try { final account = await _gsi.signIn(); if (account != null) { // 获取谷歌认证凭证并同步到Firebase Auth final authDetails = await account.authentication; final firebaseCredential = GoogleAuthProvider.credential( accessToken: authDetails.accessToken, idToken: authDetails.idToken, ); await FirebaseAuth.instance.signInWithCredential(firebaseCredential); setState(() { _status = "登录成功: ${account.email}"; }); } } catch (e) { setState(() { _status = "登录失败: $e"; }); } finally { setState(() { isLoading = false; }); } }
2. 权限请求时机错误
你在onCurrentUserChanged回调中请求生日权限,此时用户可能尚未完成完整登录流程,容易导致权限请求失败并中断登录。建议将权限声明直接放在GoogleSignIn实例初始化时:
final GoogleSignIn _gsi = GoogleSignIn( clientId: '[MY_CLIENT_ID].apps.googleusercontent.com', scopes: ['https://www.googleapis.com/auth/user.birthday.read'], // 提前声明权限 );
3. Project IDX环境的特殊配置
Project IDX的预览URL为动态生成的域名(如https://xxxx-xxxx-xxxx-xxxx-xxxx.idx.googleusercontent.com),需确保:
- 该完整URL(包含
https://)已添加到谷歌云控制台的OAuth 2.0客户端ID的「已授权重定向URI」列表中 - 在
web/index.html的<head>中手动添加谷歌GSI脚本,确保加载顺序正确:
<script src="https://accounts.google.com/gsi/client" async defer></script>
4. 回调地址不匹配
谷歌OAuth要求重定向URI完全匹配,需检查:
- 若使用Firebase Auth,需将
https://<你的Firebase项目ID>.web.app/__/auth/handler添加到授权列表 - 确保Project IDX的预览URL没有端口或路径错误(比如末尾是否带斜杠)
5. 版本兼容性问题
确保google_sign_in和firebase_auth依赖为最新版本,避免因版本不兼容导致的通信问题。在pubspec.yaml中更新依赖:
dependencies: google_sign_in: ^5.4.0 firebase_auth: ^4.6.1
完整修正后的代码
import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:flutter/material.dart'; import 'package:firebase_auth/firebase_auth.dart'; import 'package:google_sign_in_web/web_only.dart'; import 'package:google_sign_in/google_sign_in.dart'; class LoginPage extends StatefulWidget { const LoginPage({super.key}); @override State<LoginPage> createState() => _LoginPageState(); } class _LoginPageState extends State<LoginPage> { final fireStoreInstance = FirebaseFirestore.instance; bool isLoading = false; String _status = "Checking login status..."; UserCredential? tempCred; final GoogleSignIn _gsi = GoogleSignIn( clientId: '[MY_CLIENT_ID].apps.googleusercontent.com', scopes: ['https://www.googleapis.com/auth/user.birthday.read'], ); GoogleSignInAccount? _currentUser; @override void initState() { super.initState(); _gsi.onCurrentUserChanged.listen((GoogleSignInAccount? account) { setState(() { _currentUser = account; _status = account?.email ?? "未登录"; }); }); // 尝试静默登录 _gsi.signInSilently().catchError((e) { setState(() { _status = "静默登录失败: $e"; }); }); } Future<void> _handleSignIn() async { setState(() { isLoading = true; _status = "正在登录..."; }); try { final account = await _gsi.signIn(); if (account != null) { final authDetails = await account.authentication; final firebaseCredential = GoogleAuthProvider.credential( accessToken: authDetails.accessToken, idToken: authDetails.idToken, ); await FirebaseAuth.instance.signInWithCredential(firebaseCredential); setState(() { _status = "登录成功: ${account.email}"; }); } else { setState(() { _status = "用户取消登录"; }); } } catch (e) { setState(() { _status = "登录失败: $e"; }); } finally { setState(() { isLoading = false; }); } } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( backgroundColor: Theme.of(context).primaryColor, toolbarHeight: 50, actions: [ IconButton( icon: const Icon(Icons.home_max_sharp), onPressed: () { Navigator.pop(context); }, ), ], ), body: Center( child: isLoading ? Column( mainAxisAlignment: MainAxisAlignment.center, children: [ const CircularProgressIndicator(), const SizedBox(height: 20), Text(_status), ], ) : Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ const SizedBox(height: 20), renderButton( configuration: GSIButtonConfiguration( shape: GSIButtonShape.pill, size: GSIButtonSize.medium, logoAlignment: GSIButtonLogoAlignment.center, ), onPressed: _handleSignIn, ), const SizedBox(height: 20), Text( _status, style: const TextStyle( fontSize: 16, color: Colors.red, ), ), ], ), ), ); } }
最后检查
- 清除浏览器缓存和Cookie,重新测试
- 确认谷歌云控制台的OAuth同意屏幕已添加测试用户(若应用未发布)
内容的提问来源于stack exchange,提问作者Ari S
相关产品推荐
相关产品推荐

