Flutter谷歌账号登录插件google_sign_in的使用

Flutter谷歌账号登录插件google_sign_in的使用

插件介绍

google_sign_in 是一个用于Flutter应用集成Google登录功能的插件。它允许用户通过Google账户进行身份验证,从而简化了应用程序中的用户认证流程。该插件支持多个平台,包括Android、iOS、macOS和Web。

平台支持

平台 支持版本
Android SDK 16+
iOS 12.0+
macOS 10.15+
Web Any

平台集成

Android集成

要访问Google登录,您需要确保注册您的应用程序。除非您使用的是需要google-services.json文件的Google服务,否则不需要包含此文件。但您确实需要在Google Cloud Platform API管理器中启用所需的OAuth API。例如,如果您想模仿Google登录示例应用的行为,则需要启用Google People API

请确保在控制台中填写所有必填字段以完成OAuth同意屏幕,否则可能会遇到APIException错误。

iOS集成

请参考Google Sign-In for iOS的集成说明

从2020年6月30日起,提交到Apple App Store的应用程序如果使用登录服务,则也必须提供“使用Apple登录”选项。可以考虑使用来自pub.dev的Apple登录插件,如sign_in_with_apple

macOS集成

请参考Google Sign-In for macOS的集成说明

Web集成

新SDK已将身份验证与授权完全分离,因此signInsignInSilently不再授权OAuthscopes。Flutter应用程序必须能够检测用户授予的权限范围,并确认这些授权是否仍然有效。有关详细信息,请参阅google_sign_in_web包

使用方法

导入插件

要使用此插件,请按照插件安装说明操作。

使用插件

初始化GoogleSignIn时指定所需的权限范围:

const List<String> scopes = <String>[
  'email',
  'https://www.googleapis.com/auth/contacts.readonly',
];

GoogleSignIn _googleSignIn = GoogleSignIn(
  // 可选clientId
  // clientId: 'your-client_id.apps.googleusercontent.com',
  scopes: scopes,
);

完整的可用权限列表见这里

现在可以在Dart代码中使用GoogleSignIn类进行身份验证:

Future<void> _handleSignIn() async {
  try {
    await _googleSignIn.signIn();
  } catch (error) {
    print(error);
  }
}

在Web端,建议使用Google登录按钮(而不是signIn方法),以确保用户身份验证包含有效的idToken

处理权限范围和增量授权

检查是否授予了权限范围

用户可能不会授予应用程序请求的所有权限范围。特别是在Web端,signInsilentSignInrenderButton小部件不会再授予任何权限范围。应用程序必须能够:

  • 检测经过身份验证的用户是否已授权所需权限。
  • 确认几分钟前授予的权限是否仍然有效。

使用canAccessScopes方法可以实现上述检查:

bool isAuthorized = account != null;
if (kIsWeb && account != null) {
  isAuthorized = await _googleSignIn.canAccessScopes(scopes);
}

请求更多权限

如果应用程序确定用户尚未授予所需权限,应发起授权请求(记住,在Web平台上,此请求必须由用户交互触发,如按钮点击):

Future<void> _handleAuthorizeScopes() async {
  final bool isAuthorized = await _googleSignIn.requestScopes(scopes);
  if (isAuthorized) {
    unawaited(_handleGetContact(_currentUser!));
  }
}

requestScopes返回一个布尔值,表示用户是否授予了所有请求的权限。

一旦应用程序确定当前用户isAuthorized可以访问所需的服务权限范围,就可以继续正常运行。

授权过期

在Web端,accessToken不再刷新,它会在3600秒(一小时)后过期,因此应用程序需要能够处理失败的REST请求,并更新UI以提示用户进行新的授权轮次。

示例代码

以下是完整的示例代码,展示了如何使用google_sign_in插件实现Google登录功能:

import 'dart:async';
import 'dart:convert' show json;

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:google_sign_in/google_sign_in.dart';
import 'package:http/http.dart' as http;

// The scopes required by this application.
const List<String> scopes = <String>[
  'email',
  'https://www.googleapis.com/auth/contacts.readonly',
];

GoogleSignIn _googleSignIn = GoogleSignIn(
  // Optional clientId
  // clientId: 'your-client_id.apps.googleusercontent.com',
  scopes: scopes,
);

void main() {
  runApp(
    const MaterialApp(
      title: 'Google Sign In',
      home: SignInDemo(),
    ),
  );
}

class SignInDemo extends StatefulWidget {
  const SignInDemo({super.key});

  @override
  State createState() => _SignInDemoState();
}

class _SignInDemoState extends State<SignInDemo> {
  GoogleSignInAccount? _currentUser;
  bool _isAuthorized = false; // has granted permissions?
  String _contactText = '';

