AndroidでFirebaseを使ったPush通知(FCM)を実装する

初めまして

会津ラボでAndroid開発を担当している横山です

AndroidでPush通知と言ったらFCM(Firebase Cloud Messaging)ですよね

今回はそんなおなじみの機能を Firebase の設定からテストまで備忘録として記載しようと思います

Firebaseの設定

まずはFirebaseへFCM用のプロジェクトを追加しましょう

Firebase Consoleへアクセスし、「プロジェクトを追加」から新規プロジェクトを作成します


プロジェクトの追加が表示されるので
任意のプロジェクト名を入力し、「次へ」をクリックします


新しいプロジェクトのデータ共有のカスタマイズが表示されますが、
今回は動作を確認するだけなので割愛し「プロジェクトを作成」をクリックします


しばらくするとプロジェクトが作成されますので、「次へ」をクリックします


Project Overview が表示されるので
Androidアプリを追加するためアイコンをクリックします


Android パッケージ名とアプリのニックネームを入力し「アプリを登録」をクリックします
デバッグ用の署名証明書 SHA-1は後ほど入力するのでここでは省略します

※アプリのニックネームはProject Overviewに表示されます
 省略するとパッケージ名が表示されるので、識別しやすいように設定しておくと良いと思います

次に設定ファイルをダウンロードします

「google-services.json をダウンロード」をクリックします
ダウンロードが完了したら「次へ」をクリックします


Firebase SDK の追加ですが次の項で行いますので
そのまま「次へ」をクリックします


下記画面が表示されると思いますが後ほどアプリで疎通確認を行いますので
「このステップをスキップ」をクリックします


次は FCM を実装するための前準備を行っていきます

前準備

まずSHA1を確認するために、新規プロジェクトを作成します

私の環境を参考のために載せておきます

  • Android Studio(3.2.0)
  • Gradle(4.6)
  • Android Plugin Version(3.0.1)

Android Studio で Empty Activity のプロジェクトを作成します

Package name は Firebase の設定で指定した Android パッケージ名を指定しなければいけないので必要があれば変更します


Firebase の設定で省略したSHA-1の設定を行います

右側タブの Gradle を開き
<app name> -> :app -> Tasks -> android まで展開し、signingReport を実行します

タブがない場合はViews -> Tool Windows -> Gradle から表示できます


signingReport を実行すると Window 下に下記のようなログが表示されます
ここで表示される SHA1 が対象のデータなのでコピーしておきます

0:41:18: Executing task 'signingReport'...
Executing tasks: [signingReport]
:app:signingReport
Variant: release
Config: none
----------
Variant: releaseUnitTest
Config: none
----------
Variant: debug
Config: debug
Store: /Users/dyokoyama/.android/debug.keystore
Alias: AndroidDebugKey
MD5: AF:00:00:00:00:00:00:00:00:00:00:00:00:00:00:5E
SHA1: 9F:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:02 #この値
Valid until: 2047年10月6日

Web に戻り、Project Overviewが表示されていると思うので
先ほど作ったアプリを開きます


「フィンガープリントを追加」をクリックします


先ほど確認したSHA1を入力し、「保存」をクリックします


次にクラウドメッセージングタブを開き
サーバーキーをメモしておきます


今度は先ほどダウンロードした設定ファイル(google-services.json)を Android Studio のプロジェクトの配下にある app フォルダへ移動します


これで前準備は完了です
次は実装へ移ります

実装

ここからは Android Studio での作業になります
まずはFCMの機能を使用するために依存関係を設定していきます

Gradle Scripts の build.gradle (Module: app) を開き FCM SDKを追加します

apply plugin: 'com.android.application'
...
android {
    ...
}
dependencies {
    ...
    // FCM を使用するため下記行を追加
    implementation "com.google.firebase:firebase-messaging:17.4.0"
}
// FCM を使用するため下記行を追加
apply plugin: 'com.google.gms.google-services'

