如何使用 Firebase - 使用 Notification(kotlin)

如何使用 Firebase - 使用 Notification(kotlin)

情境

在早期叫做 Android Cloud to Device Messaging (C2DM),後來改成使用 Google Cloud Messaging (GCM),現在因為 Firebase 而推出了 Firebase Cloud Messaging (FCM),FCM 簡單操作而且方便,只需要幾個簡單的設定,就可以完成推播的功能。

完整程式碼

你可以到 GitHub 觀看或者下載完整程式碼。

程式碼說明

根據 如何使用 Firebase - 用 Android Studio 建立帳戶篇 所示,我們透過 Android Studio 開啟 Firebase Cloud Messaging(以下簡稱 FCM) 連結,如下圖所示。

如果你將 FCM 連結以後會看到專案內多出了一個 google-services.json 檔案,也可以看到 app 內的 build.gradle 多了一些資訊。

apply plugin: 'com.android.application'

android {
	//...
}

dependencies {
	//...
    implementation 'com.google.firebase:firebase-messaging:20.1.0'
}
apply plugin: 'com.google.gms.google-services'

接著打開 project 內的 build.gradle 同樣多了 google service 的宣告。

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

此時我們打開 Firebase 後臺會發現多了一個 FCMDemo 的專案,如下圖所示。


點進去以後就會看到一個按鈕如下圖,點選按鈕以後就可以開始傳送我們要傳送的訊息了。


如果您要傳送訊息,會有五個步驟,第一個步驟輸入文字標題以及通知文字的對話框,如下方圖所示,我們輸入好標題跟通知文字的內容。


第二個步驟是要我們選擇要傳送的 App,有時候雙平台會共用一個 Project,或者不同用途的 App 也可以塞進同一個 Proejct 內,因此,這邊要選對 App 不然就尷尬了。

備註:一個 Firebase Project 在免費版中,只能建立 10 個 Project。


第三步驟可以選擇要傳送的時間,像我們想要立即傳送,就可以選擇現在,你也可以排定你要排定的時間傳送。


第四個步驟,你可以選擇你要轉換的事件,這邊有多個選項。

你可以選擇使用者在哪種情況接收傳送訊息,第一次開啟 App或者在 App 開啟的時候。

接下來是第五步驟,這是最後一步驟了,這邊讓你多一種傳送的方式,後面會有程式碼解說,這邊讓你用 Key : Value 對應的方式進行傳送相關資料。

當按下審查以後,就會跳出一個小視窗跟你進行最後確認。

完成以上步驟就可以透過 Firebase 後臺幫我們傳送訊息了,如果有成功跟 Firebase 串接的手機端程式就可以接收到這一則訊息,那接下來我們要撰寫的部分就是如何讓手機端接收到 Firebase 傳過來的訊息。

程式碼細節說明

我們剛剛建立好了 FCMDemo 的專案,根據官網 FCM Client Setup 的引導教學,首先,在專案內一個 Service 類別,它繼承 FirebaseMessagingService,你需要建立好兩個方法,分別為 onNewToken 以及 onMessageReceived。

  • onNewToken 方法
override fun onNewToken(token: String) {  
    super.onNewToken(token)  
    Log.e("fcm", "refresh token:$token")  
}

可以看到我們可以從下面這個方式來取得 Token。

FirebaseInstanceId.getInstance().getToken()

