FlutterでGoogle/Apple認証 on Firebase
FlutterでFirebase Authenticationを利用し、Google認証・Apple認証を実装しました。巷で見かける情報通りで行かない部分もあり、結構苦戦したので書き留めておきます。
ゴール
最終的にはこれができるようになりました。
- Androidで
- Google認証でサインインができる
- iOSで
- Apple認証でサインインができる
- Google認証でサインインができる
ポイントとしては、『AndroidでApple認証をやらない』ですね。これはちょっと面倒くさそうだったということと、Android使ってるユーザーなんてGoogle認証ありゃいいでしょ、と高をくくった結果であります。(やりたいって方は、調べた内容を後述してあるので参考にしてみてください)
環境
時代とともに変わる部分もあるかと思いますので、各種バージョンを記しておきます。
- Mac OS 15.5
- Flutter 3.27.4
- firebase_core 3.14.0
- firebase_auth 5.6.0
- google_sign_in 6.3.0
Firebaseプロジェクトの作成
いの一番にやることはFirebaseプロジェクトのセットアップです。おすすめは、開発初期から本番環境用プロジェクトも作っておくことです。この手の設定って、あとから振り返ると「あれ・・、どこどこいじったんだっけ・・・?」となりがちなので、最初にまとめてやっておいたほうが楽で確実です。どうせFirebaseは無料枠あるので作って寝かしておいてもお金かからないし。
私はFirebase コンソールから、ポチポチチと作りました。
(この作業は必須ではないですが)ちゃんと本番環境用のプロジェクトは『環境の種類』を本番環境にしておきましょう。赤いアイコンが付いて間違えることが少なくなると思います。
CLIのセットアップ
firebase CLI
最初にfirebase CLIのインストールが必要です。次のサイトに従ってインストールします。私はnpmで入れました。
npm install -g firebase-tools
flutterfire
次にflutter+firebase用のCLIであるflutterfire
をセットアップします。基本的には次のサイトに沿ってやっていきます。
firebaseにログインします。
firebase login
そしてアクティベートが必要です。
dart pub global activate flutterfire_cli
# fvm使ってる人は↓こちら↓
fvm dart pub global activate flutterfire_cli
これでflutterfire
というコマンドが使用できるようになります。
Flutterプロジェクトに適用
Firebaseを導入したいFlutterプロジェクトのルートで次のコマンドを実行します。このとき、Google認証やApple認証に必要なパッケージもあわせてインストールします。
flutter pub add firebase_core firebase_auth google_sign_in
# fvm使ってる人は↓こちら↓
fvm flutter pub add firebase_core firebase_auth google_sign_in
configureコマンドで初期化します。flutterfireに色々と汚されるので、あらかじめコミットしておきましょう。コマンドを実行すると、「どのFirebaseプロジェクトを使用するんだ?」的なことを聞かれるので、開発環境用のプロジェクトを選択します。あと、適用するプラットフォームとか聞かれるので、iOSとAndroidを選択しておきます(ここはプロジェクトに応じてお好きなように)。
flutterfire configure
しばらくガチャガチャしてコマンドが正常に終了したらgitの差分を見てみましょう。きっと、lib直下にfirebase_options.dart
というファイルができているはずです。こいつの中身を見てみると、apiKey
やappId
とかが設定されているはず。これはFirebaseプロジェクトの設定画面に記載されている内容で、flutterfireが自動的に設定してくれたのですね。ちなみにFirebaseプロジェクトの設定画面とは、↓この『プロジェクトの設定』メニュー↓からいけるところです。
ではこの設定値を使用してFirebaseを初期化するようにlib/main.dart
に必要なコードを挿入します。
import 'package:firebase_core/firebase_core.dart';
import 'firebase_options.dart';
...
void main() async {
WidgetsFlutterBinding.ensureInitialized();
...
// このコードを挿入
await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform,
);
...
runApp(const MyApp());
...
開発環境用はこれでOKなのですが、本番環境用の設定が必要です。ビルドによって使用する設定値を切り替えられるように次のような感じでfirebase_options.dart
を編集します。各値をどう設定するかは後に登場するgoogle-services.json
、GoogleService-Info.plist
を見れば分かると思います。
...
static const FirebaseOptions android = kReleaseMode
? FirebaseOptions(
apiKey: '本番用のapiKey',
appId: '本番用のappId',
messagingSenderId: '本番用のmessagingSenderId',
projectId: '本番用のprojectId',
storageBucket: '本番用のstorageBucket',
)
: FirebaseOptions(
apiKey: '開発用のapiKey',
appId: '開発用のappId',
messagingSenderId: '開発用のmessagingSenderId',
projectId: '開発用のprojectId',
storageBucket: '開発用のstorageBucket',
);
...
上記はandroidの例ですが、iOSも(必要ならWebも)同様にやっておきます。
認証の基本準備に関してはこれで完了です。といってもまだまだ設定は必要なのですが、順に説明していきます。
Google認証
基本的にはここに情報が詰まっています。
実装
Google認証の実装についてはこのページですね。メインとなるサインイン処理はこれぐらいです。
import 'package:google_sign_in/google_sign_in.dart';
Future<UserCredential> signInWithGoogle() async {
// Trigger the authentication flow
final GoogleSignInAccount? googleUser = await GoogleSignIn().signIn();
// Obtain the auth details from the request
final GoogleSignInAuthentication? googleAuth = await googleUser?.authentication;
// Create a new credential
final credential = GoogleAuthProvider.credential(
accessToken: googleAuth?.accessToken,
idToken: googleAuth?.idToken,
);
// Once signed in, return the UserCredential
return await FirebaseAuth.instance.signInWithCredential(credential);
}
ただ個人的にはいくつか補足が必要かなと思いました。
SignInメソッドはアカウント作成・ログイン兼用
FirebaseのsignInWithCredentialメソッドは、該当するアカウントが存在しない場合は自動的に新規アカウントを作成し、存在する場合はそのアカウントでログインします。つまり、アカウント作成とログインを別々に実装する必要がありません。ただ、アカウント作成なのかログインなのかで認証後のメッセージは分けたかったので、次のコードで見分けることにしました。
final result = await FirebaseAuth.instance.signInWithCredential(credential);
result?.additionalUserInfo?.isNewUser ?? false //アカウント作成だったらtrueになる
「Googleでサインイン」ボタンはガイドラインがある
以下のリンク先にそれがあります。一応則ってないといけないらしいので、ちゃんとデザインしてあげないといけません。
なお、その手の認証ボタンを集めたpubパッケージもあるようなので、楽したければそっち使ったほうがいいかもしれません。(私は依存関係を減らしたいので自作しました)
Google認証だとdisplayName, email, photoUrlが取れる
GoogleでサインインするとuserのdisplayName
、email
、photoUrl
が取得できます。photoUrlがあるとプロフィール画面のアバター画像とか簡単に出せるので便利。メールアドレスを欲するアプリ開発の場合も便利なんじゃないかと思いました。このあたり、取れるもの取れないものは認証プロバイダによります。
ログインプロバイダの追加
さてボタンを置き、先のコードを呼び出すようにしてもまだGoogle認証は動きません。まず、ログインプロバイダにGoogleを追加しないといけません。Firebaseプロジェクトの[Authentication]-[ログイン方法]からGoogleを有効にするだけです。
さらに設定は続く・・・ここからはAndroid/iOSで別立てになってます。
for Android
SHA1証明書(開発用)
前述のログインプロバイダ追加のダイアログにも書かれていたのですが、SHA証明書のフィンガープリントをFirebaseプロジェクトにアップロードする必要があります。開発用のフィンガープリントは次のコマンドで表示されるSHA1のフィンガープリントをコピーします。(本番は後述)
keytool -list -v -keystore ~/.android/debug.keystore -alias androiddebugkey -storepass android -keypass android
コピーしたら、貼り付けに行きます。例のプロジェクトの設定画面でフィンガープリントを登録します。
SHA1証明書(本番用)
では本番はどうするかというと、私の場合はすでに公開済みのアプリだったのですでに署名済みでした。Google Play Consoleの次の場所からゲットできます。
開発同様、本番用のFirebaseプロジェクトにSHA1のフィンガープリントを登録しておきます。
gradleの設定
(ひょっとしたらflutterfireが勝手にやってくれたかもしれないが一応記載)
ちょこちょこ、ビルド設定に追加が必要みたい。
plugins {
id "com.android.application"
id "kotlin-android"
id "dev.flutter.flutter-gradle-plugin"
+ id "com.google.gms.google-services"
}
...
defaultConfig {
- minSdkVersion flutter.minSdkVersion
+ minSdkVersion 23
plugins {
id "dev.flutter.flutter-plugin-loader" version "1.0.0"
id "com.android.application" version "8.4.1" apply false
id "org.jetbrains.kotlin.android" version "2.0.0" apply false
+ id "com.google.gms.google-services" version "4.4.0" apply false
}
google-services.json
最後にキーjsonをFlutterプロジェクトに仕込む必要があります。Firebaseプロジェクトの設定画面からgoogle-service.json
をダウンロードします。
ダウンロードしたらFlutterプロジェクトの次のディレクトリに配置します。(ディレクトリがなければ作成してください)
- android/app/src/debug/google-services.json ... 開発用
- android/app/src/release/google-services.json ... 本番用
これでビルドに応じたファイルが使用されるようになっています。あと忘れずに.gitignore
にも追加しておきましょう。
google-services.json
AndroidはこれでGoogle認証ができるようになっているはず。エミュレーターでもちゃんと動くので試してみましょう。
for iOS
iOSのほうは挫けそうになるぐらい面倒くさいです。
GoogleService-Info.plist
まずAndroidでいうgoogle-services.jsonにあたるGoogleService-Info.plist
というファイルを仕込む必要があるのですが、これが開発/本番を切り替えられるようにするのにひと手間必要です。
まずGoogleService-Info.plist
をダウンロードします。これはgoogle-services.jsonと同様にFirebaseプロジェクトの設定画面からダウンロードできます。
これを開発用と本番用をそれぞれダウンロードしてきて、それぞれ GoogleService-Info_Debug.plist
GoogleService-Info_Release.plist
にリネームします。2つのファイルを選択してドラッグしたら、XcodeでRunner
の中にドロップします。できたらこんな感じになるはず。
続いて、ビルド時に自動的に適した方を使用するようにスクリプトを仕込みます。以下のサイトが大変参考になりました。
私はならってこのように設定しました。
cp -f "$SRCROOT/GoogleService-Info_${CONFIGURATION}.plist" "${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.app/GoogleService-Info.plist"
これでビルド環境に応じたファイルが使用されることとなります。
URL Types
これがないとiOSでGoogleでサインインしようとするとクラッシュします。Xcodeからも設定できますが、Info.plist
を直接編集したほうが早いと思います。以下の通り追加。設定する値はGoogleService-Info.plistのREVERSED_CLIENT_ID
になります。arrayなので開発用・本番用まとめて設定できます。
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLSchemes</key>
<array>
<!-- 開発用・本番用ともに -->
<string>com.googleusercontent.apps.XXXXXX</string>
<string>com.googleusercontent.apps.XXXXXX</string>
</array>
</dict>
<dict/>
</array>
以上でiOSでもGoogle認証が利用できるようになります。
あーしんどかった。。。
Apple認証
では続いてApple認証の方です。iOSだけを対象にしています。
実装
サインインの処理は基本的にはこれだけです。
Future<UserCredential?> signInWithApple() async {
final appleProvider = AppleAuthProvider();
return await _auth.signInWithProvider(appleProvider);
}
googleの方は専用のpubパッケージを入れましたが、Appleの方は何も要りません。簡単ですね。
displayName, email, photoUrlは最初しか取れない
(自分で試したわけじゃないんですが)
Google認証の場合と異なり、displayName
、email
、photoUrl
はサインアップした初回しか取得できないらしいです。これはAppleのポリシーによるもので、個人を特定しかねないデータの取り扱いが厳しいらしいです。というわけで、上記項目がどうしても欲しい場合はサインアップ時にアプリ内のユーザー情報データなどに書き込んでおかないといけないみたい。
App IDにSign in with Apple
Apple Developer ProgramのCertificates, Identifiers & Profilesに行ってAppleサインインの権限を付与します。私はリリース済みのアプリだったので、すでにあるApp IDを下の画面から選択しました。
一覧の中からSign In with Apple
を探し出しチェックを入れます。その後、[Edit]ボタンを押し、出てくるダイアログは特に何も入れないままSaveする。で保存したら完了。
Runner.entitlements
XcodeのSigning & Capabilities
からSign In with Appleを追加します。
コードで編集する場合は以下です。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>aps-environment</key>
<string>development</string>
+ <key>com.apple.developer.applesignin</key>
+ <array>
+ <string>Default</string>
+ </array>
</dict>
</plist>
以上です。
これでApple認証の方も無事サインインできるようになるはず!
AndroidでもApple認証したい人向け
ログインプロバイダの追加のダイアログを埋めればいいようです。
やり方はこのページからのリンクを辿っていけば見つかりますが、結構ややこしいです。
エッセンスだけ書くと、
- Apple Developer Programへいって、Service IDを追加
- そのService IDにSign in with Appleを付与
- その際、さきほどのダイアログ下部に記載されているコールバックURLを指定する
- さらにKeysからKeyを作成
- そのKeyの名前と秘密鍵(ダウンロードできる)をさきほどのダイアログに貼り付ける
- AppleチームIDを入れる(Apple Developer Programに載ってる)
ということです。
おわりに
なんかめちゃくちゃ大作になってしまった・・・。記事を分けてBookにしたほうが良かったかも🤔
「間違ってる」「あれはどうなんだ?」的なことがあったらコメントお気軽にどうぞ。
Discussion