  @override
  void initState() {
    super.initState();

    _googleSignIn.onCurrentUserChanged.listen((GoogleSignInAccount? account) async {
      bool isAuthorized = account != null;
      if (kIsWeb && account != null) {
        isAuthorized = await _googleSignIn.canAccessScopes(scopes);
      }

      setState(() {
        _currentUser = account;
        _isAuthorized = isAuthorized;
      });

      if (isAuthorized) {
        unawaited(_handleGetContact(account!));
      }
    });

    _googleSignIn.signInSilently();
  }

  Future<void> _handleGetContact(GoogleSignInAccount user) async {
    setState(() {
      _contactText = 'Loading contact info...';
    });
    final http.Response response = await http.get(
      Uri.parse('https://people.googleapis.com/v1/people/me/connections'
          '?requestMask.includeField=person.names'),
      headers: await user.authHeaders,
    );
    if (response.statusCode != 200) {
      setState(() {
        _contactText = 'People API gave a ${response.statusCode} '
            'response. Check logs for details.';
      });
      print('People API ${response.statusCode} response: ${response.body}');
      return;
    }
    final Map<String, dynamic> data = json.decode(response.body) as Map<String, dynamic>;
    final String? namedContact = _pickFirstNamedContact(data);
    setState(() {
      if (namedContact != null) {
        _contactText = 'I see you know $namedContact!';
      } else {
        _contactText = 'No contacts to display.';
      }
    });
  }

  String? _pickFirstNamedContact(Map<String, dynamic> data) {
    final List<dynamic>? connections = data['connections'] as List<dynamic>?;
    final Map<String, dynamic>? contact = connections?.firstWhere(
      (dynamic contact) => (contact as Map<Object?, dynamic>)['names'] != null,
      orElse: () => null,
    ) as Map<String, dynamic>?;
    if (contact != null) {
      final List<dynamic> names = contact['names'] as List<dynamic>;
      final Map<String, dynamic>? name = names.firstWhere(
        (dynamic name) => (name as Map<Object?, dynamic>)['displayName'] != null,
        orElse: () => null,
      ) as Map<String, dynamic>?;
      if (name != null) {
        return name['displayName'] as String?;
      }
    }
    return null;
  }

  Future<void> _handleSignIn() async {
    try {
      await _googleSignIn.signIn();
    } catch (error) {
      print(error);
    }
  }

  Future<void> _handleAuthorizeScopes() async {
    final bool isAuthorized = await _googleSignIn.requestScopes(scopes);
    setState(() {
      _isAuthorized = isAuthorized;
    });
    if (isAuthorized) {
      unawaited(_handleGetContact(_currentUser!));
    }
  }

  Future<void> _handleSignOut() => _googleSignIn.disconnect();

  Widget _buildBody() {
    final GoogleSignInAccount? user = _currentUser;
    if (user != null) {
      return Column(
        mainAxisAlignment: MainAxisAlignment.spaceAround,
        children: <Widget>[
          ListTile(
            leading: GoogleUserCircleAvatar(
              identity: user,
            ),
            title: Text(user.displayName ?? ''),
            subtitle: Text(user.email),
          ),
          const Text('Signed in successfully.'),
          if (_isAuthorized) ...<Widget>[
            Text(_contactText),
            ElevatedButton(
              child: const Text('REFRESH'),
              onPressed: () => _handleGetContact(user),
            ),
          ],
          if (!_isAuthorized) ...<Widget>[
            const Text('Additional permissions needed to read your contacts.'),
            ElevatedButton(
              onPressed: _handleAuthorizeScopes,
              child: const Text('REQUEST PERMISSIONS'),
            ),
          ],
          ElevatedButton(
            onPressed: _handleSignOut,
            child: const Text('SIGN OUT'),
          ),
        ],
      );
    } else {
      return Column(
        mainAxisAlignment: MainAxisAlignment.spaceAround,
        children: <Widget>[
          const Text('You are not currently signed in.'),
          buildSignInButton(
            onPressed: _handleSignIn,
          ),
        ],
      );
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Google Sign In'),
      ),
      body: ConstrainedBox(
        constraints: const BoxConstraints.expand(),
        child: _buildBody(),
      ),
    );
  }
}

这个示例代码展示了如何使用google_sign_in插件实现Google登录功能,并获取用户的联系人信息。希望这对您有所帮助!

1 回复

更多关于Flutter谷歌账号登录插件google_sign_in的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,下面是一个关于如何在Flutter应用中使用google_sign_in插件来实现谷歌账号登录的示例代码。

首先,确保你已经将google_sign_in插件添加到你的pubspec.yaml文件中:

dependencies:
  flutter:
    sdk: flutter
  google_sign_in: ^5.0.5  # 请检查最新版本号

然后,运行flutter pub get来安装该插件。

接下来,你需要配置Android和iOS平台以支持谷歌登录。

Android 配置

  1. android/app/src/main/AndroidManifest.xml文件中,添加以下权限和Activity配置:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.USE_CREDENTIALS" />

<application
    ...>
    <activity
        android:name=".MainActivity"
        android:launchMode="singleTop"
        android:theme="@style/LaunchTheme"
        android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
        android:hardwareAccelerated="true"
        android:windowSoftInputMode="adjustResize">
        ...
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
        <intent-filter>
            <action android:name="android.intent.action.VIEW" />
            <category android:name="android.intent.category.DEFAULT" />
            <category android:name="android.intent.category.BROWSABLE" />
            <data android:scheme="com.googleusercontent.apps.YOUR_CLIENT_ID"
                android:host="auth" />
        </intent-filter>
    </activity>
</application>

注意:将YOUR_CLIENT_ID替换为你的Google Cloud项目的客户端ID。

  1. android/app/build.gradle文件中,添加Google服务的依赖项:
dependencies {
    ...
    implementation 'com.google.android.gms:play-services-auth:19.0.0'  // 请检查最新版本号
}

iOS 配置

  1. ios/Runner/Info.plist文件中,添加以下配置:
<key>CFBundleURLTypes</key>
<array>
    <dict>
        <key>CFBundleTypeRole</key>
        <string>Editor</string>
        <key>CFBundleURLSchemes</key>
        <array>
            <string>com.googleusercontent.apps.YOUR_CLIENT_ID</string>
        </array>
    </dict>
</array>
<key>LSApplicationQueriesSchemes</key>
<array>
    <string>googlechrome</string>
    <string>com.google.chrome.ios</string>
</array>

同样,将YOUR_CLIENT_ID替换为你的Google Cloud项目的客户端ID。

  1. ios/Runner/AppDelegate.swift文件中,添加以下代码来处理回调URL:
import UIKit
import Flutter
import GoogleSignIn

@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
  override func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
  ) -> Bool {
    GeneratedPluginRegistrant.register(with: self)
    GIDSignIn.sharedInstance().clientID = "YOUR_CLIENT_ID"
    return super.application(application, didFinishLaunchingWithOptions: launchOptions)
  }

  override func application(_ app: UIApplication,
                            open url: URL,
                            options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
    if GIDSignIn.sharedInstance().handle(url,
                                         sourceApplication: options[UIApplication.OpenURLOptionsKey.sourceApplication] as? String,
                                         annotation: options[UIApplication.OpenURLOptionsKey.annotation]) {
      return true
    }
    return super.application(app, open: url, options: options)
  }
}

Flutter 代码

在你的Flutter项目中,你可以使用以下代码来实现谷歌登录:

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

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: SignInScreen(),
    );
  }
}

class SignInScreen extends StatefulWidget {
  @override
  _SignInScreenState createState() => _SignInScreenState();
}

class _SignInScreenState extends State<SignInScreen> {
  final GoogleSignIn _googleSignIn = GoogleSignIn();
  GoogleSignInAccount? _googleUser;

  void _handleSignIn() async {
    try {
      final GoogleSignInAccount? googleUser = await _googleSignIn.signIn();
      if (googleUser != null) {
        _googleUser = googleUser;
        _googleUser?.requestProfile().then((GoogleSignInProfile profile) {
          print(profile.displayName);
          print(profile.photoUrl);
          print(profile.email);
        });
      }
    } catch (e) {
      print(e);
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Google Sign In'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              _googleUser == null ? 'Sign in with Google' : 'You are signed in!',
            ),
            SizedBox(height: 20),
            _googleUser == null
                ? ElevatedButton(
                    onPressed: _handleSignIn,
                    child: Text('Sign in'))
                : ElevatedButton(
                    onPressed: () async {
                      await _googleSignIn.signOut();
                      setState(() {
                        _googleUser = null;
                      });
                    },
                    child: Text('Sign out')),
          ],
        ),
      ),
    );
  }
}

这个示例代码展示了如何使用google_sign_in插件来实现基本的谷歌账号登录功能。当用户点击“Sign in”按钮时,将启动谷歌登录流程。登录成功后,会显示用户的显示名称、照片URL和电子邮件。用户也可以点击“Sign out”按钮来注销。

请确保你已经按照Google Cloud文档配置了OAuth 2.0客户端ID,并且在你的项目中正确设置了重定向URI。

回到顶部
AI 助手
你好,我是IT营的 AI 助手
您可以尝试点击下方的快捷入口开启体验!