【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>
画面キャプチャ
プロジェクトを作る

アプリを登録する

テスト
