LoginSignup
23
9

More than 5 years have passed since last update.

Poiboyで使用しているFirebaseの機能紹介と事例ついでにおまけ

Last updated at Posted at 2018-12-20

はじめに

はい!こんにちは〜!
株式会社Diverseで今年からPoiboyのiOSエンジニアとして働かせてもらっているgiiiitaです!
アーキテクチャ(PoiboyはMVP,興味本位でMVVM)であったりAutoLayoutあったり覚えることがてんこ盛りですが、日々の新しいインプットが新鮮でエンジョイしてます!

昨日は、@yuki-oさんFlareをFlutterだけじゃなくてJSでもFlareった話でした。
試行錯誤した結果本家にprを出す行動・・・かっこいいなぁと!
Flutterを採用した大規模なプロダクトを開発されているチームの方なので、このプロダクトがリリースされた際にはぜひFlutterノウハウお聞きしたいですね!

本日は、
Diverse Advent Calendar 2018 20日目の記事として
Poiboyチームが今年から導入した技術の一つFirebaseについて記事にしたいと思います!
※この記事では触れてない使い方もあります

Firebaseとは

ダウンロード.png

一言で言うとGoogleが提供しているmBaaS(mobile Backend as a Service)です。

サービス開発で頻繁に使われる認証とかPush通知等汎用的な機能を比較的簡単に実装が行えたりりFireStoreといったフルマネージドなDBがあるおかげでインフラ構築、サーバーの管理、スケールを行う必要もなく開発側はアプリケーション開発に集中することができ結果リリースまでの時間を短縮させてくれるサービスだと考えています。

また、
認証機能など開発中の助けとなる機能だけではなくログ収集、収益化、A/BTestなど運用フェーズの助けとなる機能も豊富なところも注目の一つかと思っております。

ある程度の制限はございますが、無料枠でFirebaseの機能を試すことができますので興味がある方はぜひTRYしてみてください!

詳しくは、
Firebase公式ドキュメント
Firebaseのgithub
上二つのリンクを見てみると良さそうです。

Poiboyで使用している機能

Poiboyチームでは今年よりFirebaseが提供するいくつかの機能を実際のプロダクトで使用しているのでその例を紹介します!

Authentication

1_zTdZMxbTkVdXCOoZlXLnsg.png

主にFacebook,Twitter,SMSの3つのログイン経路を作成するために使用しております。

Poiboyチームで行ってる設定例
スクリーンショット 2018-12-19 16.09.33(2).png

Poiboyのログイン画面↓↓↓
スクリーンショット 2018-12-19 16.35.01.png

LINEログインなどはAuthenticationがカバーするログイン方法として提供されてはいないですがカスタム認証トークンを用いてLINEでログインが実現できるようです。

Authenticationを使用してTwitterログインを行う方法についてはこちら
Authenticationのガイドはこちら

Cloud Functions

1_xRxNEQkLv2g-2SLZlmr8dg.png

エラー検知の仕組みとして使用しております。

Cloud FunctionではHTTPであったりDBにデータが入った時などいくつかのイベントをトリガーに設定し行いたい処理を書くことができます。
Poiチームでは、Analyticsのイベントをコードに仕込みそのイベントがAnalytics/Eventsに通知された際にSlackへ通知を飛ばす仕組みをとっています。

Analytics/Eventをトリガーとするfunctionを用意

sample.ts
export const faceBookLoginFailedNotificationToSlack = functions.analytics.event('FaceBookLoginFailed').onLog(async (event) => {
    //analyticsEventに"FaceBookLoginFailed"が通知された時に実行したい処理内容を書く
});

Analytics/Eventを通知させたい箇所に以下コードを仕込む

sample.swift
Analytics.logEvent("FacebookLoginFailed", parameters: nil)

こんな具合でslackに通知が届く
スクリーンショット 2018-12-19 16.14.59.png

今回は通知のためにCloud Functionsを使用しましたが、
他にもFireStoreでは出来ないこと(ドキュメントに含まれる2つのフィールドに対して囲検索が出来ない等)をCloud FunctionsとAlgoliaを使用して出来ないことをカバーする方法があります。
ドキュメントが追加(onCreate),更新(onUpdate)されることをトリガーにFireStoreのデータをAlgoliaに送りアプリから検索を行いたい際にはAlogilaからデータを引くイメージです。
公式でも紹介されているので気になった方はこちら

functionsをDeployするときのコマンド集はこちら
Cloud Functionsのガイドはこちら
functions-sample

RemoteConfig

images.png

ABTest,特定の値を即時切り替えたい箇所で使用しております。

Poiboyチームで行ってる設定例
スクリーンショット 2018-12-19 16.07.55(2).png

具体的に、
・ABTestでは、ABそれぞれ異なるパターンのユーザ体験を用意し数パーセントのユーザにBパターンを反映されるように仕組みます。
その結果、意図した結果であれば徐々にBパターンが反映されるユーザの範囲を広げたりしております。

特定の値をすぐに切り替えたい箇所では、
とある画面の更新が終わるまでに30秒間隔を開けたい際にこの30をRemoteConfigで設定します。
設定例では30と設定されていますが、30ではなく20にしようとなった時もアプリの更新を行う必要がなく設定画面でパラメータを20にしてあげれば即時反映されます。

RemoteConfigの良さとしてリアルタイム性がありもし仮に不具合、不都合があった場合には管理画面で値を切り替えてしまえば良いのでリスク回避も柔軟に行えます。
既存コンテンツであれば、RemoteConfigの導入箇所は考えればいくつかあるかなと思っておりまして例えば、以下のような感じです。

