AndroidのFCMセットアップメモ

AndroidのPush通知実装はよく変わるので自分用に簡潔なメモ。

# 事前準備

Android Studioでプロジェクト作成
Firebase Consoleでプロジェクト作成

# google-services.jsonの生成
Firebase Consoleで以下の作業を行う。

- Overviewにある「AndroidアプリにFirebaseを追加」をクリック
- Android Studioで作成したアプリのパッケージ名を入力
- 「アプリを追加」をクリック
- `google-services.json`がダウンロードされる

# Firebaseのセットアップ
Android Studioで以下の作業を行う。

### `google-services.json`をモジュール直下に配置

デフォルトなら

```
<PROJECT_ROOT>/app/google-services.json
```

### プロジェクトルートのbuild.gradleを編集

```&lt;PROJECT_ROOT&gt;/build.gradle
buildscript {
  dependencies {
    // 追加
    classpath 'com.google.gms:google-services:3.0.0'
  }
}
```

### モジュールのbuild.gradleを編集

```&lt;PROJECT_ROOT&gt;/&lt;APP_MODULE&gt;/build.gradle
dependencies {
  compile fileTree(dir: 'libs', include: ['*.jar'])
  testCompile 'junit:junit:4.12'
  compile 'com.android.support:appcompat-v7:24.1.1'

  // 以下を追加
  compile 'com.google.firebase:firebase-core:9.2.1'
  compile 'com.google.firebase:firebase-messaging:9.2.1'
}

// 追加
apply plugin: 'com.google.gms.google-services'
```

ここまでで、Firebase ConsoleのNotificationから送信したPush通知を受け取れる

# 独自サーバにtokenを送信する

Firebase Notificationを使わない場合はFCMのTokenを独自サーバに送る必要がある。

DocumentはInstanceIdとかregistration_tokensとか書いてあるけど、
GCMはregistration_idだった、名前変わったのかな...


### Serviceを作成

registration_tokenの生成や更新を受け取るために、
FirebaseInstanceIdServiceを継承したServiceを生成する必要がある。

```MyFirebaseInstanceIdService.java
public class MyFirebaseInstanceIdService extends FirebaseInstanceIdService {
    @Override
    public void onTokenRefresh() {
        String refreshedToken = FirebaseInstanceId.getInstance().getToken();

        // サーバにtokenを送信する処理を書く
    }
}
```

### ManifestへServiceを登録

```AndroidManifest.xml
...
    <service
      android:name=".MyFirebaseInstanceIdService">
      <intent-filter>
        <action android:name="com.google.firebase.INSTANCE_ID_EVENT"/>
      </intent-filter>
    </service>
  </application>
</manifest>
```

# アプリ起動中にPush通知を受け取る

上記までだと、アプリを起動している最中に受け取ったPush通知が表示されない。

### Serviceを作成

FirebaseMessagingServiceを継承したServiceを作成することで対応。

```MyFirebaseMessagingService.java
public class MyFirebaseMessagingService extends FirebaseMessagingService {
  private static final int NOTIFICATION_ID = 0;

  @Override
  public void onMessageReceived(RemoteMessage remoteMessage) {
    String title = remoteMessage.getNotification().getTitle();
    String body = remoteMessage.getNotification().getBody();

    NotificationCompat.Builder builder =
        (NotificationCompat.Builder) new NotificationCompat.Builder(this)
            .setSmallIcon(R.mipmap.ic_launcher)
            .setContentTitle(title)
            .setContentText(body);

    NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
    manager.notify(NOTIFICATION_ID, builder.build());
  }
}
```

### ManifestへServiceを登録

```AndroidManifest.xml
...
    <service
      android:name=".MyFirebaseMessagingService">
      <intent-filter>
        <action android:name="com.google.firebase.MESSAGING_EVENT"/>
      </intent-filter>
    </service>
  </application>
</manifest>
```

# Firebase Cloud MessagingのAPIを叩いて確認

Firebase Console -> プロジェクトの設定 -> クラウドメッセージング
とクリックしてサーバーキーを確認する。(以下&lt;SERVER_KEY&gt;)
registration_tokenはLogcatなどに出力して確認する。(以下&lt;TARGET_DEVICE_TOKEN&gt;)

##### API

`POST: https://fcm.googleapis.com/fcm/send`

##### Header

```
Content-Type: application/json
Authorization: key=<SERVER_KEY>
```

##### Body

```
{
    "to" : "<TARGET_DEVICE_TOKEN>",
    "notification" : {
      "body" : "test body",
      "title" : "test title"
    }
}
```

端末にPush通知が届いたらOK

## 追記

APIを叩いたときのレスポンス

正しくPush通知が行われた場合

```
{
  "multicast_id": 8684687898872501766,
  "success": 1,
  "failure": 0,
  "canonical_ids": 0,
  "results": [
    {
      "message_id": "0:1469764622452795%a55a89aea55a89ae"
    }
  ]
}
```

tokenを間違えるなど、Push通知が正しく送信出来なかった場合

```
{
  "multicast_id": 7013707986156482002,
  "success": 0,
  "failure": 1,
  "canonical_ids": 0,
  "results": [
    {
      "error": "InvalidRegistration"
    }
  ]
}
```