ikuo00ukの日記

元エンジニアのプロダクトマネージャー。 読んだ本とか紹介しています。

Expo×Firebaseで電話番号認証をローカル環境で行う際の注意点

無駄にハマったので、メモとして残しておきます。(2019年の記事です)

目的

Firebaseの電話番号認証をExpoのローカル環境から行う。

環境設定

Expo側

expo init [プロジェクト名]

ちなみにexpoのnodeのバージョンは以下でしか動かないので注意

expo-cli supports following Node.js versions:
* >=8.9.0 <9.0.0 (Maintenance LTS)
* >=10.13.0 <11.0.0 (Active LTS)
* >=12.0.0 (Current Release)  

expoはblankで選択します。(TypeScriptにするかはお好みでどうぞ)
そうすると以下のようなディレクトリが成形されます。簡単。 スクリーンショット 2019-10-29 12.45.17.png

expo start  

これで、App.tsをいじっていけば動き出します。

Firebase側  

  • firebaseでプロジェクトを作成
  • プロジェクト作成後、アプリを作成を選択しプラットフォームはウェブにする。
  • 作成すると以下の情報が取得できるので、expo側に保存します。
    (今回はsrcディレクトリを作ってその中にfirebaseディレクトリを立てています。)

typescpirt:src/firebase/config.ts

  const firebaseConfig = {
    apiKey: xxxxx,
    authDomain: xxxxx,
    databaseURL: xxxxx,
    projectId: xxxxx,
    storageBucket: xxxxx,
    messagingSenderId: xxxxx,
    appId: xxxxx,
    measurementId: xxxx
  };

  export default firebaseConfig

以上の設定が終わったら、左タブからAuthenticationを選択して電話番号を有効にします。
スクリーンショット 2019-10-29 12.51.58.png

Expo側からFirebaseと接続を行う

1.Expoにfirebaseをinstallする。

npm install --save firebase  

これでexpoの中でfirebaseを扱えるようになりましたので、初期化させるtsファイルを作ります。

typescpirt:src/firebase/index.ts ``````javascript import firebaseConfig from './config' import * as firebase from 'firebase'

const fC = { apiKey: firebaseConfig.apiKey, authDomain: firebaseConfig.authDomain, databaseURL: firebaseConfig.databaseURL, storageBucket: firebaseConfig.storageBucket, messagingSenderId: firebaseConfig.messagingSenderId }

const firebaseApp = firebase.initializeApp(fC); firebaseApp.auth().languageCode = 'JP';

export { firebaseApp }

これで準備はOKです。
ExpoのApp.tsに上記のファイルをimportします。  

import { firebaseApp } from 'AppRoot/src/firebase'

## 電話番号認証を行う  
さてこっからはあと一息です。

[firebase公式ドキュメント](https://firebase.google.com/docs/auth/web/phone-auth)を読むと、 
> 電話番号ログインをアプリに追加する最も簡単な方法は、FirebaseUI を使用することです。このライブラリには、電話番号ログインのほか、パスワードに基づくログインやフェデレーション ログインのログインフローを実装するドロップイン式のログイン ウィジェットが含まれています。このドキュメントでは、Firebase SDK を使用して電話番号ログインフローを実装する方法について説明します。  

firebaseUIを使えば一瞬や..!と思ったのですが、[firebaseのgithub]((https://github.com/firebase)  )を探してもreact-native製は見つからず。
  
仕方ないので、UIと処理自体のコードは書くことにします。  

> 電話番号を使ってユーザーをログインさせる前に、Firebase の reCAPTCHA ベリファイアを設定する必要があります。Firebase は不正行為を防ぐ手段として reCAPTCHA を使用します。これにより、たとえば電話番号の確認リクエストがアプリで許可されたドメインから発信されたものかどうかを確認できます。

色んなqiitaやスタックオーバーフローを読んでもreact-native上にreCAPTCHAを作ることはできないことが判明したのでWebで専用ページを別途作る必要があります。(もしreact-native内に書けそうであれば共有お願いします。)

以下のようなキャプチャ用HTMLを書きます。

<!DOCTYPE html> Entering captcha

Please, enter captcha for continue


これをfirebase上にホストします。

firebaseを操作できるパッケージをインストールして、初期化します。

npm install -g firebase-tools firebase login
firebase init
hostingを選択して、指示通り進めていきdeployします。  
スクリーンショット 2019-10-29 13.13.37.png

これで準備は整ったので、Expo側からFirebaseへ呼び出し処理をします。

import { Linking } from 'expo' import * as WebBrowser from 'expo-web-browser'; import { CAPTCHA_URL_BASE } from './src/constants/Url' // sendPhoneNumber = () => { const { phoneNumber } = this.state

const captchaUrl = `${CAPTCHA_URL_BASE}?appurl=${Linking.makeUrl('')}`;
const listener = ({ url }) => {
  WebBrowser.dismissBrowser();
  const tokenEncoded = Linking.parse(url).queryParams['token'];
  if (tokenEncoded) {
    const token = decodeURIComponent(tokenEncoded);

    const captchaVerifier = {
      type: 'recaptcha',
      verify: () => Promise.resolve(token)
    };
    firebaseApp.auth().signInWithPhoneNumber(phoneNumber, captchaVerifier)
      .then(confirmResult => {
        console.log('confirmResult', confirmResult)
      }).catch(error => {
        console.log('error', error)
      });
  }
};
Linking.addEventListener('url', listener);
WebBrowser.openBrowserAsync(captchaUrl).then(() => {
  Linking.removeEventListener('url', listener);
});

}

expoのWebBrowserを使用して、ウェブ上のhtmlを一度呼び出してトークンを取得します。
問題なく取得したあと、firebaseのsiginInWithPhoneNumber関数の第二引数に渡す流れです。
第一引数には、通知を届ける電話番号を渡します。
※ちなみに電話番号は国際コードを引き渡す必要があります。
(09012345678ではなく、+8109012345678のように)

これで上手くいくはずなんですが、何度やっても通知が来ない...   firebaseのエミュレーターを立ち上げるのか?とかいろいろ試したのですが原因はfirebaseの設定にありました。

承認済みドメインを正しく設定しよう

<b>言いたいことはこれに付きます。 </b>firebaseのAuthenticationに承認済みドメインがあるのですが、 expoのドメインを正しく追加してあげないと通知は飛びません。

スクリーンショット 2019-10-29 15.00.44.png

これに記載されているドメインを、firebaseの承認済みドメインに設定してあげると無事通知が飛ぶようになりました。 意外と盲点だったりするので、みなさまお気をつけて...