React NativeでiPhoneアプリを作ることに慣れてきたら、アプリやwebサービスによくあるようなログイン機能を作ってみたくなりますよね?
ログイン機能があれば、TwitterのようなSNSサービスも作れますし、自分の資産を管理するMoney Forwordのようなサービスも作れます。
今回は、FirebaseというGoogleが提供するWebサービス(ログイン認証に使います)とReact Nativeを使って、iphoneアプリにログイン機能を実装する方法を紹介します。
Firebaseとは
Googleが提供するFirebaseはアプリ開発を最速に加速させるためのwebサービスで、様々な機能を提供しています。
- リアルタイムデータベース・・・データベースが更新されるとすぐに他の端末に通知されるようなデータベース
- ソーシャルログイン機能・・・FacebookやTwitter・Googleなどを使ってログインフォームを作れる機能
- ストレージ機能・・・S3のようにファイルを置いておけるサーバー機能
- パスワードログイン機能・・・emailとパスワードでログイン認証を作れる機能(今回使う機能)
などなど、たくさんの機能が提供されています(上記は、本当に提供されている機能の一部で、とっても優良なサービスがたくさん提供されています!)
今回は、このFirebaseのパスワードログイン機能を使って、アプリにログイン認証を組み込んでいきましょう。
Firebaseのパスワードログイン機能を利用する

https://firebase.google.com/?hl=ja
まずは上記のFirebaseにアクセスしてください。そして、googleのアカウントさえあれば、右上からすぐにログインができますので、ログインして、「コンソールへ移動」をクリックして、コンソールへ移動してください。

コンソールへ移動すると、google大好きの「The! マテリアルデザイン」のダッシュボード画面が現れますので、そちらで「プロジェクトを追加」をクリック!

プロジェクト名に適当な名前を入力して、国も適当に日本を選んで、プロジェクトを作成してください。

プロジェクトが作成できたら、そのプロジェクトのダッシュボード画面が開きます。
左の黒いメニュー一覧から、「Authentication」を選びましょう。

そして、Authenticationの画面の、「メール/パスワード」の選択肢の鉛筆マークを押すと、

「有効にする」というスライド式のボタンがポップアップで現れますので、そちらを有効にして、保存。
これで、Firebaseを利用して、ログイン認証(Email/Password認証)する準備が整いました。
React NativeにFirebaseのAuth認証を接続させる
Firebaseでログイン認証を使用する準備が出来たので、そのログイン認証機能をReact Native内で使用できるように組み込んでいきましょう。
今回は、React Native CLIで「react-native init プロジェクト名」で作成したファイル一式に「src」ディレクトリを追加して、そのsrcディレクトリの中だけでログインフォームを作っていきます。
まずは、firebaseモジュールをReact Nativeで使うために、プロジェクトディレクトリで
1 |
npm i -S firebase |
して、firebaseモジュールをインストールしてください。
そして、React Nativeのルートのindex.jsは
1 2 3 4 5 |
import React from 'react'; import { View, AppRegistry } from 'react-native'; import App from './src/App'; AppRegistry.registerComponent('test', () => App); |
srcディレクトリの中のApp.jsを読み込むだけの形にします。
※これで編集するファイルは全てsrcディレクトリの中だけになりました。
次に全てのコンポーネントを表示するApp.jsに、firebaseモジュールを使って、先程作ったFirebaseとの接続をする記述を書いていきます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
import React, { Component } from 'react'; import {View} from 'react-native'; import firebase from 'firebase'; import LoginForm from './LoginForm'; import Header from './Header'; class App extends Component { state = { loggedIn: null }; componentWillMount() { firebase.initializeApp({ apiKey: 'dummydummydummydummydummydummy', authDomain: 'dummydummydummydummydummydummy', databaseURL: 'dummydummydummydummydummydummy', projectId: 'dummydummydummydummydummy', storageBucket: 'dummydummydummydummydummydummy', messagingSenderId: 'dummydummydummydummydummy' }); firebase.auth().onAuthStateChanged((user) => { if (user) { this.setState({ loggedIn: true }); } else { this.setState({ loggedIn: false }); } }) } render() { return ( <View> <Header showText="ログイン" /> <LoginForm /> </View> ) } } export default App; |
- 3行目で firebaseをimport
- 11〜18行目で自分が作成したfirebaseのAPI認証情報を入力してください。これで、Firebaseを使った認証処理がReact Native内で使えるようになりました。(API認証情報の取得の仕方は、以下に記載)
- 20〜26行目は、これからつくっていくログインフォームで、ユーザーがログインに成功すると、stateのloggedInにtrueを失敗するとfalseを入れる処理です。
※API認証情報の取得の仕方

