FirebaseCloudMessaging を試してみる

2016年5月18日~20日に行われた Google デベロッパー向けカンファレンス Google I&fra…

2016年5月18日~20日に行われた Google デベロッパー向けカンファレンス
Google I⁄O 2016 で Firebase のメジャーアップデートが発表されました。
Firebase とは2011年にアメリカで始まった Mobile Backend as a Service (MBaas) と
呼ばれるクラウドサービスで、 2014年に Google に買収されたことにより知名度が上がりました。
 
今回、この Firebase のサービスの1つである FirebaseCloudMessaging (FCM) を
利用してプッシュ通知をやってみます。
Android でプッシュ通知といえば GoogleCloudMessaging (GCM) だったのですが
これが FCM に変わったという感覚で問題ないかと思います。
 

google-services.json の生成

Firebase にログインし、 google-services.json を生成します。
 
プロジェクト作成
firebase_top
 
プロジェクト名
project
 
Android アプリに Firebase を追加
welcome
 
アプリの詳細を入力
app_detail
デバッグ用の署名証明書 SHA-1 (オプション)は、
Android Studio がインストールされていれば次のコマンドで確認できます。
(パスワードは何も入力せずにEnter)
WINDOWS

keytool -exportcert -list -v -alias androiddebugkey -keystore %USERPROFILE%\.android\debug.keystore

MAC ⁄ LINUX

keytool -exportcert -list -v -alias androiddebugkey -keystore ~/.android/debug.keystore

 
アプリを追加ボタンを押して google-services.json がダウンロードされたら完了です。
 

Android プロジェクトの作成

それでは例に漏れずプロジェクトを作っていきましょう
プロジェクトを作成したら app 配下に先ほどダウンロードした google-services.json を配置しておきます。
そしたら build.gradle から見ていきましょう。
 
プロジェクトレベルの build.gradle

// Top-level build file where you can add configuration options common to all sub-projects/modules.

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:2.1.2'
        classpath 'com.google.gms:google-services:3.0.0'

        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

allprojects {
    repositories {
        jcenter()
    }
}

task clean(type: Delete) {
    delete rootProject.buildDir
}

ここで特筆すべき点は、これですね。

classpath 'com.google.gms:google-services:3.0.0'

FCM とは言ってもやはり Google のサービスを利用しているというのが分かります。
 
アプリレベルの build.gradle

apply plugin: 'com.android.application'
apply plugin: 'com.google.gms.google-services'

android {
    compileSdkVersion 23
    buildToolsVersion "23.0.3"

    defaultConfig {
        applicationId "jp.co.supersoftware.android.fcm.test"
        minSdkVersion 21
        targetSdkVersion 21
        versionCode 1
        versionName "1.0.0"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
    dataBinding {
        enabled = true
    }
}

dependencies {
    compile fileTree(include: ['*.jar'], dir: 'libs')
    testCompile 'junit:junit:4.12'
    compile 'com.android.support:appcompat-v7:23.4.0'
    compile 'com.google.firebase:firebase-core:9.0.0'
    compile 'com.google.firebase:firebase-messaging:9.0.0'
    compile 'com.google.android.gms:play-services:9.0.0'
}

Firebase の機能を利用しますのでそれ関係の依存ライブラリを設定します。
またプッシュ通知は Google Play Services を利用するので play-services も忘れずに入れておきましょう。
 
AndroidManifest.xml

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="jp.co.supersoftware.android.fcm.test">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">

        <uses-permission android:name="android.permission.VIBRATE" />

        <activity
            android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <service android:name=".FcmTestFirebaseInstanceIdService">
            <intent-filter>
                <action android:name="com.google.firebase.INSTANCE_ID_EVENT" />
            </intent-filter>
        </service>
        <service android:name=".FcmTestFirebaseMessagingService">
            <intent-filter>
                <action android:name="com.google.firebase.MESSAGING_EVENT" />
            </intent-filter>
        </service>

    </application>

</manifest>

今回は1つの Activity と2つの Service を作成するのでマニフェストに記載しておきます。
MainActivity はアプリ起動時に表示する画面です。
FcmTestFirebaseInstanceIdService は GCM で言うところの登録 ID を発行してくれるサービスです。
FcmTestFirebaseMessagingService はプッシュ通知を受け取った時に動作するサービスです。
 
1つずつ見ていきましょう。
 
MainActivity.java

package jp.co.supersoftware.android.fcm.test;

import android.app.Dialog;
import android.support.v7.app.AppCompatActivity;
import android.widget.Toast;

import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.ErrorDialogFragment;
import com.google.android.gms.common.GooglePlayServicesUtil;

/**
 * メイン画面です。
 * <p/>
 * Created by Shirai on 2016/08/04.
 */
public class MainActivity extends AppCompatActivity {

    @Override
    protected void onResume() {
        super.onResume();

        // Google Play Servicesのインストールチェック
        // GCMの場合、GoogleApiClientで妥当なチェックできないため非推奨メソッドを利用
        int gpsResult = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);
        if (gpsResult != ConnectionResult.SUCCESS) {
            if (GooglePlayServicesUtil.isUserRecoverableError(gpsResult)) {
                Dialog errorDialog = GooglePlayServicesUtil.getErrorDialog(gpsResult, this, 0);
                if (errorDialog != null) {
                    ErrorDialogFragment errorDialogFragment = ErrorDialogFragment.newInstance(errorDialog);
                    errorDialogFragment.show(getFragmentManager(), "");
                }
            } else {
                Toast.makeText(this, "Google Play Services が利用不可です", Toast.LENGTH_LONG).show();
            }
        }
    }

}

