Xamarin.Android 的遠端推播通知 Remote Push Notification - 使用 Azure Notification Hub
本章節將會說明如何透過 Azure Notification Hub 服務,建立起一個具有遠端推播訊息功能的 Android App。
了解更多關於 [Xamarin.Android] 的使用方式
了解更多關於 [Xamarin.iOS] 的使用方式
了解更多關於 [Xamarin.Forms] 的使用方式
了解更多關於 [Hello, Android:快速入門] 的使用方式
了解更多關於 [Hello, iOS – 快速入門] 的使用方式
了解更多關於 [Xamarin.Forms 快速入門] 的使用方式
本教學課程示範如何使用 Azure 通知中樞將推播通知傳送至 Xamarin.Android 應用程式。 您會建立可使用 Firebase 雲端通訊 (FCM) 接收推播通知的空白 Xamarin.Android 應用程式。 您會使用通知中樞,將推播通知廣播到所有執行您的應用程式的裝置。 NotificationHubs 應用程式範例中提供完成的程式碼。
在本教學課程中,您會執行下列步驟:
- 建立 Firebase 專案並啟用 Firebase 雲端通訊
- 建立 Azure 通知中樞
- 建立 Xamarin.Android 應用程式,並將其連線至通知中樞
- 從 Azure 入口網站傳送測試通知
必要條件
- Azure 訂用帳戶。 如果您沒有 Azure 訂用帳戶,請在開始前建立免費 Azure 帳戶。
- Visual Studio 搭配 Xamarin (在 Windows 上) 或 Visual Studio for Mac (在 OS X 上)。
- 有效的 Google 帳戶
建立 Firebase 專案並啟用 Firebase 雲端通訊
建立一個新的 Firebase 專案
- 打開 Firebase 主控台 網頁,使用您的 Google 帳號,登入到 Firebase 系統內 。在登入首頁內,點選 [新增專案] 按鈕
- 在 [新增專案] 對話窗中的 [專案名稱] 欄位,輸入
Xamarin-Push-Notification
- 勾選 [新增專案] 對話窗最下方的 我接受 ... 檢查盒
- 最後,點選 [建立專案] 按鈕
- 當此 Firebase 專案建立完成之後,點選 [繼續] 按鈕
- 現在,將會顯示
Xamarin-Push-Notification
這個專案頁面,找到 [首先請新增應用程式] 文字,點選該文字上方代表 Android 機器人的圖示,[將 Firebase 新增至 Android 應用程式] - 此時,將會顯示 [新增 Android 應用程式] 頁面,並且將會有四個步驟要進行,分別是 [註冊應用程式]、[下載設定檔]、[新增 Firebase SDK]、[執行應用程式以驗證是否安裝成功]
- 在 [註冊應用程式] 步驟中,需要填寫底下兩個欄位資料
- 在 [Android 套件名稱] 欄位中,輸入
com.vulcan.AzureNHub
把這個 Android 套件名稱 字串記錄下來該 Android 套件名稱 將會於 Xamarin.Android 專案中用到,這將會用於 Xamarin.Android 的 [Xamarin.Android 專案屬性] > [Android 資訊清單] > [套件名稱] 欄位,因此,請將這個 套件名稱 記錄下來
- 在 [應用程式暱稱 (選填)] 欄位中,輸入
Azure Notification Hub Lab
- 點選 [註冊應用程式] 按鈕
- 在 [下載設定檔] 步驟中,請點選 [下載 google-servic.json] 按鈕,取得
google-servic.json
這個檔案,等下在 Xamarin.Android 專案內會使用的到。
請將這個 google-servic.json 妥善保存在適當的地方google-servic.json 檔案 將會於 Xamarin.Android 專案中用到
- 點選右下角的 [繼續] 按鈕,繼續下一個步驟
- 在 [新增 Firebase SDK] 步驟中,點選右下角的 [繼續] 按鈕,繼續下一個步驟
- 在 [執行應用程式以驗證是否安裝成功] 步驟中,點選右下角的 [略過此步驟] 連結,完成 新增 Android 應用程式 程序。
Firebase 專案設定
- 現在將會顯示出 [Xamarin-Push-Notification] 頁面,在該頁面左上方找到 [Project Overview] 文字的右方,有個齒輪圖示
- 點選該齒輪圖示,在彈出子視窗中,點選 [專案設定]
- 此時,將會看到 [設定] 頁面的 [一般] 標籤,若剛剛忘記取得
google-servic.json
這個檔案,可以在這裡點選 [下載 google-servic.json] 按鈕,來重新取得 - 點選 [Cloud Messaging] 標籤,將會看到有個 伺服器金鑰 欄位。
把這個 伺服器金鑰 字串記錄下來請把這個 伺服器金鑰 值記錄下來,等下在 Azure 通知中樞內會用到,因此,請將這個 伺服器金鑰 記錄下來
建立 Azure 通知中樞
- 打開 Azure 入口網站 網頁,使用您的 Microsoft 帳號,登入到 Azure 系統內 。
- 在 Azure 入口網站 左方,點選 [所有服務],當 所有服務 的彈出子畫面出現後,在該子畫面最上方輸入
hub
,將會得到與 hub 有關的 Azure 產品。此時,請選擇 [Notification Hubs] 這個項目 - 現在將會顯示 [Notification Hubs] 頁面,請點選上方工具列的 [新增] 按鈕,準備新增一個 Notification Hubs 服務
- 當顯示新 刀鋒 視窗,分別在底下欄位填入適當的欄位值
- Notification Hub
這裡需要填入這個通知中樞服務的名稱,請輸入azure-notification-hub-lab
- Create a new namespace
在這裡填入一個通知中樞的命名空間,由於在這裡僅是做練習,因此請在此輸入azure-notification-hub-lab
,建立一個新的通知中樞命名空間 - 位置
在這裡選擇東南亞
- Resource Group
由於在這裡僅是做練習,在這裡點選 [新建] 連結,當顯示文字資源群組是能夠存放 Azure 解決方案相關資源的容器。
的彈出視窗,在該彈出視窗的 名稱 欄位內,填入azure-notification-hub-lab
,完成後,點選 [確定] 按鈕。 - 訂用帳戶
依據登入帳號可以使用訂用帳戶,選擇合適的帳戶項目 - Pricing tier
由於在這裡僅是做練習,在這裡就僅選擇Free
- Notification Hub
把這個 通知中樞服務的名稱 字串記錄下來通知中樞服務的名稱 等下在 Xamarin.Android 專案內會用到,因此,請將這個通知中樞服務的名稱 字串記錄下來
- 最後,在該 刀鋒 視窗下方,點選 [建立] 按鈕
- 當通知中樞建立完成之後,可以點選 [通知] 鈴鐺圖示,然後選取 [前往資源] 按鈕,或重新整理 [通知中樞] 頁面中的清單,然後選取您的通知中樞
- 當進入到剛剛建立的 [azure-notification-hub-lab] 通知中樞項目頁面,在左方的功能表清單中,選取 [Access Policies]。
把這個 DefaultListenSharedAccessSignature 字串記錄下來這裡存在兩個連接字串,請記下 [DefaultListenSharedAccessSignature] 這個連結字串,因為,等下在 Xamarin.Android 專案中會使用到
設定通知中樞的 GCM 設定
- 在剛剛的 [azure-notification-hub-lab] 通知中樞項目頁面,從左方功能表清單內,點選 [Google (GCM/FCM)] 這個項目
- 找出剛剛在 Firebase 專案內的 伺服器金鑰 ,將這個 伺服器金鑰 值填入到 [API Key] 欄位內,然後點選 [Save] 按鈕,儲存這個設定
建立 Xamarin.Android 應用程式,並將其連線至通知中樞
建立 Xamarin.Forms 專案
請依照底下說明步驟,建立一個使用 Prism 開發框架的 Xamarin.Forms 練習專案
- 啟動 Visual Studio 2017 應用程式
- 點選功能表 [檔案] > [新增] > [專案]
- 在 [新增專案] 對話窗左方,點選 [Prism] 項目
- 在 [新增專案] 對話窗中間,點選 [Prism Blank App (Xamarin.Forms)],
- 在 [新增專案] 對話窗下方的 [名稱] 欄位,輸入
XFAzureNHub
- 點選 [新增專案] 對話窗右下方的 [確定] 按鈕
- 當 [PRISM PROJECT WIZARD] 對話窗出現之後,請確定有勾選 [ANDROID] 與 [iOS] 這兩個項目,而 [UWP] 這個項目則不要勾選
- 確定 [Container] 下拉選單欄位,選擇的是 [Unity]
- 最後,點選 [CREATE PROJECT] 按鈕
- 現在,請等候 Xamarin.Forms 專案建立完成
套用 Firebase 設定到 Xamarin.Android 專案
- 展開 [XFAzureNHub.Android] 專案,使用滑鼠雙擊 [Properties] 節點
- 點選 [Android 資訊清單] 標籤頁次,將剛剛在 Firebase 專案中設定的套件名稱,也就是
com.vulcan.AzureNHub
,填入到 [套件名稱] 欄位內。
需要設定與 Firebase 專案上相同的 套件名稱若 Xamarin.Android 專案屬性中的套件名稱與 Firebase 專案內的套件名稱兩者不一致,將會造成這個 Xamarin.Android 專案無法正常接收到來自遠端的推播通知。
安裝相關 NuGet 套件
- 滑鼠右擊 [XFAzureNHub.Android] 專案的 [參考] 節點,選取 [管理 NuGet 套件] 選項
- 切換到 [瀏覽] 標籤頁次
- 搜尋 [Xamarin.GooglePlayServices.Base] 套件,安裝到 [XFAzureNHub.Android] 專案
- 搜尋 [Xamarin.Firebase.Messaging] 套件,安裝到 [XFAzureNHub.Android] 專案
- 搜尋 [Xamarin.Azure.NotificationHubs.Android] 套件,安裝到 [XFAzureNHub.Android] 專案
新增 Google Services JSON 檔案
接下來要來處理一個 Firebase 很重要的檔案,也就是剛剛從 Google Firebase 主控台下載下來的
google-services.json
檔案- 找到剛剛下載下來的
google-services.json
,把它拖拉到方案總管的 [XFAzureNHub.Android] 專案內 - 點選
google-services.json
檔案,並且在 [屬性] 窗格中,將 [建置動作] 設定為 GoogleServicesJson。
看不到 GoogleServicesJson 選項之處置做法如果您未看到 GoogleServicesJson 選項,請關閉 Visual Studio 再加以重新啟動,並重新開啟專案,然後重複上述步驟,就會看到了 GoogleServicesJson 選項。
開始設計 Firebase 推播通知的相關程式碼
- 展開 [XFAzureNHub.Android] 專案內的 [Properties] 節點,打開 [AndroidManifest.xml] 檔案
- 將下列
<receiver>
元素插入<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>
- 底下是修正後的 [AndroidManifest.xml] 檔案內容
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" package="com.vulcan.AzureNHub" android:installLocation="auto">
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="27" />
<uses-permission android:name="android.permission.INTERNET" />
<application android:label="XFAzureNHub.Android" android:icon="@mipmap/ic_launcher">
<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>
</application>
</manifes>
建立 Constants.cs 類別
- 在 [XFAzureNHub.Android] 專案內,建立一個 Constants.cs 類別,並定義類別中的下列常數值。其中,[ListenConnectionString] 這個常數,需要到 Azure 通知中樞中,找到 [DefaultListenSharedAccessSignature] 這個欄位值來填入進來,這個欄位值可以從 [azure-notification-hub-lab] 這個通知中樞設定頁面,在左方功能清單的最下方,找到 [Manage] > [Access Policies] 連結,點擊之後,就會在右方視窗中看到 [DefaultListenSharedAccessSignature] 欄位。另外一個 [NotificationHubName] 常數,就是這個 Azure 通知中樞的名稱,也就是 [azure-notification-hub-lab]
Constants.cs
public static class Constants
{
public const string ListenConnectionString = "請在這裡填入 Azure Notification Hub 的 DefaultListenSharedAccessSignature 值";
public const string NotificationHubName = "這裡填入 Azure Notificaion Hub 的名稱";
public const string ChannelName = "azure-notification-hub-lab";
public const string CHANNEL_ID = "location_notification";
public const string NotificationTitle = "Azure 通知中樞訊息";
}
修正 MainActivity 類別
- 打開 [MainActivity.cs] 檔案,在最前面加入底下的命名空間參考
MainActivity.cs
using Android.Util;
在這個 [MainActivity] 類別,加入底下的常數欄位宣告
MainActivity.cs
public const string TAG = "MainActivity";
- 將下列程式碼新增到
base.OnCreate(savedInstanceState)
之後的OnCreate
MainActivity.cs
if (Intent.Extras != null)
{
foreach (var key in Intent.Extras.KeySet())
{
if(key!=null)
{
var value = Intent.Extras.GetString(key);
Log.Debug(TAG, "Key: {0} Value: {1}", key, value);
}
}
}
建立 MyFirebaseIIDService 類別
- 在 [XFAzureNHub.Android] 專案內,建立一個 MyFirebaseIIDService.cs 類別
- 使用底下程式碼替換掉檔案內容
MyFirebaseIIDService.cs
using System.Collections.Generic;
using Android.App;
using Android.Content;
using Android.Util;
using WindowsAzure.Messaging;
using Firebase.Iid;
namespace XFAzureNHub.Droid
{
[Service]
[IntentFilter(new[] { "com.google.firebase.INSTANCE_ID_EVENT" })]
public class MyFirebaseIIDService : FirebaseInstanceIdService
{
const string TAG = "MyFirebaseIIDService";
NotificationHub hub;
public override void OnTokenRefresh()
{
var refreshedToken = FirebaseInstanceId.Instance.Token;
Log.Debug(TAG, "FCM token: " + refreshedToken);
SendRegistrationToServer(refreshedToken);
}
void SendRegistrationToServer(string token)
{
// Register with Notification Hubs
hub = new NotificationHub(Constants.NotificationHubName,
Constants.ListenConnectionString, this);
var tags = new List<string>() { };
var regID = hub.Register(token, tags.ToArray()).RegistrationId;
Log.Debug(TAG, $"Successful registration of ID {regID}");
}
}
}
建立 MyFirebaseMessagingService 類別
- 在 [XFAzureNHub.Android] 專案內,建立一個 MyFirebaseMessagingService.cs 類別
- 使用底下程式碼替換掉檔案內容
MyFirebaseMessagingService.cs
using System;
using System.Linq;
using Android.App;
using Android.Content;
using Android.Media;
using Android.OS;
using Android.Support.V4.App;
using Android.Util;
using Firebase.Messaging;
namespace XFAzureNHub.Droid
{
[Service]
[IntentFilter(new[] { "com.google.firebase.MESSAGING_EVENT" })]
public class MyFirebaseMessagingService : FirebaseMessagingService
{
const string TAG = "MyFirebaseMsgService";
public override void OnMessageReceived(RemoteMessage message)
{
Log.Debug(TAG, "From: " + message.From);
if (message.GetNotification() != null)
{
//These is how most messages will be received
Log.Debug(TAG, "Notification Message Body: " + message.GetNotification().Body);
createNotification(Constants.NotificationTitle, message.GetNotification().Body);
}
else
{
//Only used for debugging payloads sent from the Azure portal
createNotification(Constants.NotificationTitle, message.Data.Values.First());
}
}
void createNotification(string title, string desc)
{
var intent = new Intent(this, typeof(MainActivity));
intent.AddFlags(ActivityFlags.ClearTop);
var pendingIntent = PendingIntent.GetActivity(this, RandomGenerator(), intent, PendingIntentFlags.OneShot);
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
.SetSmallIcon(Resource.Drawable.ic_launcher)
.SetContentTitle(title)
.SetContentText(desc)
.SetSound(RingtoneManager.GetDefaultUri(RingtoneType.Notification))
.SetAutoCancel(true)
.SetContentIntent(pendingIntent);
NotificationManager notificationManager;
notificationManager = (NotificationManager)GetSystemService(Context.NotificationService);
if (Build.VERSION.SdkInt < BuildVersionCodes.O)
{
notificationManager.Notify(RandomGenerator(), notificationBuilder.Build());
}
else
{
notificationBuilder.SetChannelId(Constants.CHANNEL_ID);
var name = Constants.ChannelName;
var description = desc;
var channel = new NotificationChannel(Constants.CHANNEL_ID, name, NotificationImportance.Default)
{
Description = description,
};
notificationManager.CreateNotificationChannel(channel);
notificationManager.Notify(RandomGenerator(), notificationBuilder.Build());
}
}
private int RandomGenerator()
{
return new Random().Next(int.MinValue, int.MaxValue);
}
}
}
開始進行測試
- 滑鼠右擊專案 [XFAzureNHub.Android],點選 [設定為起始專案] 選項
- 在 Azure 通知中樞 (azure-notification-hub-lab) 的網頁上,點選 [Test Send] 按鈕
- 切換 [Platform] 欄位值為 [Android]
- 點選下方的 [Send] 按鈕
- 當最下方的 [Result] 列表出現新的紀錄,則表示剛剛的通知推播已經傳送到遠端裝置上了
- 從模擬器上就可以看到這個遠端推播訊息通知
選擇模擬器或者實體裝置當要執行這個練習專案,並且可以接收到來自於 Azure 通知中樞的遠端推播內容,需要在目的模擬器或者實體裝置上有安裝 Google Play Service 這個軟體,否則,是無法接收到來自於遠端推播通知訊息。因此,在 Android Device Manager 對話窗中,請針對要進行除錯的模擬器,使用滑鼠右擊該裝置項目,再彈出對話窗中,選擇 [編輯] 選項當該模擬器裝置的屬性對話窗出現之後,在其裝置屬性對話窗的左下方,將會看到有個 [Google Play Store] 選項,請勾選它;若無法勾選這個選項,請將 處理器 這個下拉選單,選擇 x86 這個項目即可。
If you add splash activity for splash screen as your main launcher then push notification will not work. To get around this issue I assign splash theme to my MainActivity and change the theme to Maintheme using base.SetTheme(resid: Resource.Style.MainTheme); before base.OnCreate(savedInstanceState); call. my 2 cents.
回覆刪除