Firebaseのダッシュボードの中央の「ウェブアプリにFirebaseを追加」ボタンを押すとポップアップにて、
1 2 3 4 5 6 7 8 9 10 11 12 13 |
<script src="dummydummydummydummydummy"></script> <script> // Initialize Firebase var config = { apiKey: "dummydummydummydummydummy", authDomain: "dummy-dummy.firebaseapp.com", databaseURL: "https://dummy-dummy.firebaseio.com", projectId: "dummy-dummy", storageBucket: "dummy-dummy.appspot.com", messagingSenderId: "dummydummydummy" }; firebase.initializeApp(config); </script> |
というソースが出現しますので、configの中のオブジェクト「{}」をまるごと、「firebase.initializeApp()」の丸括弧の中に入れちゃってください。
以上にて、FireBaseとReact Nativeを接続させる処理は終了です。
React Native内でログインフォームを作る
FireBaseの認証機能を使う準備が出来たので、いよいよReactNativeにログインフォームを作っていきましょう。
ログインフォーム用のファイル(LoginForm.js)をsrcディレクトリに作成します。すると、
1 2 3 4 |
src ├── App.js ├── Header.js └── LoginForm.js |
こういった形のファイル構成になるはずです。(Header.jsはヘッダーを表示するだけのComponent)
それでは、LoginForm.jsを記述していきます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 |
import React, { Component } from 'react'; import { View, TouchableOpacity, Text, TextInput, ActivityIndicator } from 'react-native'; import firebase from 'firebase'; class LoginForm extends Component { state = { email: '', password: '', error: '', loading: false}; onButtonPress() { const { email, password } = this.state; this.setState({error: '', loading: true}); firebase.auth().signInWithEmailAndPassword(email, password) .then((this.onLoginSuccess.bind(this))) .catch(() => { firebase.auth().createUserWithEmailAndPassword(email, password) .then((this.onLoginSuccess.bind(this))) .catch((this.onLoginFail.bind(this))); }); } onLoginSuccess() { this.setState({ email: '', password: '', loading: false, error: '' }); } onLoginFail() { this.setState({ loading: false, error: 'Authentication Failed' }); } loadSpinner() { if (this.state.loading) { return <ActivityIndicator size="small" /> } return ( <TouchableOpacity onPress={this.onButtonPress.bind(this)} style={styles.buttonStyle}> <Text style={styles.textStyle}> ログイン </Text> </TouchableOpacity> ) } render() { return ( <View> <View style={styles.wrap}> <TextInput placeholder="user@gmail.com" autoCorrect={false} value={this.state.email} onChangeText={email => this.setState({ email })} style={styles.inputStyle} /> </View> <View style={styles.wrap}> <TextInput secureTextEntry placeholder="password" autoCorrect={false} value={this.state.password} onChangeText={password => this.setState({ password })} style={styles.inputStyle} /> </View> <View style={styles.wrap}> {this.loadSpinner()} </View> </View> ) } } const styles = { wrap: { padding: 10 }, textStyle: { alignSelf: 'center', color: '#007aff', fontSize: 16, fontWeight: '600', paddingBottom: 10, paddingTop: 10 }, buttonStyle: { alignSelf: 'stretch', backgroundColor: '#fff', borderRadius: 5, borderWidth: 1, borderColor: '#007aff' }, inputStyle: { color: '#000', paddingRight: 5, paddingLeft: 5, fontSize: 18, lineHeight: 23, height: 30, borderWidth: 1, borderColor: '#333' } } export default LoginForm; |
一気に長いコードになってしまいましたが、びっくりしないでください笑 1つずつ説明していけばとてもシンプルなソースです。
機能としては、emailとpasswordを入力してログインボタンを押すと、初回だけそのemailとpasswordをもったユーザーが新規作成されます。そして、この操作でemailを登録すると、2回目からはその時に登録したemailとpasswordの組み合わせを入力してログインボタンを押すとログインすることができます。
- 1〜3行目 必要なモジュールをインポート(もうおなじみですね)
- 8〜19行目 onButtonPress()というメソッドで、ログインボタンが押されたときにstateのemailとpasswordをfirebaseの機能で認証しています。
- 21〜35行目 onButtonPress内のfirebase.auth()でユーザー作成やログインに成功した場合はonLoginSuccessを、失敗したときはonLoginFailを呼び出してstate操作をしています。
- 37〜49行目 loadSpinnerメソッドでは、Firebaseと通信している最中はログインボタンをスピナー(ActivityIndicator)に変更する処理を書いています。
- 51〜78行目 最後のrenderでは、「TextInput」タグをもちいて、様々なオプションに必要な情報を入力してフォームの役割を持たせています。
といった流れのソースになっています。
基本的には
- TextInputタグの中身を入力
- 入力内容に合わせて、stateが変わる(onChangeText={email => this.setState({ email })})
- ログインボタンを押す
- はじめてのメールアドレスだったら、新規ユーザー作成
- 既に登録してあるメールアドレスの場合、パスワードが一致すればログイン成功
- 失敗したら、ログイン失敗
という、典型的なログインフォームの簡易版です。
TextInputやTouchableOpacity,ActivityIndicatorなどのReactNative特有のタグが頻出して、少し戸惑う可能性がありますが、データの流れはシンプルです。
以下が、ここまでコーディングした状態の画面です。