これは何もないただ画面です。
Google Play Services を利用するので端末にインストールされているかチェックをしています。
場合によっては、エラー時はアプリを落としてしまっても良いかもしれません。
 
FcmTestFirebaseInstanceIdService

package jp.co.supersoftware.android.fcm.test;

import android.util.Log;

import com.google.firebase.iid.FirebaseInstanceId;
import com.google.firebase.iid.FirebaseInstanceIdService;

/**
 * プッシュ通知に使用する登録トークンの生成、更新をハンドルするサービスです。
 * <p/>
 * Created by Shirai on 2016/08/05.
 */
public class FcmTestFirebaseInstanceIdService extends FirebaseInstanceIdService {

    /**
     * ログ出力用
     */
    private static final String TAG = "FCM";

    @Override
    public void onTokenRefresh() {
        super.onTokenRefresh();

        // InstanceIDトークンを取得
        String refreshedToken = FirebaseInstanceId.getInstance().getToken();
        Log.i(TAG, "Refreshed token: " + refreshedToken);
    }

}

onTokenRefresh() をオーバーライドしてインスタンス ID トークンを取得します。
これがプッシュ通知を利用する際に使用される ID です。
GCM で言うところの登録 ID です。
 
FcmTestFirebaseMessagingService

package jp.co.supersoftware.android.fcm.test;

import android.app.Notification;
import android.app.PendingIntent;
import android.content.Intent;
import android.support.v4.app.NotificationManagerCompat;
import android.support.v7.app.NotificationCompat;

import com.google.firebase.messaging.FirebaseMessagingService;
import com.google.firebase.messaging.RemoteMessage;

import java.util.Map;

/**
 * プッシュ通知を受け取るサービスです。
 * <p/>
 * Created by Shirai on 2016/08/05.
 */
public class FcmTestFirebaseMessagingService extends FirebaseMessagingService {

    @Override
    public void onMessageReceived(RemoteMessage remoteMessage) {
        super.onMessageReceived(remoteMessage);

        // 通知設定
        Map<String, String> data = remoteMessage.getData();
        String title = data.get("title");
        String body = data.get("body");
        NotificationCompat.Builder notificationCompatBuilder = new NotificationCompat.Builder(this);
        notificationCompatBuilder.setSmallIcon(R.mipmap.ic_launcher);
        notificationCompatBuilder.setContentTitle((title != null) ? title : "");
        notificationCompatBuilder.setContentText((body != null) ? body : "");
        notificationCompatBuilder.setDefaults(Notification.DEFAULT_ALL);
        notificationCompatBuilder.setAutoCancel(true);
        // タップ時の動作設定
        Intent intent = new Intent(this, MainActivity.class);
        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
        notificationCompatBuilder.setContentIntent(pendingIntent);
        notificationCompatBuilder.setFullScreenIntent(pendingIntent, false);
        // 通知表示
        NotificationManagerCompat notificationManagerCompat = NotificationManagerCompat.from(this);
        notificationManagerCompat.notify(346, notificationCompatBuilder.build());
    }

}

受け取ったプッシュ通知を Notification として表示します。
 
これでプッシュ通知を受け取るアプリが完成しました。
 

通知を送ってみる

試しに通知を送ってみましょう。
Firebase のサービスから通知を送信することも可能ですが
アプリがフォアグラウンドかバックグラウンドかで動作が変わってしまうため
今回は curl コマンドを使って通知を送ってみます。

curl --header "Authorization: key=$api_key" \
     --header "Content-Type: application/json; charset=Shift-JIS" \
     https://fcm.googleapis.com/fcm/send \
     -d "{\"to\":\"$instance_id\", \"data\": {\"title\": \"タイトル\", \"body\": \"テスト\"}}" \
     -k

※環境によっては、文字エンコーディングが異なったり、最後の k オプションが不必要かもしれません。
 
$instance_id は初回アプリ実行時にログから取得できます。
以下は開発環境で実行した際に出力されたログです。

08-06 03:29:20.328 9798-10464/jp.co.supersoftware.android.fcm.test I/FCM: Refreshed token: dKAJEEB0aJw:APA91bF2lNL9DEHiwLnNWwfvjYrN7gIR9UBSZ9rLLb_IwD3SDvy3OhZCOz2HBJmahmiMX5kh9VtmdU2dJocznjw9iqfDYLWSNHsNsyWzLu9utMmt_KvyfWY0zBnn0xAMURZkni6fATaM

 
$api_key は Firebase の「プロジェクトの設定→クラウドメッセージング」にあるサーバーキーです。
api_key
 

実行結果

問題なくプッシュ通知が受け取れました。
fcm_ss
 
 
実際、 FCM を使ってみて以前と比べて便利になったと感じました。

  • マニフェストにやたらと使用するパーミッションを書かなくてよくなった
  • 登録 ID の更新タイミングを自分でハンドリングしなくてよくなった
  • BroadcastReceiver がいらなくなった

まぁ GCM 3.0 くらいから徐々に便利にはなってきていましたが FCM はさらに、といった感じです。
FCM 以外にも Firebase には様々な機能があるので試していければと思います。