取得目前最新的 Token,這個 Token 是有時效性的,因此,當我們這個方法被呼叫的時候,就會更新到我們的 APP Server 上面 (App Server 是我們自己架設的伺服器,用來跟 FCM Server 溝通。

  • onMessageReceived 方法
override fun onMessageReceived(remoteMessage: RemoteMessage){  
    super.onMessageReceived(remoteMessage)
}

這邊是我們需要關心的地方, 當 App Server 或者 Firebase Console 發出訊息時, 會從這個方法接收到傳送出去的訊息。
現在我們來試看看是否會收到訊息?
我們在 onMessageReceived 方法內插入了一筆 Log。

override fun onMessageReceived(remoteMessage: RemoteMessage){  
    super.onMessageReceived(remoteMessage)
    Log.e("fcm", "onMessageReceived")
}

此時你會發現訊息都收不到, 很可能是在 AndroidManifest.xml 的 <Application></Application> 內忘記補上 Service Filter 。

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

當你補上 Service Filter 以後,就會發現 Firebase 後臺送出訊息後,會有資料進來。

com.example.givemepass.fcmdemo I/message: onMessageReceived

那如果想把傳送過來的訊息印出來該怎麼辦?
可以把 Log 改成下面方式印出來。

Log.i("fcm", remoteMessage.getNotification().getBody())

當 Firebase 後臺傳送訊息以後, 就能夠在 logcat 看到訊息。

com.example.givemepass.fcmdemo I/message: 你傳送的訊息

我們在後臺傳送訊息頁面往下拉,點選進階選項,看到這樣的畫面,這邊就是前面您送出標題跟內文的地方。


後臺有另外一種通知的方式,是以 key : value 的方式傳送,通常這邊會是使用者在 App 內,我們想要讓使用者知道訊息,所進行的一種處理。我們嘗試送出去一筆資訊,將接收訊息的方法改成以下方式來處理。

override fun onMessageReceived(remoteMessage: RemoteMessage) {  
	super.onMessageReceived(remoteMessage)  
	remoteMessage.run {  
		var msg = StringBuffer()  
		//..  
		data.forEach {  
			val m = "key:${it.key}, value:${it.value}"  
			Log.e("fcm", "m:$it")  
			msg.append(m)  
		}  
		sendNotification(msg.toString())  
		EventBus.getDefault().post(msg.toString())  
	}  
}

再回顧一下第五步驟,在 Firebase 後臺輸入對應的值,按下審核且送出訊息,就是在處理這部分。


看一下 Android Studio 的 logcat,就會看到以下的訊息。

com.example.givemepass.fcmdemo I/fcm msg title:Hi, body:I want to play a game.
com.example.givemepass.fcmdemo I/fcm key:Who are you, value:I am your daddy

你會看到有兩個訊息分別來自不同的傳送方式。

  • 透過 Title 以及 Body 方法來取得,這部分專門用在 Notification。

RemoteMessage.getNotification().getTitle()
RemoteMessage.getNotification().getBody()

  • 透過 Key : Value 的傳送方式必須透過以下的方式來取得,再透過 foreach 的方式把資料全部撈出來,這部分用在使用者 In App 的時候。

RemoteMessage.getData()

Notification 顯示。

如果你想要做成 Notification 的方式呈現,根據官網範例只需要加入以下的方式就可以很容易實現。

private fun sendNotification(msg: 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 = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)  
    val notificationBuilder = NotificationCompat.Builder(this, "")  
            .setSmallIcon(R.drawable.ic_android)  
            .setContentTitle("FCM Message")  
            .setContentText(msg)  
            .setAutoCancel(true)  
            .setSound(defaultSoundUri)  
            .setContentIntent(pendingIntent)  
    val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager  
    notificationManager.notify(0, notificationBuilder.build())  
}

只要加入這段程式碼,接著只要收到訊息以後,而且不在 App 內,就會看見 Notification 出現。


那如果說你想要接收從推播過來的訊息,剛好使用者也在 App 內,所以想把接收的結果呈現在畫面上, 應該怎麼做呢?
我們可以透過 EventBus 來達成這樣的功能,它在操作上非常簡單,只需要在要發送的地方使用以下程式碼,就會進行發送了。

EventBus.getDefault().post("你要發送的訊息")

接著在 MainActivity 定義一個方法來接收它,並且在 onCreate 以及 onPause 註冊跟反註冊即可。

override fun onCreate(savedInstanceState: Bundle?) {  
    super.onCreate(savedInstanceState)  
    setContentView(R.layout.activity_main)  
    EventBus.getDefault().register(this)  
}  
  
@Subscribe(threadMode = ThreadMode.MAIN)  
fun onMsgEvent(msgEvent: String) {  
    Log.e("fcm", "msg:${msgEvent}")  
    msg_text.text = msgEvent  
}  
  
override fun onPause() {  
    super.onPause()  
    EventBus.getDefault().unregister(this)  
}

如此一來, 就可以透過後臺傳送訊息過來的結果, 顯示在畫面上。


這樣就是一個簡單的 Firebase Notification 的範例了。