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已将身份验证与授权完全分离,因此signIn
和signInSilently
不再授权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端,signIn
、silentSignIn
或renderButton
小部件不会再授予任何权限范围。应用程序必须能够:
- 检测经过身份验证的用户是否已授权所需权限。
- 确认几分钟前授予的权限是否仍然有效。
使用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登录功能,并获取用户的联系人信息。希望这对您有所帮助!
更多关于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 配置
- 在
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。
- 在
android/app/build.gradle
文件中,添加Google服务的依赖项:
dependencies {
...
implementation 'com.google.android.gms:play-services-auth:19.0.0' // 请检查最新版本号
}
iOS 配置
- 在
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。
- 在
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。