・緊急メンテを行いたい場合管理画面で値を切り替え即時メンテ用の画面に切り替える
・ソシャゲのイベントでイベント完走率が見込んだ数字より低ければ難易度を下げる
etc...(考えればチームにフィットした使い方があるはず!!!)

アプリの更新をせずに専用のコードさえ仕込んでおけば管理画面からポチッと切り替えられるのは強い!!!

FirebaseでABTestを行う方法についてはこちら
RemoteConfigのガイドはこちら

Firebaseの機能を導入してみて

チームで決めた施策やテストを行う際にそれが反映、実現されるまでのスピード感があるなと感じてます。
ABTestを行うにしろ基盤作成から工数を見積もるといつテストが始まるのだろう?となりがちなところをFirebaseの機能にのっかってしまえば後はテストしたい箇所に数行コードを書くだけでテストが行えたりするので便利だと感じております。

認証とかはアプリではほぼ必須な機能ですが、Authenticationを使用することで少ない工数で実装が可能なのでアプリケーション開発に時間を回せるのもエンジニア的には嬉しいのではないでしょうか?

おまけ

ユーザ登録からユーザ画面までを実装してみる

リポジトリ用意しました

サンプルリポジトリ
だいたい1時間もかからないくらいでこの実装が行えたのでかなりコスパ良いかなと思ってます!

イメージ

Login画面に表示されているボタンをタップすることでLogin処理を行います。
Login処理が完了後にプロフィール用の画像、名前を入力してDBに保存します。
プロフィール用の画像、名前が無事DBに保存されればユーザ画面を表示します。
スクリーンショット 2018-12-18 17.38.43.png

使用するFirebaseのサービス

Authentication <- 認証に匿名ログインを使用
FireStore <- UserDataのread/write
CloudStorage <- Userのプロフィール画像の置き場所

実装箇所でポイントだと思う箇所をピックアップ

サンプルリポジトリに含まれるコードでFirebaseを使って機能実装している箇所でポイントとなる箇所のみ抽出してみました!

ログイン済みかどうかで最初に表示するViewControllerを選択

AppDelegate.swift
if let userId: String = Auth.auth().currentUser?.uid {
    Firebase.User.get(userId) { (user, error) in
        if let error = error { return }
        guard let user = user else { return }
        let vc: UserViewController = UserViewController.instantiate(with: .init(user: user))
        self.window?.rootViewController = vc
        self.window?.makeKeyAndVisible()

    }
} else {
    let vc: LoginViewController = LoginViewController.instantiate()
    self.window?.rootViewController = vc
    self.window?.makeKeyAndVisible()
}

UserModelの定義

Pringを使用することで、FireStoreのDocumentをオブジェクトのように扱うことが可能です。
ここでは、ユーザ登録情報として必須のname,thumbnail,必須項目が登録済みであるかのisActivatedを含むオブジェクトを作成しています。

Firebase+User.swift
import Foundation
import Firebase
import FirebaseFirestore
import Pring

extension Firebase {
    @objcMembers
    class User: Object {

        dynamic var name: String?
        dynamic var thumbnail: File?

        // nameとthumbnailが登録されていれば利用可能
        dynamic var isActivated: Bool = false

    }
}

匿名ログイン

LoginViewController.swift
    private func registrationAnonymus() {
        Auth.auth().signInAnonymously(completion: { (authDataResult, error) in
            if let error = error { return }
            guard let authDataResult = authDataResult else { return }
            let id: String = authDataResult.user.uid
            let user: Firebase.User = Firebase.User(id: id)
            user.save { (ref, error) in
                if let error = error { return }
                print("Registration Success")
                let vc: UserRegistrationViewController = UserRegistrationViewController.instantiate(with: .init(user: user))

                let nvc: UINavigationController = UINavigationController(rootViewController: vc)

                self.present(nvc, animated: true)

            }
        })
    }

signInAnonymouslyWithCompletion: メソッドがエラーの場合は早期return,エラーがない場合は匿名ユーザーのアカウントデータをFIRAuthDataResultオブジェクトから取得しています。
user.save { (ref, error) in }でエラーがなければ新しくUserコレクション内に新規のドキュメントが生成されます。

Auth.auth().signInAnonymously(completion: { (authDataResult, error) in
    if let error = error { return }
    guard let authDataResult = authDataResult else { return }
    let id: String = authDataResult.user.uid
    let user: Firebase.User = Firebase.User(id: id)
    user.save { (ref, error) in
        if let error = error { return }
    }
})

UserDocumentの更新

Userオブジェクトのnameに値を入れて
self.user.updateを行うとFireStoreのUserDocumentのFieldが更新されます。

UserRegistrationViewController.swift
        self.user.name = name
        self.user.update { [weak self] (error) in
            if let error = error { return }
        }

Firebase管理画面のスクショ

Autentication周り

匿名ログインを有効にして、ユーザ作成が行われるとこのように表示されます。
auth1.png
auth2.png

Firestore
Firestore内のデータは以下スクショのように確認出来ます。
UserCollectionの中にそれぞれのUserDocumentが作成されています。
管理画面上で検索も可能です。
cloudFireStore.png

スクリーンショット 2018-12-20 14.42.27.png

Cloud Storage

ユーザのthumbnailがCloud Storageに保存されております。
FirestoreのUserDocumentにはCloudStorageに保存されているthumbnailのDownLoadURLが格納されています。
storage.png

明日のアドカレ内容について

Diverse Advent Calendar 2018 21日目は@mina_mさんデザイナーが考える!心理学を取り入れて少しでもマッチングの確率を上げる方法についてです!

マッチングの確率を上げる方法として心理な観点からどのようなアプローチがあるのか楽しみですね!

23
9
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
23
9