Flutterの記事を整理し本にしました
- 本稿の記事を含む様々な記事を体系的に整理し本にまとめました
- 今後はこちらを最新化するため、最新情報はこちらをご確認ください
- 10万文字を超える超大作になっています(笑)
はじめに
- FlutterのFirebaseパッケージのメソッドとかがコロコロ変わる印象があり、先人方のコピペで動かない事があったので、最新版で動くものを整理しました。
まとめ
概要
FirebaseのAuthenticationの基本については、Firebaseの機能1-1:Authentication(メール)をご参照ください。
Firebase Authentication(以下Authentication)には、メールとパスワード以外にも、様々なSNSとの連携が実現できるようになっています。
本チャプターでは、一番代表的なGoogleアカウントとの連携の実装を解説します。
この認証方法を使えば、メールアドレスを登録することなく、Googleアカウントさえ持っていれば、認証を通ることができます。
開発者側は、ユーザのUIDがメールでもGoogle認証でも同じように払い出されますので、認証後は統一したロジックで処理を行うことができます。
事前準備
共通の設定
まずは、FirebaseでGoogleAuthを有効化します。
Authenticationから、プロバイダーのGoogleを有効にします。
プロジェクトの公開名はデフォルトでも構いませんが、認証時にユーザに表示されます。
Androidの設定
AndroidではSHA1のフィンガープリントが必要になります。
% keytool -list -v-alias androiddebugkey -keystore ~/.android/debug.keystore
キーストアのパスワードを入力してください:
別名: androiddebugkey
作成日: 2020/08/09
エントリ・タイプ: PrivateKeyEntry
証明書チェーンの長さ: 1
証明書[1]:
所有者: C=US, O=Android, CN=Android Debug
発行者: C=US, O=Android, CN=Android Debug
シリアル番号: 1
有効期間の開始日: Sun Aug 09 19:24:48 PWT 2020終了日: Tue Aug 02 19:24:48 PWT 2050
証明書のフィンガプリント:
MD5: ********
SHA1: ********
SHA256: ********
署名アルゴリズム名: SHA1withRSA
バージョン: 1
まず、コマンドでSHA1のフィンガプリントを作成し、下記のアプリの設定部分に登録します。
パスワードは特にありませんので、そのままEnterを入れてください。
続いて、SHA1を設定した後は、再度google-services.json
をダウンロードし配置します。
google-services.json
の設定方法については、Firebase概要をご確認ください。
iOSの設定
<array>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLSchemes</key>
<array>
<string>{REVERSED_CLIENT_ID}</string>
</array>
</dict>
</array>
info.plistに設定を追加します。
下記イメージの通り、CFBundleURLSchemesにREVERSED_CLIENT_IDを設定します。
実装
ここ数年でメソッド名が変わったりしていますので、ご注意ください。
(FirebaseUserがUserに変更されたり、getCredentialがcredentialに変更されたりしています
本チャプターは下記のパッケージバージョンで動作確認をしています。
まず、必要なパッケージをインストールします。
必要に応じて、最新のバージョンをお使いください。
dependencies:
firebase_core: ^1.0.4
firebase_auth: ^1.1.1
google_sign_in: ^5.0.2
続いて、検証に用いる画面のソースコードになります。
ログインのページとログアウトのページを準備し、それぞれの動作を確認していきます。
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';
import 'package:firebase_test/LoginPage.dart';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: LoginPage(),
);
}
}
メイン画面は、LoginPageを呼び出すだけですが、Firebaseを初期化するために、main関数を非同期にした上で、初期化用のメソッドを呼んでいます。
import 'package:flutter/material.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:google_sign_in/google_sign_in.dart';
import 'package:firebase_test/LogoutPage.dart';
class LoginPage extends StatelessWidget {
static final googleLogin = GoogleSignIn(scopes: [
'email',
'https://www.googleapis.com/auth/contacts.readonly',
]);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Flutter Demo'),
),
body: Center(
child: TextButton(
onPressed: () async {
GoogleSignInAccount signinAccount = await googleLogin.signIn();
if (signinAccount == null) return;
GoogleSignInAuthentication auth =
await signinAccount.authentication;
final GoogleAuthCredential credential =
GoogleAuthProvider.credential(
idToken: auth.idToken,
accessToken: auth.accessToken,
);
User user =
(await FirebaseAuth.instance.signInWithCredential(credential))
.user;
if (user != null) {
await Navigator.of(context).pushReplacement(
MaterialPageRoute(builder: (context) {
return LogoutPage(user);
}),
);
}
},
child: Text(
'login',
style: TextStyle(fontSize: 50),
),
),
),
);
}
}
続いて、ログイン画面です。
画面には、ボタンが1つあるだけで、ログインボタンを押すと認証を行います。
処理は、GoogleSignIn
でアカウントを取得したあとに、GoogleSignInAuthentication,
とGoogleAuthCredential
で認証を行います。
Google認証が問題なく行われたあとに、この情報を使って、Firebaseに認証情報を登録します。
該当部分は、FirebaseAuth.instance.signInWithCredential(credential))
になります。
返ってきたユーザ情報を持って、ログアウトページに遷移しています。
import 'package:flutter/material.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:google_sign_in/google_sign_in.dart';
import 'package:firebase_test/LoginPage.dart';
class LogoutPage extends StatelessWidget {
User user;
LogoutPage(this.user);
static final googleLogin = GoogleSignIn(scopes: [
'email',
'https://www.googleapis.com/auth/contacts.readonly',
]);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Flutter Demo'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text("Hello ${user.displayName}", style: TextStyle(fontSize: 50)),
SizedBox(height: 20),
TextButton(
onPressed: () async {
FirebaseAuth.instance.signOut();
await googleLogin.signIn();
await Navigator.of(context)
.pushReplacement(MaterialPageRoute(builder: (context) {
return LoginPage();
}));
},
child: Text('Logout', style: TextStyle(fontSize: 50)),
)
],
),
),
);
}
}
最後は、ログアウト画面です。
ログアウト画面は、認証されたuser
のdisplayName
を使ってユーザ名を表示しています。
その下にログアウトのボタンを配置し、ボタンを押すとログアウトが行われます。
処理は、まずFirebaseAuth.instance.signOut();
でFirebaseのログアウトを行います。
次にgoogleLogin.signIn();
でGoogleのログアウトを行います。
最後に、ログインページに遷移しています。
動作イメージ
実際の動作イメージは下記のようになります。
初回のみ設定が必要となりますが、2回目からは問い合わせのみになるため、スムーズなログイン/ログアウトが行えます。
AndroidとiPhoneで表示される内容やステップが若干異なります。
また、2要素認証の有無によっても初回の動作が異なります。