CrossBridge Lab

技術ネタ、デバイスネタを...

Firebase を使って30分でiOSのチャットアプリを作ってみる(新SDK対応版)

はじめに

本記事は以下の記事の新SDK対応版です

crossbridge-lab.hatenablog.com


BaaS の1つである Firebase の勉強がてらサンプル的なiOSのチャットアプリを作ったメモです。Firebaseの使い方はとても簡単でした。

f:id:crossbridge-lab:20160601084524p:plain

Firebaseとは

Firebase とはチャットアプリのようなリアルタイムにデータを同期する必要があるサービスに適しているバックエンドサービスです。データはSQLではなくJSONのオブジェクトとして保存されます。Parse を使おうとした矢先に終了のお知らせが出てしまったので、何か他のサービスを使ってみようと Firebase を選んでみました。 ※使う理由としてはチャットアプリではないのですがまずは勉強に簡単なチャットアプリをということです。

REST APIの他、以下のSDKが用意されています。

アカウント登録

https://www.firebase.com からGoogleアカウントで SIGN UP すれば完了です。速い。

f:id:crossbridge-lab:20160601084537p:plain

管理画面で新規プロジェクトを作成

ログインすると Console (管理画面)が表示されます。

f:id:crossbridge-lab:20160601084552p:plain

この画面で新規プロジェクトを作成をクリックします。そしてプロジェクト名と国を選択してプロジェクト作成をクリックします。

f:id:crossbridge-lab:20160601084600p:plain

SDKを導入

プロジェクトを作成したらアプリの管理画面に進むのでiOSアプリにFirebaseを追加をクリックします。もし管理画面を閉じていた場合はConsoleから作成したアプリを選択するとアプリの管理画面に進みます。

f:id:crossbridge-lab:20160601085943p:plain

iOSアプリにFirebaseを追加をクリックすると作成するアプリのバンドルIDとApp StoreIDの入力を求められます。とりあえずバンドルIDだけ入力してアプリを追加をクリックして進みます。

f:id:crossbridge-lab:20160601085949p:plain

アプリを追加をクリックするとGoogleServie-info.plistというファイルがダウンロードされるので画面の説明の通りプロジェクトに追加し、続行をクリックします。

f:id:crossbridge-lab:20160601085955p:plain

次の画面の説明の通りCocoaPodsでSDKをさくっと入れます。Firebaseには様々な機能があり、それぞれライブラリを入れることになりますが今回はデータベースを使うのでpod 'Firebase/Database'の1行も追加します。

pod 'Firebase'
pod 'Firebase/Database'

そしてAppDelegateクラスで以下のようにFirebaseのimportと初期化コードを入れればこれでFirebaseを使う準備が完了です。

import UIKit
import Firebase

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?

    func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
        FIRApp.configure() // 初期化
        return true
    }
    
    // 以下省略

ルールを設定

デフォルトではデータベースへのアクセスには認証が必要となっています。今回はとりえあえずチャットアプリを作るということが目的なので、誰でもアクセスできるようにします。 ※本来はアクセス制限をすべきです。

アプリの管理画面の左側からDatabeseを選択します。そしてルールタブをクリックして以下のように修正します。そして公開ボタンをクリックして反映させます。公開ボタンをクリックしないと反映しないので注意しましょう。

{
  "rules": {
    ".read": true,
    ".write": true
  }
}

f:id:crossbridge-lab:20160602085445p:plain

UIを適当に作る

UITextView と UITextField x 2 の極めてダサいシンプルなUIにします。

f:id:crossbridge-lab:20160225075126p:plain

Outletも忘れずに。

@IBOutlet weak var textView: UITextView!
@IBOutlet weak var nameTextField: UITextField!
@IBOutlet weak var messageTextField: UITextField!

初期設定

    var databaseRef:FIRDatabaseReference!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        
        databaseRef = FIRDatabase.database().reference()

データベースにはFIRDatabaseReferenceクラスを通じてアクセスします。FIRDatabase.database().reference()インスタンスを取得します。

データの読み込み

observeEventTypeメソッドが名前の通りイベントを監視するメソッドです。ここでは.ChildAddedを指定して子要素が追加されたときにwithBlockで与えた処理が実行されるようにしています。データに追加があると自動で呼ばれるので、更新ボタンやPull to refreshを実装する必要はありません。

snapshotというのが追加されたデータで、そこからnameとmessageの値を取り出してTextViewに追記していきます。

databaseRef.observeEventType(.ChildAdded, withBlock: { snapshot in
    if let name = snapshot.value!.objectForKey("name") as? String,
        message = snapshot.value!.objectForKey("message") as? String {
            self.textView.text = "\(self.textView.text)\n\(name) : \(message)"
    }
})

データの書き込み

送信ボタンを作るのも面倒なのでReturn入力時に送信するようにしています。childByAutoIdメソッドがランダムな名前の子要素を作るメソッドで、setValueメソッドでデータを書き込みます。Dictionaryを作って与えています。

func textFieldShouldReturn(textField: UITextField) -> Bool{
    
    let messageData = ["name": nameTextField.text!, "message": messageTextField.text!]
    databaseRef.childByAutoId().setValue(messageData)
    
    textField.resignFirstResponder()
    messageTextField.text = ""
    
    return true
}

実際には以下のようにデータが保存されます。

f:id:crossbridge-lab:20160225075137p:plain

完成

以上で完成です。多分、30分もかかっていないですね。ViewControllerのソースはキーボードを開いた時にTextFieldを上に持ち上げる処理などを除けば以下のように。

@IBOutlet weak var textView: UITextView!
@IBOutlet weak var nameTextField: UITextField!
@IBOutlet weak var messageTextField: UITextField!
    
var databaseRef:FIRDatabaseReference!
    
override func viewDidLoad() {
    super.viewDidLoad()
    
    databaseRef = FIRDatabase.database().reference()
    
    databaseRef.observeEventType(.ChildAdded, withBlock: { snapshot in
        if let name = snapshot.value!.objectForKey("name") as? String,
            message = snapshot.value!.objectForKey("message") as? String {
                self.textView.text = "\(self.textView.text)\n\(name) : \(message)"
        }
    })
}

func textFieldShouldReturn(textField: UITextField) -> Bool{
    
    let messageData = ["name": nameTextField.text!, "message": messageTextField.text!]
    databaseRef.childByAutoId().setValue(messageData)
    
    textField.resignFirstResponder()
    messageTextField.text = ""
    
    return true
}

最後に

でもお高いんでしょ?https://firebase.google.com/pricing/ が料金プランのページです。コネクション数、ストレージの容量、転送量などで分かれています。小さなアプリ(サービス)なら無料でもいけるのでは?といった感じです。

f:id:crossbridge-lab:20160602085639p:plain