Flutter对接Google登录流程
1. firebase平台配置(console.firebase.google.com/)
1.1 直接创建新的Firebase项目,然后添加Android应用
包名填写正确,其它不用管,无脑下一步
1.2 在身份验证中添加登录方法
直接勾选启用,添加支持账号就行
1.3 配置SHA-1指纹证书
配置完成下载最新的
json文件
2. 项目内配置
2.1 下载的文件到android\app目录下
2.1 配置文件修改
android\build.gradle.kts
allprojects {
repositories {
google()
mavenCentral()
}
}
plugins {
// ...
// Add the dependency for the Google services Gradle plugin
id("com.google.gms.google-services") version "4.4.3" apply false
id("com.google.cloud.artifactregistry.gradle-plugin") version "2.2.1"
}
val newBuildDir: Directory = rootProject.layout.buildDirectory.dir("../../build").get()
rootProject.layout.buildDirectory.value(newBuildDir)
subprojects {
val newSubprojectBuildDir: Directory = newBuildDir.dir(project.name)
project.layout.buildDirectory.value(newSubprojectBuildDir)
}
subprojects {
project.evaluationDependsOn(":app")
}
tasks.register<Delete>("clean") {
delete(rootProject.layout.buildDirectory)
}
增加这一块
plugins {
// ...
// Add the dependency for the Google services Gradle plugin
id("com.google.gms.google-services") version "4.4.3" apply false
id("com.google.cloud.artifactregistry.gradle-plugin") version "2.2.1"
}
android\settings.gradle.kts
pluginManagement {
val flutterSdkPath = run {
val properties = java.util.Properties()
file("local.properties").inputStream().use { properties.load(it) }
val flutterSdkPath = properties.getProperty("flutter.sdk")
require(flutterSdkPath != null) { "flutter.sdk not set in local.properties" }
flutterSdkPath
}
includeBuild("$flutterSdkPath/packages/flutter_tools/gradle")
repositories {
google()
mavenCentral()
gradlePluginPortal()
}
}
plugins {
id("dev.flutter.flutter-plugin-loader") version "1.0.0"
id("com.android.application") version "8.7.3" apply false
id("org.jetbrains.kotlin.android") version "2.1.0" apply false
// Google services 插件
id("com.google.gms.google-services") version "4.4.3" apply false
}
include(":app")
plugins增加这一块
// Google services 插件
id("com.google.gms.google-services") version "4.4.3" apply false
android\app\build.gradle.kts
plugins {
id("com.android.application")
id("kotlin-android")
// The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins.
id("dev.flutter.flutter-gradle-plugin")
// Add the Google services Gradle plugin
id("com.google.gms.google-services")
}
dependencies {
// Import the Firebase BoM
implementation(platform("com.google.firebase:firebase-bom:34.1.0"))
implementation("com.google.android.gms:play-services-auth")
// TODO: Add the dependencies for Firebase products you want to use
// When using the BoM, don't specify versions in Firebase dependencies
implementation("com.google.firebase:firebase-analytics")
// Add the dependencies for any other desired Firebase products
// https://firebase.google.com/docs/android/setup#available-libraries
}
android {
namespace = "com.your.project"
compileSdk = flutter.compileSdkVersion
ndkVersion = "27.0.12077973"
compileOptions {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}
kotlinOptions {
jvmTarget = JavaVersion.VERSION_11.toString()
}
defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId = "com.your.project"
// You can update the following values to match your application needs.
// For more information, see: https://flutter.dev/to/review-gradle-config.
minSdk = flutter.minSdkVersion
targetSdk = flutter.targetSdkVersion
versionCode = flutter.versionCode
versionName = flutter.versionName
}
buildTypes {
release {
// TODO: Add your own signing config for the release build.
// Signing with the debug keys for now, so `flutter run --release` works.
signingConfig = signingConfigs.getByName("debug")
}
}
}
flutter {
source = "../.."
}
plugins增加这一块
// Add the Google services Gradle plugin
id("com.google.gms.google-services")
增加这一块
dependencies {
// Import the Firebase BoM
implementation(platform("com.google.firebase:firebase-bom:34.1.0"))
implementation("com.google.android.gms:play-services-auth")
// TODO: Add the dependencies for Firebase products you want to use
// When using the BoM, don't specify versions in Firebase dependencies
implementation("com.google.firebase:firebase-analytics")
// Add the dependencies for any other desired Firebase products
// https://firebase.google.com/docs/android/setup#available-libraries
}
3.实际应用
封装的服务工具
import 'dart:async';
import 'package:google_sign_in/google_sign_in.dart';
import 'package:dio/dio.dart';
import 'package:yourapp/app/utils/logger/logger.dart';
/// Google 登录全局服务(单例)
/// 支持:
/// - 全局唯一实例
/// - 登录/登出状态监听
/// - 获取服务端授权码
/// - 与后端 quickLogin 接口对接
class GoogleSignInService {
// ------------------- 单例实现 -------------------
static final GoogleSignInService _instance = GoogleSignInService._internal();
factory GoogleSignInService() => _instance;
GoogleSignInService._internal();
// ------------------- 内部属性 -------------------
final GoogleSignIn _googleSignIn = GoogleSignIn.instance;
// 当前登录的 Google 用户对象
GoogleSignInAccount? currentUser;
// 服务端授权码,用于后端 quickLogin
String serverAuthCode = '';
// 错误提示信息
String errorMessage = '';
// 登录状态广播(支持多处监听)
final StreamController<GoogleSignInAccount?> _loginStateController =
StreamController<GoogleSignInAccount?>.broadcast();
/// 登录状态变化流(可用 StreamBuilder 监听)
Stream<GoogleSignInAccount?> get onLoginStateChanged =>
_loginStateController.stream;
/// 快捷判断当前是否已登录
bool get isLoggedIn => currentUser != null;
// ------------------- 初始化 -------------------
/// 初始化 GoogleSignIn 实例,注册登录事件监听
Future<void> initialize({String? clientId, String? serverClientId}) async {
await _googleSignIn.initialize(
clientId: clientId,
serverClientId: serverClientId,
);
// 监听登录事件(SignIn/SignOut)
_googleSignIn.authenticationEvents
.listen(_handleAuthenticationEvent)
.onError(_handleAuthenticationError);
logger.i('✅ GoogleSignIn 初始化完成');
// 尝试自动登录(静默登录)
//await _googleSignIn.attemptLightweightAuthentication();
}
// ------------------- 登录 -------------------
/// 发起 Google 登录流程
Future<GoogleSignInAccount?> signIn() async {
try {
currentUser = await _googleSignIn.authenticate(); // 新 API
_loginStateController.add(currentUser);
logger.i('✅ 登录成功: ${currentUser?.displayName}, ${currentUser?.email}');
return currentUser;
} catch (e) {
errorMessage = 'Google 登录失败: $e';
_loginStateController.add(null);
logger.e(errorMessage);
return null;
}
}
// ------------------- 登出 -------------------
/// 退出登录,并清空缓存的用户信息
Future<void> signOut() async {
await _googleSignIn.disconnect();
currentUser = null;
serverAuthCode = '';
errorMessage = '';
_loginStateController.add(null);
logger.i('🚪 已退出登录');
}
// ------------------- 获取服务端授权码 -------------------
/// 获取 Google serverAuthCode,用于后端验证登录
Future<String?> getServerAuthCode() async {
if (currentUser == null) {
logger.w('⚠️ 获取授权码失败:当前用户为空');
return null;
}
// currentUser!
// 是当前已登录的 Google 用户对象(类型为 GoogleSignInAccount)。
// .authorizationClient
// 表示该用户的授权客户端对象,可以用来发起 OAuth2 授权。
// .authorizeServer([...])
// 发起服务端授权请求,让你的 app 能访问用户的某些数据(Scopes)。
try {
final GoogleSignInServerAuthorization? serverAuth = await currentUser!
.authorizationClient
.authorizeServer(['email', 'profile']);
serverAuthCode = serverAuth?.serverAuthCode ?? '';
logger.i('🔑 服务端授权码获取成功: $serverAuthCode');
return serverAuthCode;
} on GoogleSignInException catch (e) {
errorMessage = 'Google 授权异常 ${e.code}: ${e.description}';
logger.e(errorMessage);
return null;
} catch (e) {
errorMessage = '未知错误(授权阶段): $e';
logger.e(errorMessage);
return null;
}
}
// ------------------- quickLogin -------------------
/// 调用后端 quickLogin 接口,用 Google 信息登录/注册
Future<Map<String, dynamic>?> quickLogin() async {
if (currentUser == null) {
logger.w('⚠️ quickLogin 调用失败:用户未登录');
return null;
}
try {
final dio = Dio();
final data = FormData.fromMap({
'type': 'google',
'nickname': currentUser!.displayName ?? '',
'openid': currentUser!.id,
'avatar': currentUser!.photoUrl ?? '',
});
final response = await dio.post(
'',//自己的API接口地址
data: data,
options: Options(headers: {'server': 'true', 'think-lang': 'zh-tw'}),
);
logger.i('🧩 用户ID: ${currentUser!.id}');
logger.i('✅ 登录返回结果: ${response.data}');
return response.data;
} catch (e) {
logger.e('❌ quickLogin 请求出错: $e');
errorMessage = e.toString();
return null;
}
}
// ------------------- 内部事件处理 -------------------
// 当 Google 登录状态改变时触发
// event: GoogleSignInAuthenticationEvent 包含 SignIn 或 SignOut 事件
void _handleAuthenticationEvent(GoogleSignInAuthenticationEvent event) {
currentUser = switch (event) {
GoogleSignInAuthenticationEventSignIn() => event.user,
GoogleSignInAuthenticationEventSignOut() => null,
};
_loginStateController.add(currentUser);
logger.i(
currentUser == null ? '👋 检测到登出事件' : '🙌 检测到登录事件: ${currentUser?.email}',
);
}
// 处理 Google 登录异常
// 当登录过程中出现异常时调用
void _handleAuthenticationError(Object e) {
currentUser = null;
_loginStateController.add(null);
errorMessage = e is GoogleSignInException
? 'Google 登录异常 ${e.code}: ${e.description}'
: '未知错误: $e';
logger.e(errorMessage);
}
// ------------------- 销毁 -------------------
/// 释放资源(一般不需要调用)
void dispose() {
_loginStateController.close();
}
}
调用
一、初始化(App 启动时调用)
在你的 main.dart 或者 App 初始化逻辑中(比如 main() 或 initState()),先初始化服务:
import 'package:yourapp/app/service/google_signin_service.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
// 初始化 Google 登录服务
await GoogleSignInService().initialize(
clientId: null,
serverClientId: null,
);
runApp(MyApp());
}
二、在登录页面使用(发起登录)
在 LoginView 或者登录按钮点击事件中:
import 'package:yourapp/app/service/google_signin_service.dart';
import 'package:flutter/material.dart';
class LoginView extends StatefulWidget {
const LoginView({super.key});
@override
State<LoginView> createState() => _LoginViewState();
}
class _LoginViewState extends State<LoginView> {
final _googleService = GoogleSignInService();
Future<void> _handleGoogleLogin() async {
final user = await _googleService.signIn();
if (user == null) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('登录失败,请重试')),
);
return;
}
// 拿到 serverAuthCode(可选)
final authCode = await _googleService.getServerAuthCode();
print('🔑 服务端授权码:$authCode');
// 调后端 quickLogin
final result = await _googleService.quickLogin();
print('✅ 后端返回:$result');
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: ElevatedButton.icon(
icon: const Icon(Icons.login),
label: const Text('使用 Google 登录'),
onPressed: _handleGoogleLogin,
),
),
);
}
}
三、登出
await GoogleSignInService().signOut();
可以放在 “退出登录” 按钮 或 “个人中心” 里。
四、实时监听登录状态(推荐做法)
在任意页面,你可以用 StreamBuilder 监听登录状态:
StreamBuilder(
stream: GoogleSignInService().onLoginStateChanged,
builder: (context, snapshot) {
final user = snapshot.data;
if (user == null) {
return const Text('未登录');
} else {
return Column(
children: [
CircleAvatar(backgroundImage: NetworkImage(user.photoUrl ?? '')),
Text(user.displayName ?? ''),
Text(user.email),
],
);
}
},
)
这样当用户登录或登出时,界面会自动刷新,无需手动 setState。
五、判断是否已登录(快速判断)
final loggedIn = GoogleSignInService().isLoggedIn;
if (loggedIn) {
print('当前已登录:${GoogleSignInService().currentUser?.email}');
}