はじめに
近年ではモバイル系のクロスプラットフォーム開発のデファクトスタンダードとなっているFlutterですが、自分でも技術獲得をするためにアプリ開発をしていました。
なので、その際に学んだ知識についてブログにまとめていこうと思います。
完成イメージ
今回は、タイトルにある通りFirebase Authenticationを利用してGoogle認証ログイン機能の実装について紹介します。
動作としては以下のようなイメージになります。
pubspec.yamlにパッケージを追加
pubspec.yamlに以下の3つのパッケージを追加してflutter pub getします。
dependencies:
flutter:
sdk: flutter
flutter_localizations:
sdk: flutter
firebase_core: ^1.10.0
firebase_auth: ^3.2.0
google_sign_in: ^5.2.1
gradleにパスを追加(Androidの場合)
Androidの場合は、以下のように2つのgradleスクリプトを修正します。
- パッケージのbuild.gradle
buildscript {
...
dependencies {
classpath 'com.android.tools.build:gradle:4.1.0'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath 'com.google.gms:google-services:4.3.13'
}
}
- appのbuild.gradle
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'com.google.gms.google-services'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
Firebase Authenticationの設定
Firebase consoleでのAuthenticationのGoogle認証設定は以下のページでまとめているので参照して下さい。
設定が終わったら、Forebase consoleのプロジェクトの概要→プロジェクトの設定に進みgoogle-services.jsonをダウンロードします。
ダウンロードしたjsonファイルをAndroidプロジェクトのルートフォルダであるandroid/appのフォルダに配置します。
main.dartに初期化処理を追加
まずは、main.dartに以下のようにFirebaseの初期化処理を追加します。
import 'package:firebase_core/firebase_core.dart';
import 'package:growing_sake/firebase_google_auth.dart';
void main() async{
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(const GrowingSakeApp());
}
Google認証ログイン画面の実装
完成イメージにあるような画面の実装は以下のようになります。
認証処理で特に大事な部分についてを赤字にしています。
import 'package:flutter/material.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:google_sign_in/google_sign_in.dart';
import 'package:growing_sake/main.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
///
/// FirebaseでのGoogle認証によるログイン
///
class FirebaseGoogleAuth extends StatefulHookConsumerWidget {
const FirebaseGoogleAuth({Key? key}) : super(key: key);
@override
ConsumerState<FirebaseGoogleAuth> createState() => _FirebaseGoogleAuthState();
}
class _FirebaseGoogleAuthState extends ConsumerState<FirebaseGoogleAuth> {
// Google 認証
final _google_signin = GoogleSignIn(scopes: [
'email',
'https://www.googleapis.com/auth/contacts.readonly',
]);
late GoogleSignInAccount googleUser;
late GoogleSignInAuthentication googleAuth;
late AuthCredential credential;
// Firebase 認証
final _auth = FirebaseAuth.instance;
late UserCredential result;
User? user;
///
/// ユーザー画像を取得する
///
ImageProvider getUserImage(String? userImage) {
if (userImage != null && userImage != "") {
return NetworkImage(userImage);
} else {
return const AssetImage("images/account_black.png");
}
}
@override
Widget build(BuildContext context) {
final uid = ref.watch(uidProvider);
user = _auth.currentUser;
String? userImage;
String userName;
String loginState;
bool loginButtonEnable;
if (uid.compareTo("") == 0) {
userImage = "";
userName = "";
loginState = 'ログアウト中';
loginButtonEnable = true;
} else {
userImage = user?.photoURL;
userName = user?.displayName ?? "";
loginState = 'ログイン中';
loginButtonEnable = false;
}
return Scaffold(
body: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Padding(
padding: const EdgeInsets.fromLTRB(8, 4, 8, 4),
child: Container(
color: const Color(0xfff0f0f0),
padding: const EdgeInsets.fromLTRB(8, 16, 8, 16),
child: Column(
children: [
///
/// ログイン状態の場合はアイコンも表示する
///
Container(
width: 100,
height: 100,
padding: const EdgeInsets.fromLTRB(8, 0, 0, 0),
decoration: BoxDecoration(
shape: BoxShape.circle,
image: DecorationImage(
fit: BoxFit.fill,
image: getUserImage(userImage),
),
),
),
///
/// ログイン状態の場合はユーザー名も表示する
///
Container(
padding: const EdgeInsets.all(8),
child: Text(userName == "" ? loginState : userName),
),
///
/// 認証ボタンを横に並べる
///
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
///
/// Google認証によるログイン処理ボタン
///
ButtonTheme(
height: 60.0,
child: RaisedButton(
child: const Text('Google認証\nログイン',
style: TextStyle(fontWeight: FontWeight.bold),),
textColor: Colors.white,
color: loginButtonEnable ? Colors.lightGreen : Colors.grey,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
onPressed: () async {
if (!loginButtonEnable) return;
// Google認証の部分
googleUser = (await _google_signin.signIn())!;
googleAuth = await googleUser.authentication;
credential = GoogleAuthProvider.credential(
accessToken: googleAuth.accessToken,
idToken: googleAuth.idToken,
);
// Google認証を通過した後、Firebase側にログイン ※emailが存在しなければ登録
try {
result = await _auth.signInWithCredential(credential);
user = result.user;
ref.read(uidProvider.notifier).state = user!.uid;
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('ようこそ' + user!.displayName!)));
} catch (e) {
print(e);
}
}
),
),
///
/// Google認証によるログアウト処理ボタン
///
ButtonTheme(
height: 60.0,
child: RaisedButton(
child: const Text('Google認証\nログアウト',
style: TextStyle(fontWeight: FontWeight.bold),),
textColor: Colors.white,
color: loginButtonEnable ? Colors.grey : Colors.lightGreen,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
onPressed: () {
if (loginButtonEnable) return;
_auth.signOut();
_google_signin.signOut();
ref.read(uidProvider.notifier).state = "";
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('ログアウトしました')));
}
),
),
],
),
],
),
),
),
],
),
),
);
}
}
さいごに
今回の内容は以上となります。
この実装をしたAndroidアプリはGooglePlayで公開されていますので是非参照してみて下さい!
また、ソースコードについてもGitHubで公開しています!