はじめに
GameWith Advent Calendar 2018 21日目担当のkyamです。
初めはiOSエンジニアのキャリアを考えるという壮大なテーマを過去に自分が担当したプロジェクトを紹介しつつ書いていたのですが、長すぎるかつ自分語りが多すぎて客観的にこれどうなんだろうとなり、とりあえず下書きに保存しました。
というわけで今回は全然テーマが変わりましてiOSで電話番号認証を行う方法になります。
最近よく電話番号を入力し、iPhoneに送られた通知から確認コードを取得し、それをアプリ側で入力することでユーザー認証を済ませるというケースを見かけますが、過去に自分が担当したプロジェクトでは実装したことがなく少し気になったのと触る機会があったので調べてみて簡単に検証してみました。
Firebase Auth
みんな大好きFirebaseです。
Firebase Authentication
の中に電話番号の項目があり、どうやらFirebaseは電話番号での認証も対応しているようです。
今回はFirebase Authを用いて電話番号でアプリ内登録を行うサンプルコードを紹介します。
実装方法
準備としてCocoaPodsを用いて
pod 'Firebase/Auth'
で予めライブラリを導入しておく必要があります。
① 電話番号を元に確認コードを端末に送る
以下Firebaseガイドの引用です。
verifyPhoneNumber:UIDelegate:completion:
を呼び出すと、Firebaseからアプリにサイレントプッシュ通知が送信されるか、ユーザーに対してreCAPTCHAチャレンジ
が発行されます。
アプリが通知を受信した後、またはユーザーがreCAPTCHAチャレンジ
を完了した後、Firebaseから認証コードを含むSMSメッセージが指定の電話番号に送信され、確認IDが補完関数に渡されます。ユーザーをログインさせるには、確認コードと確認IDの両方が必要です。
上記の内容を実際にコードで書いてみると以下のようになります。
//"+1 ???-???-???"
let phoneNumber = "+1?????????"
PhoneAuthProvider.provider().verifyPhoneNumber(phoneNumber, uiDelegate: nil) { (verificationID, error) in
if let error = error {
self.showMessagePrompt(message: "ErrorDescription \(error.localizedDescription)")
return
}
// 確認IDをアプリ側で保持しておく
if let verificationID = verificationID {
print("verificationID \(verificationID)")
UserDefaults.standard.authVerificationID = verificationID
}
}
抑えておきたいポイントとしては、
-
+1 ???-???-???
のような形式の電話番号は+1?????????
として渡す- 正しいフォーマットでないとInvalid Formatのエラーが返ります
- ユーザー認証には確認コードだけでなく確認IDの両方が必要であること
- ユーザーが実際に入力するのは確認コードだけなので、確認IDはアプリ側で持っておく必要がある
② 確認コードを元に実際に認証を行う
guard let verificationID = UserDefaults.standard.authVerificationID else {
self.showMessagePrompt(message: "NoVerificationID")
return
}
let verificationCode = "123456"
let credential = PhoneAuthProvider.provider().credential(withVerificationID: verificationID, verificationCode: verificationCode)
Auth.auth().signInAndRetrieveData(with: credential) { (authResult, error) in
if let error = error {
self.showMessagePrompt(message: "ErrorDescription \(error.localizedDescription)")
return
}
if let authResult = authResult {
self.showMessagePrompt(message: "AuthResult \(authResult.user) \(String(describing: authResult.additionalUserInfo))")
}
}
これだけでFirebaseAuthの認証が完了します。
初めてログインすると、新しいユーザーアカウントが作成され実際にコンソールにログインすることでも確認できます。
reCAPTCHAチャレンジに関して
基本的にはアプリにサイレントプッシュ通知が送信されるのですが、ユーザーがアプリのバックグラウンド更新を無効にしている場合や、シミュレータでアプリをテストしている場合などは通知を受信できないためreCAPTCHAチャレンジを行うことになります。
上記のコード内のshowMessagePrompt
とUserDefault
に関して
それぞれ簡単なExtensionを用意しています。以下参考までにどうぞ。
extension UIViewController {
func showMessagePrompt(message: String) {
let alertController = UIAlertController(title: message, message: nil, preferredStyle: .alert)
let cancelAction = UIAlertAction(title: "OK", style: .cancel, handler: nil)
alertController.addAction(cancelAction)
(navigationController ?? self)?.present(alertController, animated: true, completion: nil)
}
}
private let AuthVerificationIDKey = "authVerificationID"
extension UserDefaults {
var authVerificationID: String? {
set(newValue) {
set(newValue, forKey: AuthVerificationIDKey)
synchronize()
} get {
return string(forKey: AuthVerificationIDKey)
}
}
}
終わりに
Firebase Authを使うことで簡単に電話番号での認証が行えました。
電話番号や確認コードの入力はUIを作る必要があるのですが、アプリに合ったUIを作れると思うとそれはそれで良いなと思いました。
明日の22日目も連続して自分が担当させていただきます。
明日は少し長い内容になりますがiOSエンジニアになりたい人が読むと良いかもしれない話についてです。
お楽しみに!