Gradle Scripts の build.gradle (Module: ) を編集します

buildscript {
    ...
    dependencies {
        ...
        // この行を追加
        classpath 'com.google.gms:google-services:4.2.0'
    }
}
allprojects {
    ...
}

編集すると右上に「Sync Now」が表示されるのでクリックしてプロジェクトを同期します


MainActivity と同じパッケージディレクトリに MyFirebaseMessagingService クラスを作成します

package com.aizulab.sample.fcm
import android.app.NotificationChannel
import android.app.NotificationManager
import android.os.Build
import android.support.v4.app.NotificationCompat
import android.util.Log
import com.google.firebase.messaging.FirebaseMessagingService
import com.google.firebase.messaging.RemoteMessage
class MyFirebaseMessagingService : FirebaseMessagingService() {
    companion object {
        private const val CHANNEL_ID = "com.aizulab.sample.fcm.MY_CHANNEL"
    }
    override fun onMessageReceived(remoteMessage: RemoteMessage?) {
        remoteMessage?.data?.also { data ->
            val title = data["title"]
            val message = data["message"]
            // Android O(8.0) 以上で通知を表示する場合はチャンネルIDを指定する必要があるので
            // 処理を分けます
            val builder = if (Build.VERSION_CODES.O <= Build.VERSION.SDK_INT) {
                NotificationCompat.Builder(this, CHANNEL_ID)
            }
            else {
                NotificationCompat.Builder(this)
            }
            val notification = builder
                .setSmallIcon(R.mipmap.ic_launcher)     // アイコンは指定必須です
                .setContentTitle(title)                 // 通知に表示されるタイトルです
                .setContentText(message)                // 通知内容を設定します
                .build()
            // 通知を表示します
            val nm = getSystemService(NOTIFICATION_SERVICE) as NotificationManager
            nm.notify(0, notification)
        }
    }
    override fun onNewToken(instanceToken: String?) {
        // テストで使用するため、ログにトークンを出力します
        Log.i("SampleFCM", "token: $instanceToken")
        // 同時に通知の設定をここでしてしまいます
        val nm = getSystemService(NOTIFICATION_SERVICE) as NotificationManager
        // Android O(8.0) 以上で通知を使用する場合は通知チャンネルを作成する必要があります
        if (Build.VERSION_CODES.O <= Build.VERSION.SDK_INT) {
            var channel = nm.getNotificationChannel(CHANNEL_ID)
            if (channel == null) {
                channel = NotificationChannel(
                    CHANNEL_ID,
                    "プッシュ通知用のチャンネルです",
                    NotificationManager.IMPORTANCE_HIGH)
                nm.createNotificationChannel(channel)
            }
        }
    }
}

クラスを作成したら、AndroidManifest.xml へサービスを登録します

<?xml version="1.0" encoding="utf-8"?>
<manifest ...>
    <application ...>
        <service
            android:name=".MyFirebaseMessagingService"
            android:exported="false"
            android:enabled="true">
            <intent-filter>
                <action android:name="com.google.firebase.MESSAGING_EVENT" />
            </intent-filter>
        </service>
        <activity ... />
    </application>
</manifest>

ここまで作成できたら実機またはエミュレーターへインストールし、実行してみましょう

下記のようなログが表示されば実装は完了です

05-18 13:20:12.750 30081-30283/com.aizulab.sample.fcm I/SampleFCM: token: e7ydExtRVt8:APA91 〜省略〜 ciZV2xz2UK5X1v6BGW

残るはテストのみ、もう一踏ん張りです

テスト

さて、実装まで完了したので実際にPush通知が届くか確認してみましょう

通知を送信するためのシェルスクリプトを作成します
わかりやすい場所に push.sh ファイルを作り、処理を記載します