ログアウトボタンとログイン状態を確認しよう
最後にログアウトボタンの追加とログイン状態が確認できるようにしましょう。
App.jsにrenderForm()メソッドと、ログアウトボタンを追加します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
import React, { Component } from 'react'; import {View, Text, TouchableOpacity} from 'react-native'; import firebase from 'firebase'; import LoginForm from './LoginForm'; import Header from './Header'; class App extends Component { state = { loggedIn: null }; componentWillMount() { firebase.initializeApp({ apiKey: "dummy-dummy", authDomain: "rara-dummy.firebaseapp.com", databaseURL: "https://dummy-dummy.dummy.com", projectId: "dummy-dummy", storageBucket: "dummy-dummy.dummy.com", messagingSenderId: "dummy" }); firebase.auth().onAuthStateChanged((user) => { if (user) { this.setState({ loggedIn: true }); } else { this.setState({ loggedIn: false }); } }) } renderForm() { if (this.state.loggedIn) { return( <View style={styles.wrap}> <TouchableOpacity onPress={() => firebase.auth().signOut()} style={styles.buttonStyle}> <Text style={styles.textStyle}>ログアウト</Text> </TouchableOpacity> </View> ) } else { return(<LoginForm />) } } render() { return ( <View> <Header showText="ログイン" /> {this.renderForm()} <View> <Text>{this.state.loggedIn ? "ログイン中だよ!" : "ログインしてないよ!"}</Text> </View> </View> ) } } const styles = { wrap: { padding: 10 }, textStyle: { alignSelf: 'center', color: '#007aff', fontSize: 16, fontWeight: '600', paddingBottom: 10, paddingTop: 10 }, buttonStyle: { alignSelf: 'stretch', backgroundColor: '#fff', borderRadius: 5, borderWidth: 1, borderColor: '#007aff' } } export default App; |
あ追加した後のソースは以上のような形で、
- 20行目のfirebase.auth().onAuthStateChanged()でユーザーのログイン状態の変化を感知して、その状態をstateにもたせる
- 29行目〜41行目 renderForm()にて、ログイン中はログアウトボタンを、ログアウト中はログインフォームを表示する
- わかりやすいように、49行目でログイン中かどうかを文字で表示(笑)
となっています。
ここまで説明してきたソースで、react nativeを動作させれば
ログアウト中(初回アクセス時)

ログイン中

このような表示になります。
まとめ
Firebaseを使って、ログインフォームをReact Nativeに組み込むということで、かなりの長文になってしまいました。
しかし、この動作さえ覚えておけば、ログインが必要なアプリを作れるようになります。
是非、頑張って、ログインフローをマスターしてください!
サンプルとして、完成版のファイル一式を以下のgitにアップしておきます。参考にしてください
https://github.com/rara-tan/react-native-auth-login-form