Railsのコードを書けないAndroidアプリ開発者がFirebaseを使ってチャットアプリを作る

昨晩のGoogle IO 2016で、Firebaseの大幅機能拡充が発表されました。

[Railsのコードを書けないAndroidアプリ開発者がnifty cloud mobile backendを使ってチャットアプリを作る](http://qiita.com/YusukeIwaki/items/1c2d81755e6e2691e7ac) っていうのをやったときに、ニフティクラウド モバイルバックエンド最大の欠点であった、「リアルタイムDBが使えない！」っていうのがFirebaseではいけてるように見えたので、実際にどうなのかさわってみることにしました。

## アプリケーションの作成

![image](https://qiita-image-store.s3.amazonaws.com/0/74571/c7c95f06-0ddd-5b8d-9f5f-84cb4947e5da.png)

なんか[イイ感じのページ](https://firebase.google.com)から「GET STARTED FOR FREE」で

![image](https://qiita-image-store.s3.amazonaws.com/0/74571/6b845e17-e6fa-ff2d-1adb-94a48a1fbd5f.png)

アプリケーションを新規作成。


## アプリとFirebaseのひも付け

![image](https://qiita-image-store.s3.amazonaws.com/0/74571/1e9f83a6-cc3e-7160-8776-33b10f13304e.png)

Googleログインを利用してラクしたいので、SHA-1ハッシュを登録します。

まずは、Android StudioでKeyStoreをつくります。

![image](https://qiita-image-store.s3.amazonaws.com/0/74571/f7a7407c-4028-9d09-10cf-da895a5d000b.png)

![image](https://qiita-image-store.s3.amazonaws.com/0/74571/31cd7546-4c80-8d69-c502-dde13d7991fe.png)

```bash:SHA-1
$ keytool -exportcert -list -v -alias fuga -keystore fugafuga.jks 
キーストアのパスワードを入力してください:  
別名: fuga
作成日: 2016/05/19
エントリ・タイプ: PrivateKeyEntry
証明書チェーンの長さ: 1
証明書[1]:
所有者: CN=Yusuke Iwaki, OU=Development, O=CrowdWorks, L=Shibuya, ST=Tokyo, C=JP
発行者: CN=Yusuke Iwaki, OU=Development, O=CrowdWorks, L=Shibuya, ST=Tokyo, C=JP
シリアル番号: 12df6f13
有効期間の開始日: Thu May 19 12:25:23 JST 2016終了日: Mon May 13 12:25:23 JST 2041
証明書のフィンガプリント:
	 MD5:  C3:BC:08:68:E1******ひみつ******:0F:00:7B
	 SHA1: 4B:15:15:A8:F3******ひみつ******:0B:6C:84:A7
	 SHA256: 8C:36:D2:C1:35******ひみつ******:9F:86:80
	 署名アルゴリズム名: SHA256withRSA
	 バージョン: 3

拡張: 

#1: ObjectId: 2.5.29.14 Criticality=false
SubjectKeyIdentifier [
KeyIdentifier [
0000: 01 DE E2******ひみつ******8.=z .P.>
0010: DF 62******ひみつ******
]
]

```

SHA1のところをFirebaseにいれます。


![image](https://qiita-image-store.s3.amazonaws.com/0/74571/e0999448-9af2-47f9-806b-28c467b4ef95.png)

びっくりするくらい丁寧な説明がでますｗ


## アプリにFirebaseを組み込む


https://firebase.google.com/docs/android/setup#add_the_sdk にあるとおりですが、今回は

* firebase-core
* firebase-database
* firebase-auth

の３つを組み込みます。

```diff:組み込み
diff --git a/app/build.gradle b/app/build.gradle
index 1e130c6..097e3b1 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -23,4 +23,10 @@ dependencies {
     compile fileTree(dir: 'libs', include: ['*.jar'])
     testCompile 'junit:junit:4.12'
     compile 'com.android.support:appcompat-v7:23.4.0'
-}
\ No newline at end of file
+
+    compile 'com.google.firebase:firebase-core:9.0.0'
+    compile 'com.google.firebase:firebase-database:9.0.0'
+    compile 'com.google.firebase:firebase-auth:9.0.0'
+    compile 'com.google.android.gms:play-services-auth:9.0.0'
+}
+apply plugin: 'com.google.gms.google-services'
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
index 58f1f1b..fa5c600 100644
--- a/build.gradle
+++ b/build.gradle
@@ -9,6 +9,7 @@ buildscript {
 
         // NOTE: Do not place your application dependencies here; they belong
         // in the individual module build.gradle files
+        classpath 'com.google.gms:google-services:3.0.0'
     }
 }
 

```

## ログイン周りをつくる

以前に、[ニフティクラウドのモバイルバックエンドのテストアプリ作った時のやつ](http://qiita.com/YusukeIwaki/items/1c2d81755e6e2691e7ac#%E4%BC%9A%E5%93%A1%E7%99%BB%E9%8C%B2%E3%83%AD%E3%82%B0%E3%82%A4%E3%83%B3%E3%83%AD%E3%82%B0%E3%82%A2%E3%82%A6%E3%83%88%E3%81%AA%E3%81%A9) を流用します。

Google OAuthやるのがやっぱり面倒になってきたので（え？ｗ）、ID/passで新規会員登録・ログインを実装します。

![image](https://qiita-image-store.s3.amazonaws.com/0/74571/19d83e6e-9974-a4bd-f5d8-de1b0a211c06.png)

とりあえずFirebaseがわでEmail認証をONにします。

前回つくったやつを流用して、[会員登録/ログイン/ログアウトをすごく雑に](https://github.com/YusukeIwaki/FugaFugaWorks/commit/0cb8ea9e513e4430fa4f2928bf1179367941c0f5)つくると・・・

![image](https://qiita-image-store.s3.amazonaws.com/0/74571/c684491e-98fc-1b1d-f3d6-e11b6c96471b.png)

で登録すると、次の瞬間に、Firebaseのコンソールにユーザが現れました！

![Bitmap.png](https://qiita-image-store.s3.amazonaws.com/0/74571/7a948b65-2356-8525-a5d1-4f1779669082.png)

このあたりはニフティクラウドとほぼ同等の使用感。

ただ、細かいことを言うと、会員登録のコールバックをPromise文法で書けるあたりはさすが。ニフティクラウドよりもイケてる。

```java:ログインのコード例
FirebaseAuth.getInstance().signInWithEmailAndPassword(email, password).continueWith(new Continuation<AuthResult, Object>() {
    @Override
    public Object then(@NonNull Task<AuthResult> task) throws Exception {
        if (!task.isSuccessful()) {
            Log.e("FugaFugaWorks", "error", task.getException());
        }
        return null;
    }
});
```

## メッセージの送受信を作る

いよいよお楽しみのRealtime DBですね。
Meteor使いもびっくりの、オブジェクトDB。詳細は[このへんの記事](https://html5experts.jp/technohippy/18040/)がわかりやすいです。

データベースに突っ込むのも引っ張ってくるのも、結構ゆるい感じです

### モデルを定義

```java:Message
public class Message {
    public String author;
    public String content;

    public Message(String author, String content) {
        this.author = author;
        this.content = content;
    }
}
```

POJOなかんじで。てきとうです。


### メッセージ送信（DBにデータをつっこむ）

```java:DBにつっこむ
    private DatabaseReference getMessageRef() {
        FirebaseDatabase database = FirebaseDatabase.getInstance();
        return database.getReference(MESSAGE_STORE); // MESSAGE_STORE = "message"
    }

    private void sendMessage(String content) {
        FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
        
        getMessageRef().push().setValue(new Message(user.getUid(), content)).continueWith(new Continuation<Void, Object>() {
            @Override
            public Object then(@NonNull Task<Void> task) throws Exception {
                if (!task.isSuccessful()) {
                    Log.e("FugaFugaWorks","error", task.getException());
                    return null;
                }

                ((TextView) findViewById(R.id.txt_content)).setText("");
                return null;
            }
        });
    }
```

ポイントは、書いたあとに特にDBのリロードとかはやっていないということ。なぜなら、リアルタイムDBの恩恵により、DBに突っ込まれた次の瞬間に変更通知が降ってきて、ビューが更新されるから。

### メッセージ表示（DBからロード）

「ロード」と言ってしまうとワンショットで取ってくるイメージが強いですが、Firebaseの考え方としては、おそらく「DBのなかのデータモデルをビューに写像するだけ」というものです。

![firebase.png](https://qiita-image-store.s3.amazonaws.com/0/74571/b82e0a6b-dec5-8ce1-887e-798ccd7bf226.png)

どうやってリスト表示しようかなーめんどくさいなーと悩んでいたところ、[Firebase-uiというサブプロジェクトが、Firebaseをリスト表示してくれるアダプタを提供している](https://github.com/firebase/FirebaseUI-Android/tree/master/database)じゃありませんか！

ありがたく拝借。

```java:ListAdapter
        mAdapter = new FirebaseListAdapter<Message>(this, Message.class, android.R.layout.simple_list_item_1, getMessageRef()) {
            @Override
            protected void populateView(View v, Message model, int position) {
                ((TextView) v).setText(model.author+": "+model.content);
            }
        };
        ListView listview = (ListView) findViewById(R.id.listview);
        listview.setAdapter(mAdapter);
```

CRUDの世話を全くしなくていいのが本当に素晴らしい。


## 実際にメッセージを送ってみる

![Bitmap.png](https://qiita-image-store.s3.amazonaws.com/0/74571/35abd30b-361e-9cc9-ff91-eced29faac6e.png)

すると即座に（しかもリアルタイムに！）FirebaseのWebコンソールに反映されて↓

![image](https://qiita-image-store.s3.amazonaws.com/0/74571/9d7f5ae9-aa8b-3a72-a842-a3fde17e59ff.png)

さらに次の瞬間には・・・

![image](https://qiita-image-store.s3.amazonaws.com/0/74571/85ff4e25-b1c4-7dd0-6c04-c30a23ec6173.png)

画面にも反映される、という。


## まとめ

すっごい簡単にチャットアプリがつくれました。
たぶんGCM（あらためFCM？）とか使うとプッシュ通知も簡単に届くんだと思います。

![test.gif](https://qiita-image-store.s3.amazonaws.com/0/74571/6dee5d98-fe8b-ae04-2eed-3dfd8a768f02.gif)

リアルタイムDBさわってみて、Meteorを初めて見た時のような感動で、結構しびれました。


## (というか・・・

https://github.com/firebase/AndroidChat

サンプルあるやーん！！ｗｗ