今回はFirebaseを用いで電話番号認証機能を実装していきます。
前提
下記の設定は行なった前提で進めていきます。
1.FlutterとFirebaseを連携
2.Firebaseコンソールで電話番号認証を有効にする
バージョン
Flutter 3.0.0
firebase_core: ^1.17.1
firebase_auth: ^3.3.19
1. 各プラットフォームの設定
電話番号認証機能を実装するには各プラットフォームで設定を行う必要があります。
Android
デバッグ用に署名証明書SHA1を取得する必要があります。
プロジェクトのpathで下記コマンドを実行。
keytool -list -v -keystore ~/.android/debug.keystore -alias androiddebugkey -storepass android -keypass android
ターミナルからSHA1キーを確認することができるのでコピー。
証明書のフィンガプリント:
SHA1: <ここをコピー>
firebaseの「プロジェクトの設定」でプロジェクトと紐づいたAndroidアプリを開き、「SHA証明書フィンガープリント」部分に先ほどコピーしたキーを追加。
ios
iosではプッシュ通知の設定が必要になります。詳しくは下記の記事が参考になります。
web
登録済みwebアプリのOAuthリダイレクトドメインに、アプリケーションのドメインを追加する必要があります。ドメインの追加には下記の記事が参考になりそうです。
注意;電話番号認証は、実機とWebでのみ使用可能です。
シュミレーターでテストを行いたい場合はfirebaseで別途設定が必要になります。
詳細 → https://firebase.flutter.dev/docs/auth/phone/#testing
2.パッケージをインストール
電話番号認証を行う場合は下記2つのパッケージをインストールする必要があります。
flutter pub add firebase_core
flutter pub add firebase_auth
3.実装
スマートフォン(ios、Android)とWebでは異なるメソッドを使用する必要があり、今回はiosのみの実装なのでverifyPhoneNumber
メソッドを使用します。
フロント部分載せると冗長になりそうなので電話番号認証の実装部分のみ解説していきます。電話番号入力用のフォームと登録ボタンを設置し、登録ボタンを押下すると下記メソッドが発火するように実装。引数に入力された電話番号が入るようにしてください。
Future<void> verifyPhone(String phone) async {
await FirebaseAuth.instance.verifyPhoneNumber(
phoneNumber: '+81$phone',
verificationCompleted: (PhoneAuthCredential credential) {},
verificationFailed: (FirebaseAuthException e) {},
codeSent: (String verificationId, int? resendToken) {},
codeAutoRetrievalTimeout: (String verificationId) {},
);
}
詳しく解説していきます。
-
phoneNumber
国別の番号(日本は+81)と入力された電話番号をいれる。ここで入力された電話番号宛に認証コードが送信されます。 -
verificationCompleted
Androidの場合はこちらで実装を行います。今回はiosのみなので割愛。 -
verificationFailed
Firebaseのエラー(電話番号が正しくない等)が発生したときにここでエラーを受け取ることができます。
await FirebaseAuth.instance.verifyPhoneNumber(
verificationFailed: (FirebaseAuthException e) {
if (e.code == 'invalid-phone-number') {
print('電話番号が正しくありません。');
}
},
);
-
codeSent
このハンドラが起動したらshowDialog
等を用いてユーザーの認証コードの入力を待つ必要があります。
await FirebaseAuth.instance.verifyPhoneNumber(
codeSent: (String verificationId, int? resendToken) async {
final smsCode = '';
// ダイアログでユーザーの認証コード入力を待つ
await showDialog(
context: context,
builder: (_) {
return AlertDialog(
title: Text("認証コード"),
content: Text("SMS宛に届いた認証コードを入力してください"),
actions: <Widget>[
TextFormField(
onChanged: (value) {
smsCode = value;
},
),
ElevatedButton(
child: Text("認証"),
onPressed: () => Navigator.pop(context),
),
],
);
},
);
// 認証コード(smsCode)とverificationIdをfirebaseに送信して認証
final credential = PhoneAuthProvider.credential(verificationId: verificationId, smsCode: smsCode);
// 認証が完了したらFirebaseAuthにユーザー登録
await auth.signInWithCredential(credential);
},
);
-
codeAutoRetrievalTimeout
タイムアウト時間を指定して、指定時間が過ぎたらこちらのハンドラが発火します。
await auth.verifyPhoneNumber(
timeout: const Duration(seconds: 60),
codeAutoRetrievalTimeout: (String verificationId) {
// デフォルトでは30秒で発火
},
);
全体コード
iosのみの実装の場合は下記コピペで動くと思います。
Future<void> verifyPhone(String phone) async {
await FirebaseAuth.instance.verifyPhoneNumber(
phoneNumber: '+81$phone',
verificationCompleted: (PhoneAuthCredential credential) {
// iosの場合は空欄で問題なし
},
verificationFailed: (FirebaseAuthException e) {
if (e.code == 'invalid-phone-number') {
print('電話番号が正しくありません。');
}
},
codeSent: (String verificationId, int? resendToken) {
final smsCode = '';
await showDialog(
context: context,
builder: (_) {
return AlertDialog(
title: Text("認証コード"),
content: Text("SMS宛に届いた認証コードを入力してください"),
actions: <Widget>[
TextFormField(
onChanged: (value) {
smsCode = value;
},
),
ElevatedButton(
child: Text("認証"),
onPressed: () => Navigator.pop(context),
),
],
);
},
);
final credential = PhoneAuthProvider.credential(verificationId: verificationId, smsCode: smsCode);
await auth.signInWithCredential(credential);
},
codeAutoRetrievalTimeout: (String verificationId) {
// タイムアウト時の挙動を指定しない場合は空欄でも問題なし
},
);
}
動作例
電話番号認証はUXの向上や不正アカウントの防止などさまざまなメリットがありますし、firebaseを導入すると簡単に実装することができるので皆さんも是非実装してみてください。
参考