【Android】 Google クラウド メッセージング（GCM）の新バージョン、Firebase Cloud Messaging（FCM）


>
**Google クラウド メッセージング（GCM）の新バージョン、Firebase Cloud Messaging（FCM）**
>Developer Console の GCM 統計情報と GCM 診断が FCM 統計情報と FCM 診断に変わります。
Firebase Cloud Messaging の利用にあたり設定などの変更は不要ですが、アップグレードするとさまざまな新機能を使用できます。


Google Play Developer Consoleでこんなこと言われ続けて、気になっちゃってしょうがない＞＜
ということで、基本的にGCMと変わらないのでさくさくっと、GCMをFCMに置き換えです
本家のドキュメントはこちら
https://firebase.google.com/docs/android/setup

# Firebase コンソールでの設定
## 1. Firebase Consoleへ
https://firebase.google.com/console/https://firebase.google.com/console/

## 2. プロジェクトを作成
　既にある場合はそれを利用

## 3. "Android アプリに Firebase を追加"クリック
　iosの方はiosもあります

## 4. アプリのパッケージ名入力
　Playで公開してるパッケージ名。適当にテスト用のアプリのパッケージ名でもおｋ。

## 5. デバッグ用の署名証明書のハッシュキー
https://developers.google.com/android/guides/client-auth
ちなみに、既にGCM実装済みの場合は、https://console.developers.google.com/ でハッシュキーを入れているはずなので、それをコピーして貼り付けでOK
完了するとgoogle-service.jsonとやらがもらえます。

# Gradle の編集

## 1. google-service.jsonとやらがもらえるのでappモジュールの中の階層に配置

優しきことに説明がでてきてたと思うのでそのとおりに。

google-service.jsonには作ったプロジェクトの情報が書き込まれたあなただけのファイルです。そのアプリ専用のファイルです。

プロジェクトの中のメインのモジュールの階層の中に配置。

