【Android】FirebaseCloudMessagingを使ってみた
お約束
この記事は「いのべこ夏休みアドベントカレンダー2020」の19日目(8月19日)の記事です。 本記事の掲載内容は私自身の見解であり、所属する組織を代表するものではありません(お約束)。
本題
L●NEは、ユーザ側でアプリをタスクキルしていても通知が届く。 さて、どうやって実現するんだろう?という話。
クラウドメッセージという存在
Googleが出しているクラウドメッセージサービスがある。 2019年まではGCM(Google Cloud Messaging)だったが、2020年現在はFCM(Firebase Cloud Messaging)である。
Firebaseのサイトに沿ってプロジェクト情報の登録、アプリ情報(アプリ名とかパッケージ名)の登録をして。 アプリ実装側では、Firebaseでアプリ情報を登録してる間に生成されたJSONファイルを組み込んで。 SDKもbuild.gradleに追記しつつ、デバイストークンを取得。 取得したデバイストークン&登録したアプリのパッケージ名に向けて、通知を送信してやる流れ。
軽くやってみることにする。
Firebaseのサイトが1ステップごとに説明してくれるので、それにそってやれば大体できる。
ステップ | Firebase/AndroidStudio | やること |
---|---|---|
事前準備 | Firebase | コンソール画面にGoogleアカウントでログイン。 必要ならアカウント作って。 |
事前準備 | AndroidStudio | AndroidStudioを使い、アプリを新規作成する アプリ名、パッケージ名はあとで使うので覚えておくこと。 |
プロジェクト登録 | Firebase | コンソールトップ画面から、プロジェクトを追加する。 |
プロジェクト登録 | Firebase | プロジェクト名をつける |
プロジェクト登録 | Firebase | Googleアナリティクスを有効にするか否か選ぶ。 地域も選ぶ 今回はアナリティクスは有効。地域は日本にした。 |
プロジェクト登録 | Firebase | いろいろ同意するチェックを入れるとプロジェクトができる。 |
アプリ登録 | Firebase | プロジェクト作成後の画面で、作りたいアプリの種類を選ぶ。 今回はAndroid |
アプリ登録 | Firebase | 先ほどAndroidStudioで作ったアプリのアプリ名・パッケージ名を入力する |
アプリ登録 | Firebase | google-service.jsonが生成される。 このJSONファイルはapp配下にコピーする |
アプリ登録 | Firebase & AndroidStudio |
[Firebase]google-service.jsonが生成される。 [AndroidStudio]このJSONファイルはapp配下にコピーする |
アプリ登録 | AndroidStudio | [プロジェクトフォルダ]/build.gradleに依存関係を追加する。※ソース1 |
アプリ登録 | AndroidStudio | app/build.gradleに依存関係を追加する。※ソース2 |
実装 | AndroidStudio | デバイストークンを取得し、画面に表示されるMainActivity.ktを作った。※ソース3 |
実装 | AndroidStudio | FirebaseMessagingServiceを継承したクラスを作る。※ソース4 |
実装 | AndroidStudio | AndroidManifestを修正。※ソース5 |
実装 | AndroidStudio | レイアウトをいじる。※ソース6 |
テスト | AndroidStudio | エミュレータを起動し、画面に表示されているデバイストークンをコピーしておく |
テスト | Firebase | 左側メニューの「拡張>CloudMessaging>Send your First Message」を選ぶ | |
テスト | Firebase | 通知タイトル・内容を入力し、「テストメッセージを送信」を押下 |
テスト | Firebase | FCMトークンを入力して、送信を押す |
テスト | AndroidStudio | エミュレータにインストールしたアプリに対して通知されてることを確認する |
ね?簡単でしょ? Googleアカウント無料で作れるし、ぜひ遊んでみて!
いのべこ夏休みアドベントカレンダー2020では2本目。 また画面キャプチャとソースばかりの記事になってしまった。。 次回以降もこんな感じで、このお祭りに参加していきたい。
以下、ソースと画面キャプチャ
ソース1:プロジェクトフォルダ直下のbuild.gradle
buildscript { repositories { // 追加 google() } dependencies { // 追加 classpath 'com.google.gms:google-services:4.3.3' } }
ソース2:app/bild.gardle
apply plugin: 'com.google.gms.google-services' dependencies { implementation 'com.google.firebase:firebase-analytics:17.4.4' implementation 'com.google.firebase:firebase-messaging:20.2.4' }
ソース3:MainActivity.kt
class MainActivity : AppCompatActivity() { @SuppressLint("StringFormatInvalid") override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) FirebaseInstanceId.getInstance().instanceId .addOnCompleteListener(OnCompleteListener { task -> if (!task.isSuccessful) { Log.w("narita", "getInstanceId failed", task.exception) return@OnCompleteListener } // Get new Instance ID token val token = task.result?.token textView.text = token Log.i("token:",token.toString()) // サーバにトークン送信していないため、トークンをTextBoxに格納 textBox.setText(token, TextView.BufferType.NORMAL) }) } }
ソース4:FirebaseMessagingServiceを継承したMyFirebaseMessage.kt
private val TAG: String = com.test.notification.MyFirebaseMessage::class.java.simpleName override fun onMessageReceived(message: RemoteMessage) { val from = message.from val data: Map<*, *> = message.data Log.d(TAG, "from:$from") Log.d(TAG, "data:$data") val msg = data["data"].toString() sendNotification(msg) } private fun sendNotification(message: String) { val intent = Intent(this, MainActivity::class.java) intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) val pendingIntent = PendingIntent.getActivity( this, 0, intent, PendingIntent.FLAG_ONE_SHOT ) val defaultSoundUri: Uri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_RINGTONE) val notificationBuilder = NotificationCompat.Builder(this) .setSmallIcon(R.mipmap.sym_def_app_icon) .setContentTitle("Push通知のタイトル") .setSubText("Push通知のサブタイトル") .setAutoCancel(true) .setSound(defaultSoundUri) .setStyle(NotificationCompat.BigTextStyle().bigText(message)) .setContentIntent(pendingIntent) val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager notificationManager.notify(0, notificationBuilder.build()) }
ソース5:AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.test.notification"> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme"> <!-- Set custom default icon. This is used when no icon is set for incoming notification messages. See README(https://goo.gl/l4GJaQ) for more. --> <meta-data android:name="com.google.firebase.messaging.default_notification_icon" android:resource="@drawable/ic_launcher_foreground" /> <!-- Set color used with incoming notification messages. This is used when no color is set for the incoming notification message. See README(https://goo.gl/6BKBk7) for more. --> <meta-data android:name="com.google.firebase.messaging.default_notification_color" android:resource="@color/colorAccent" /> <meta-data android:name="com.google.firebase.messaging.default_notification_channel_id" android:value="@string/common_google_play_services_notification_channel_name" /> <service android:name=".MyFirebaseMessage" android:enabled="true" android:exported="false" > <intent-filter> <action android:name="com.google.firebase.MESSAGING_EVENT"/> </intent-filter> </service> <activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>
ソース6:レイアウトactivity_main.xml
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <TextView android:id="@+id/textView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Hello World!" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" /> <EditText android:id="@+id/textBox" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="114dp" android:layout_marginTop="419dp" android:ems="10" android:inputType="textPersonName" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> </androidx.constraintlayout.widget.ConstraintLayout>
画面キャプチャ
プロジェクトを作る
アプリを登録する
テスト