Flutter 接入 Google Sign In(不用Firebase)

Flutter 接入 Google Sign in

创建 OAuth Client

1. 前往 Google Cloud Console

Google Cloud Console

2. 创建一个新项目

image

image

image

5. 分别创建 iOS 和 Android 的 client

  • iOS

image

  • Android

image

6. 创建好后下载对应的plist(iOS)和 json(Android)文件

image
image

7. 将下载好的文件分别放到项目中(Android)

image

项目配置

1. 在Flutter依赖中添加依赖(pubspec.yaml)

image

2. 在 iOS 的 info.plist 文件中添加

<!-- Google Sign-in Section -->
<key>CFBundleURLTypes</key>
<array>
	<dict>
		<key>CFBundleTypeRole</key>
		<string>Editor</string>
		<key>CFBundleURLSchemes</key>
		<array>
			<!-- REVERSED_CLIENT_ID -->
			<string>你下载下来的 plist 文件中的 REVERSED_CLIENT_ID</string>
		</array>
	</dict>
</array>
<key>GIDClientID</key>
<string>你下载下来的 plist 文件中的 ClientId</string>

编写登录代码

下面是一个简单的工具类示例

import 'dart:convert';

import 'package:flutter/material.dart';
import 'package:google_sign_in/google_sign_in.dart';
import 'package:shared_preferences/shared_preferences.dart';

class GoogleAuthService {
  static final GoogleAuthService _instance = GoogleAuthService._internal();
  factory GoogleAuthService() => _instance;
  GoogleAuthService._internal();

  final GoogleSignIn _googleSignIn = GoogleSignIn(scopes: ['email', 'profile']);

  GoogleSignInAccount? _currentUser;
  bool _isSignedIn = false;

  GoogleSignInAccount? get currentUser => _currentUser;
  bool get isSignedIn => _isSignedIn;

  // 初始化服务
  Future<void> initialize() async {
    _googleSignIn.onCurrentUserChanged.listen((GoogleSignInAccount? account) {
      _currentUser = account;
      _isSignedIn = account != null;
      _saveUserToPrefs();
    });

    // 检查是否已经登录
    _currentUser = await _googleSignIn.signInSilently();
    _isSignedIn = _currentUser != null;
  }

  // 登录
  Future<GoogleSignInAccount?> signIn() async {
    try {
      final GoogleSignInAccount? account = await _googleSignIn.signIn();
      if (account != null) {
        _currentUser = account;
        _isSignedIn = true;
        await _saveUserToPrefs();
        return account;
      }
      return null;
    } catch (error) {
      debugPrint('Google Sign-In Error: $error');
      return null;
    }
  }

  // 登出
  Future<void> signOut() async {
    try {
      await _googleSignIn.signOut();
      _currentUser = null;
      _isSignedIn = false;
      await _clearUserFromPrefs();
    } catch (error) {
      debugPrint('Google Sign-Out Error: $error');
    }
  }

  // 获取用户详细信息
  Future<Map<String, dynamic>?> getUserInfo() async {
    if (_currentUser == null) return null;

    try {
      final GoogleSignInAuthentication auth =
          await _currentUser!.authentication;

      // 获取用户基本信息
      final userInfo = {
        'id': _currentUser!.id,
        'email': _currentUser!.email,
        'displayName': _currentUser!.displayName,
        'photoUrl': _currentUser!.photoUrl,
        'serverAuthCode': auth.serverAuthCode,
        'accessToken': auth.accessToken,
        'idToken': auth.idToken,
      };

      // 如果服务器授权码存在,可以用于后端验证
      if (auth.serverAuthCode != null) {
        // 这里可以调用你的后端API来验证token
        // await _verifyTokenWithBackend(auth.serverAuthCode!);
      }

      return userInfo;
    } catch (error) {
      debugPrint('Get User Info Error: $error');
      return null;
    }
  }

  // 保存用户信息到本地存储
  Future<void> _saveUserToPrefs() async {
    if (_currentUser == null) return;

    final prefs = await SharedPreferences.getInstance();
    final userData = {
      'id': _currentUser!.id,
      'email': _currentUser!.email,
      'displayName': _currentUser!.displayName,
      'photoUrl': _currentUser!.photoUrl,
    };

    await prefs.setString('google_user_data', jsonEncode(userData));
    await prefs.setBool('is_signed_in', true);
  }

  // 从本地存储清除用户信息
  Future<void> _clearUserFromPrefs() async {
    final prefs = await SharedPreferences.getInstance();
    await prefs.remove('google_user_data');
    await prefs.setBool('is_signed_in', false);
  }

  // 从本地存储加载用户信息
  Future<void> loadUserFromPrefs() async {
    final prefs = await SharedPreferences.getInstance();
    final isSignedIn = prefs.getBool('is_signed_in') ?? false;

    if (isSignedIn) {
      final userDataString = prefs.getString('google_user_data');
      if (userDataString != null) {
        try {
          final userData = jsonDecode(userDataString) as Map<String, dynamic>;
          // 注意:这里只是恢复基本信息,完整的GoogleSignInAccount对象需要重新登录
          _isSignedIn = true;
        } catch (e) {
          debugPrint('Error parsing user data: $e');
          await _clearUserFromPrefs();
        }
      }
    }
  }

  // 验证token与后端(可选)
  Future<bool> _verifyTokenWithBackend(String serverAuthCode) async {
    try {
      // 这里应该调用你的后端API来验证Google token
      // final response = await http.post(
      //   Uri.parse('YOUR_BACKEND_URL/verify-google-token'),
      //   body: {'serverAuthCode': serverAuthCode},
      // );
      // return response.statusCode == 200;
      return true; // 暂时返回true
    } catch (error) {
      debugPrint('Backend verification error: $error');
      return false;
    }
  }
}

大功告成!

参考:
Flutter Tutorial - Google SignIn WITHOUT Firebase
google_sign_in

posted @ 2025-08-02 02:06  ryand  阅读(180)  评论(0)    收藏  举报