#!/bin/bash
api_key=前準備でメモしておいたサーバーキーをここに記載
token=実装でログに表示したトークンをここに記載
type=data
#type=notification
curl --header "Authorization: key=$api_key" \
     --header Content-Type:"application/json" \
     https://fcm.googleapis.com/fcm/send \
     -d "{\"to\":\"$token\", \"$type\":{\"title\":\"メッセージタイトル\",\"message\":\"メッセージ本文\",\"type\":\"notification\"}}"

ファイルを作成したらターミナルを開き下記コマンドを実行します
パスは各々のファイルを作成した場所を指定してください

chmod 755 ~/push.sh

ここまできたらあとはシェルスクリプトを実行するだけです

~/push.sh

通知が表示されればテスト完了です

以上、Firebase の設定からテストまででした

おわりに

いかがでしたでしょうか?

意外と簡単に実装からテストまでできたと思います

また、疑問点や不明点、誤字脱字等ありましたらコメント頂けますと幸いです

それでは、お疲れ様でした

2個のコメント

タチコマより

2020.10.03 16:57

お世話になっております。
本記事拝見しandroidに造詣が深いとお見受け致します。
当方、androidでアプリ開発をやり始めたばかりなのですが、自作アプリでLINE notifyを使用し自身のライングループへアプリから固定のメッセージを送りたいと考えております。
そう難しくはないかと思ったのですが、どういうコードを書けばいいかピンと頭に思い浮かばず苦戦しております。。。
【javaをやり始めて2ケ月足らずですので、まだ初心者です。。】
申し訳ないのですが、本記事とは少し反れますが以下疑問がありますので可能であればアドバイス頂けないでしょうか?
①line notifyを使用したいならLINE SDKをandroid studioにインポートしなければならないでしょうか?
②javaで単純にLINE notifyを使用して固定メッセージを送る場合どのようなコードになるのかアドバイス頂けないでしょうか?【line側のアクセストークン等は既に取得済です。】
多忙な中申し訳ございませんが、アドバイス頂けたら助かります。
何卒宜しくお願い致します。

yokoyamaよりタチコマに返信

2020.11.27 11:51

タチコマ様

返信が遅くなってしまいすみません。

本件、解決されましたでしょうか?
私が試した範囲で回答いたします。
①line notifyを使用したいならLINE SDKをandroid studioにインポートしなければならないでしょうか?
→不要のようです。
②javaで単純にLINE notifyを使用して固定メッセージを送る場合どのようなコードになるのかアドバイス頂けないでしょうか?【line側のアクセストークン等は既に取得済です。】
→下記に私が試したコードを記載します。

*AndroidManifest.xml

<manifest ...>
// 下記行を追加
<uses-permission android:name="android.permission.INTERNET" />
<application .../>
</manifest>

*送信処理
final Runnable run = new Runnable() {
@Override
public void run() {
HttpURLConnection httpConn = null;
OutputStream os = null;
try {
URL url = new URL(“https://notify-api.line.me/api/notify”);
httpConn = (HttpURLConnection) url.openConnection();
httpConn.setRequestMethod(“POST”);
httpConn.setDoOutput(true);
httpConn.setDoInput(true);
httpConn.setRequestProperty(“Authorization”, “Bearer トークン”); // トークンを置き換えてください。
httpConn.connect();
os = httpConn.getOutputStream();
os.write(“message=foobar”.getBytes(“UTF-8”)); // メッセージを変えたい場合は foobar を別の文字に置き換えてください。
os.flush();
os.close();
Log.e(“TAG”, “status code: ” + httpConn.getResponseCode() + “, message: ” + httpConn.getResponseMessage());
}
catch (Exception e) {
e.printStackTrace();
}
finally {
if (httpConn != null) {
httpConn.disconnect();
}
}
}
};
Thread thread = new Thread(run);
thread.start();

以上になります。
よろしくお願いいたします。

コメントを残す

メールアドレスが公開されることはありません。*がついている欄は必須項目です。

日本語が含まれない投稿は無視されますのでご注意ください。