[料理佳餚] Xamarin.Forms(Android)接收來自 Firebase Cloud Messaging 的推播通知

Firebase 目前在 Google 的旗下,是一個支援 iOS、Android、Web 應用程式的後端平台,此篇文章是要利用 Firebase 中的 Cloud Messaging(簡稱 FCM)服務,在 Xamarin.Forms Android 的專案中接收來自 FCM 的推播通知。

我個人是習慣用 Xamarin.Forms 來開發 App,無論目前是不是只要發展單一平台還是要跨平台,理由是 Xamarin.Forms 會幫我處理大部分可以跨平台通用的 UI Control,而且用 XAML 這種標籤式語言來刻畫 UI 對我來講比較友善,View Code 跟 C# Code 也清楚地幫我分離了,不過當然這是個人的選擇。

建立 Firebase 專案

註冊一個 Google 帳號,然後到 Firebase 的後台,點擊「新增專案」之後,在畫面上輸入專案名稱、挑選國家/地區,接著點擊「建立專案」按鈕。

連結應用程式

Firebase 可以連結 iOS、Android、Web 三種類型的應用程式,我們選擇「將 Firebase 加入您的 Android 應用程式」。

輸入 Android 的套件名稱,其他兩個欄位為選填,不一定要輸入,完畢後點擊「註冊應用程式」。

下載 google-services.json

接著下載 google-services.json 檔案,待會兒會用到。

如果不小心跳過了「下載設定檔」步驟忘了下載,之後還可以在應用程式的設定畫面中下載得到。

新增 Xamarin.Forms 專案

Cross-Platform App (Xamarin.Forms) 專案範本來建立專案,並且順手將套件名稱修改為剛剛註冊應用程式時所輸入的 Android 套件名稱。

從 NuGet 安裝套件在 xxx.Android 專案

我們從 NuGet 上安裝下列這兩個套件:

  1. Xamarin.GooglePlayServices.Base
  2. Xamarin.Firebase.Messaging

安裝的時候要注意一下自己選擇編譯的 Android 版本,Android 透過 Support Library 的幫忙使我們可以向下相容,如果我們選擇編譯的 Android 版本是 8.0 那麼安裝的 NuGet 套件即便是相依於 MonoAndroid v7.0 也是會建置通過的,但是一旦安裝的 NuGet 是相依於 MonoAndroid v8.0 我們就只能選擇 Android 8.0 的編譯版本,如果選錯了建置就失敗了。

哪一個 MonoAndroid 版本支援哪些 API Level 可以在 Xamarin.Android releases 找到

新增 Google Services JSON 檔案

將剛剛下載的 google-services.json 加入至 xxx.Android 專案,然後在檔案屬性裡面將建置動作調整為 GoogleServicesJson,如果沒有看到 GoogleServicesJson 這個選項,重建方案後把方案關閉再開啟試試看。

在 AndroidManifest.xml 新增 <receiver>

AndroidManifest.xml 是什麼? 簡單來講它是一個 Android App 的自我介紹檔案,裡面宣告了 Android App 用到的服務、程式庫、權限...等包山包海。

AndroidManifest.xml 檔案的位置是在 xxx.Android 專案底下的 Properties 裡面,現在我們要新增 FirebaseInstanceIdInternalReceiverFirebaseInstanceIdReceiver 這兩個 Receiver 進去,把下面這段 Xml 放在 <application> 裡面。

<receiver android:name="com.google.firebase.iid.FirebaseInstanceIdInternalReceiver" android:exported="false" />
<receiver android:name="com.google.firebase.iid.FirebaseInstanceIdReceiver" android:exported="true" android:permission="com.google.android.c2dm.permission.SEND">
	<intent-filter>
		<action android:name="com.google.android.c2dm.intent.RECEIVE" />
		<action android:name="com.google.android.c2dm.intent.REGISTRATION" />
		<category android:name="${applicationId}" />
	</intent-filter>
</receiver>

FirebaseInstanceIdReceiver 的作用是為每個 App 提供一個唯一的 Instance ID,也會幫忙做認證跟授權。

FirebaseInstanceIdInternalReceiver 是一個內部的實作,它會確保服務會被安全地啟動。

建立繼承自 FirebaseInstanceIdService 的類別

這個的目的是我們需要啟動一個背景服務,能夠幫我們到 Firebase 去註冊並取得 Instance ID,我就新增一個類別叫 FirebaseIIDService 繼承自 FirebaseInstanceIdService,覆寫 OnTokenRefresh() 方法並標記兩個 Attribute - ServiceIntentFilter

[Service]
[IntentFilter(new[] { "com.google.firebase.INSTANCE_ID_EVENT" })]
public class FirebaseIIDService : FirebaseInstanceIdService
{
    public override void OnTokenRefresh()
    {
        var token = FirebaseInstanceId.Instance.Token;
        
        Log.Debug("NotificationApp", token);
    }
}

ServiceAttribute 這個 Attribute 主要是用來宣告一個長時間執行的背景服務或 API,它會在產生 AndroidManifest.xml 檔案的當下一起由 monodroid.exe 將 ServiceAttribute 所定義的服務或 API 及其參數寫進 AndroidManifest.xml 檔案。

IntentFilterAttribute 用來定義此 Activity、Service 或 Broadcast Receiver 需要回應的意圖類型,一樣會透過 monodroid.exe 將 IntentFilterAttribute 所定義的意圖類型寫進 AndroidManifest.xml 檔案。

有關於意圖(Intent)的說明可以參考意圖和意圖篩選器這篇文章。

OnTokenRefresh() 方法不常被呼叫,但會在下列幾種情況 Instance ID 被更新時呼叫它:

  1. App 被安裝或移除
  2. 使用者刪除 App 資料
  3. Instance ID 被刪除
  4. Token 的安全性受到影響
  5. 根據 Google Instance ID 文件,通常 App 每 6 個月會更新 Instance ID。

接著我們可以用模擬器或是實體手機實際來部署我們的 App,我們可以用 Android.Util 底下提供的 Log.Debug() 來將 Token 輸出到偵錯視窗查看一下,記得複製下來,待會測試發送推播訊息會用到。

測試發送

我們可以利用 Firebase Notifications 的服務來測試發送推播通知

在撰寫訊息的頁面裡面填入「訊息文字」、「目標」...等,目標就選擇「單一裝置」填入剛剛取得的 Instance ID,在進階選項裡還可以選填「標題」、「優先等級」、「音效」...等。

按下「傳送訊息」之後,在模擬器或者是實體手機上就可以看到推播的訊息了。

參考資料

 < Source Code >

C# 指南ASP.NET 教學ASP.NET MVC 指引
Azure SQL Database 教學SQL Server 教學Xamarin.Forms 教學