![スクリーンショット 2016-07-05 00.21.15.png](https://qiita-image-store.s3.amazonaws.com/0/70150/5aa75287-7824-39ad-fec5-c7225c9d57ae.png)

## 2. プロジェクト（上の階層）のbuild.gradleを編集

classpath 'com.google.gms:google-services:3.0.0'を追加

```groovy
buildscript {
    repositories {
        jcenter()
        mavenCentral()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:2.1.2'
        classpath 'com.android.tools.build:gradle-experimental:0.2.0'

        // これを追加
        classpath 'com.google.gms:google-services:3.0.0'
    }
}
```

## 3. アプリモジュールの方のbuild.gradle編集

下記が要らなくなるので **削除**
com.google.android.gms:play-services-gcm:9.0.2

代わりに下記を **追加**
com.google.firebase:firebase-messaging:9.0.2
com.google.firebase:firebase-messaging:9.0.2

一番下に下記を **追加**
apply plugin: 'com.google.gms.google-services'

```groovy
apply plugin: 'com.android.application'

android {

}

dependencies {
    // これはいらなくなる
    //compile 'com.google.android.gms:play-services-gcm:9.0.2'

    compile 'com.google.firebase:firebase-core:9.0.2'
    compile 'com.google.firebase:firebase-messaging:9.0.2'
    // 今回は関係ないけど、Firebaseアナリティクスも試したい方はこれも入れる
    compile 'com.google.firebase:firebase-analytics:9.0.2'
}

// 一番下に追加
apply plugin: 'com.google.gms.google-services'
```

コンパイルが通らない時は、classpath 'com.google.gms:google-services:3.0.0'を書いてないとか、google-service.jsonを置いてないとかだと思われるでござる



# コードの置き換え

## 1. パーミッションの削除

manifestファイルです。これらはFCMでは必要なくなるので削除


```xml
<!--
<uses-permission android:name="android.permission.WAKE_LOCK" />
<permission android:name="<your-package-name>.permission.C2D_MESSAGE"
            android:protectionLevel="signature" />
<uses-permission android:name="<your-package-name>.permission.C2D_MESSAGE" />
-->
```

## 2. レジーバーの削除

manifestファイルです。レジーバーは宣言がいらなくなります
fcmのsdkが自動でやってくれるようになったようです。便利!

```xml
<!--
<receiver
    android:name="com.google.android.gms.gcm.GcmReceiver"
    android:exported="true"
    android:permission="com.google.android.c2dm.permission.SEND" >
    <intent-filter>
        <action android:name="com.google.android.c2dm.intent.RECEIVE" />
        <category android:name="com.example.gcm" />
    </intent-filter>
</receiver>
-->
```

## 3. InstanceIDListenerServiceを更新

Token更新イベントなどを受信して更新処理をしていたInstanceIDListenerServiceを変更します
manifestファイルの宣言を変更

```xml
<!--
<service
    android:name=".MyInstanceIDListenerService"
    android:exported="false">
    <intent-filter>
        <action android:name="com.google.android.gms.iid.InstanceID" />
    </intent-filter>
</service>
-->

<service
    android:name=".MyInstanceIDListenerService">
    <intent-filter>
        <action android:name="com.google.firebase.INSTANCE_ID_EVENT" />
    </intent-filter>
</service>
```

既存のInstanceIDListenerServiceを消して

```java
/**
public class MyInstanceIDListenerService extends InstanceIDListenerService {

  ...

  @Override
  public void onTokenRefresh() {
      // Fetch updated Instance ID token and notify our app's server of any changes (if applicable).
      Intent intent = new Intent(this, RegistrationIntentService.class);
      startService(intent);
  }
}
**/
```

下記に変更します。

FirebaseInstanceIdServiceを継承し
FirebaseInstanceId.getInstance().getToken();でTokenを発行します。

```java
public class MyInstanceIDListenerService extends FirebaseInstanceIdService {

  ...

  /**
   * Called if InstanceID token is updated. This may occur if the security of
   * the previous token had been compromised. Note that this is also called
   * when the InstanceID token is initially generated, so this is where
   * you retrieve the token.
   */
  // [START refresh_token]
  @Override
  public void onTokenRefresh() {
      // Get updated InstanceID token.
      String refreshedToken = FirebaseInstanceId.getInstance().getToken();
      Log.d(TAG, "Refreshed token: " + refreshedToken);
      // TODO: Implement this method to send any registration to your app's servers.
      sendRegistrationToServer(refreshedToken);
  }

}
```
ちなみに、FirebaseInstanceId.getInstance().getToken();は、uiスレッドで読んでも問題ありませんでした。

アプリが初めて起動した時のApplication#onCreateとかで呼ぶとnullが返る。
そのあと数秒するとonTokenRefreshが呼ばれて、null以外のidが取得できます。

Tokenの発行はライブラリが自動で行い、onTokenRefreshを読んでくれるので、自分でやる必要はない
以前書いていた下記のコードはいらなくなる

```java
 InstanceID instanceID = InstanceID.getInstance(this);
  String token = instanceID.getToken(getString(R.string.gcm_defaultSenderId),
          GoogleCloudMessaging.INSTANCE_ID_SCOPE, null);
  // [END get_token]
  Log.i(TAG, "GCM Registration Token: " + token);
```

## 4. GcmListenerService(GCMの受信などしてた)の置き換え

```xml

<!--
<service
    android:name=".MyGcmListenerService"
    android:exported="false">
    <intent-filter>
        <action android:name="com.google.android.c2dm.intent.RECEIVE" />
    </intent-filter>
</service>
-->

<service
    android:name=".MyFcmListenerService">
    <intent-filter>
        <action android:name="com.google.firebase.MESSAGING_EVENT" />
    </intent-filter>
</service>
```

FirebaseMessagingServiceを継承に変更
データもgetDataでBundleではなく、Mapで取得に変更です

```java
/**
public class MyGcmListenerService extends GcmListenerService {
  @Override
  public void onMessageReceived(String from, Bundle data){
    ...
  }

  ...
}
**/

public class MyFcmListenerService extends FirebaseMessagingService {
  @Override
  public void onMessageReceived(RemoteMessage message){
    String from = message.getFrom();
    Map data = message.getData();
  }
  ...
}
```

onMessageReceivedでいつものように、通知表示処理を行えばおｋ

ただし、アプリがbackgroundだったり、foregroundだったりで挙動が違ったり、ちょっとつまづく仕様があるので、くわしくはまた次以降で!


いろいろ自動化されて、いろいろ消したなー :D


公式ドキュメント
https://developers.google.com/cloud-messaging/android/android-migrate-fcm