使用 PushSharp 來推送 Push Notification 到 Xamarin.Forms 開發的 Android 或者 iOS App 上
因此,首先就透過 Azure Notification Hub 的測試推播功能,發送出一個該 App 使用者可以接收的推播訊息,可是,該 App 還是沒有收到任何推播內容,最後,是在客戶的幫忙,將 App 取得的推播 Token,使用他寫的程式,直接向 Apple APNS 發送推播通知請求,結果,我開發的 App 是可以接收到這個推播通知,所以,可以證明 Xamarin.Forms App 對於來自遠端 Apple APNS 推播內容,是可以正常運作的。
經過這次的經驗,我覺得我這裡還是需要有個這樣的直接對於 Google / Apple 的 PNS 系統,直接送出推播通知請求,以便日後方便針對這樣的問題進行除錯。
要完成這樣的需求,首先需要安裝 PushSharp 的 NuGet 套件,這裡將會建立一個 Console App,完成底下的測試推播程式碼(在該篇文章的最後面)。
在這裡的程式碼將會由 PushSharp 所提供的範例說明程式碼,整理出可以對於 Android / iOS App 推送出 Push Notification 的程式碼,因此,想要對 iOS App 推送出一個推播內容,就可以呼叫 PushiOS 這個方法,而需要將該 App 取得的推播 Token,傳送進去,若想要對 Android App 推送出一個推播內容,就可以呼叫 PushAndroid 這個方法,當然,這裡也需要將該 App 取得的推播 Firebase 的 Token,傳送進去。
針對 iOS 裝置進行訊息推播
在 PushiOS 方法中,這個敘述
string sendMessage = File.ReadAllText("iOS.json", System.Text.Encoding.UTF8);
將會從這個專案目錄下,讀取出要發送出去的推播內容,這裡是一個 JSON 格式內容,如下所示:{
"aps": {
"alert": {
"title": "推播主題",
"body": "Notification Hub test notification"
},
"sound": "default"
}
}
透過
apnsBroker.QueueNotification(new ApnsNotification{DeviceToken = deviceid, Payload = JObject.Parse(sendMessage)});
方法呼叫,可以將指定 App 推播 Token ,也就是 deviceid 這個參數,與上述指定的推播內容,傳送到 Apple APNS ( Apple Push Notification Service ) 上,進而 iOS App 就會收到這個推播通知。
在建立可以用於 Apple APNS 推播的物件時候,會需要使用到
var config = new ApnsConfiguration(ApnsConfiguration.ApnsServerEnvironment.Sandbox, Constants.APNS_P12FILENAME, Constants.PUSH_CERT_PWD);
敘述,在這裡的第一個參數使用了 ApnsConfiguration.ApnsServerEnvironment.Sandbox ,表示使用的是開發模式下的推播,因此,需要從 Apple Developer 蘋果開發人員網頁中,點選設定的 App ID,下載出該推播憑證檔案,轉換成為 .p12 憑證格式;在這裡是將這個憑證檔案放入測試專案內,指定 輸出到目錄屬性為一律複製,因此,第二個引述將會指向這個檔案所在的路徑,而第三個引數則是要使用這個憑證的時候,需要使用到的密碼。
在這個測試專案中,對於 Android.json (Android 推播內容), iOS.json (iOS 推播內容) 與 com.vulcan.azurehub.p12 (iOS 推播憑證) 都已經放置到該專案內。
想要進行 iOS 的推播測試,需要使用實體裝置,例如,這裡使用的一台 iPhone 手機 (不像 Android 平台,可以使用模擬器來進行測試,只要該模擬器上有安裝 Google Play 軟體即可),底下為進行 iOS 裝置下的推送測試結果,這個範例程式是可以送出讓 iOS App 上收到該推播通知。
在底下,測試了當送出推播訊息之後,App 正好在前景狀態與在背景狀態情境下,所看到收到推播訊息的畫面。
針對 Android 裝置進行訊息推播
在 PushAndroid 方法中,這個敘述
string sendMessage = File.ReadAllText("Android.json", System.Text.Encoding.UTF8);
將會從這個專案目錄下,讀取出要發送出去的推播內容,這裡是一個 JSON 格式內容,如下所示:{
"data": {
"title": "推播主題",
"message": "Notification Hub test notification"
}
}
透過
gcmBroker.QueueNotification(new GcmNotification{ RegistrationIds = new List<string> { regId }, Data = JObject.Parse(sendMessage) });
方法呼叫,可以將指定 App 推播 Token ,也就是 regId 這個參數,與上述指定的推播內容,傳送到 FCM ( Firebase Cloud Messaging ) 上,進而 Google App 就會收到這個推播通知。
在建立可以用於 Apple APNS 推播的物件時候,會需要使用到
var config = new GcmConfiguration(Constants.GCM_SENDER_ID, Constants.AUTH_TOKEN, null);
敘述,第一個引數,GCM_SEND_ID 與第二個引數, AUTH_TOKEN 可以從 Firebase Console 網站中取得。
底下為進行 Android 裝置下的推送測試結果,這個範例程式是可以送出讓 Android App 上收到該推播通知。
發送 iOS / Android 推播的測試程式原始碼
class Program
{
static void Main(string[] args)
{
// 進行 iOS 裝置的推播
PushiOS("ad1942af16e2d85d40fbc7e186555eb276ce67a8112fe5fbe0b6b33a1d404a3f");
// 進行 Android 裝置的推播
//PushAndroid("eJTHqO53Tbk:APA91bGUWCleYTdY39Ws1JmbtMnJm80RRsWm8sE5zINsd5YP4dDi_lqp1MHnD38Hr-x7UpIdx0VP3TEuOgpQ7W77bE_c0k4G2FGLK73GAiHsdqEJZhyF8rBIjC7hmfBHOoqteE_cWCbC");
}
static void PushiOS(string deviceid)
{
// Configuration (NOTE: .pfx can also be used here)
var config = new ApnsConfiguration(ApnsConfiguration.ApnsServerEnvironment.Sandbox,
Constants.APNS_P12FILENAME, Constants.PUSH_CERT_PWD);
// Create a new broker
var apnsBroker = new ApnsServiceBroker(config);
// Wire up events
apnsBroker.OnNotificationFailed += (notification, aggregateEx) =>
{
aggregateEx.Handle(ex =>
{
// See what kind of exception it was to further diagnose
if (ex is ApnsNotificationException notificationException)
{
// Deal with the failed notification
var apnsNotification = notificationException.Notification;
var statusCode = notificationException.ErrorStatusCode;
Console.WriteLine($"Apple Notification Failed: ID={apnsNotification.Identifier}, Code={statusCode}");
}
else
{
// Inner exception might hold more useful information like an ApnsConnectionException
Console.WriteLine($"Apple Notification Failed for some unknown reason : {ex.InnerException}");
}
// Mark it as handled
return true;
});
};
apnsBroker.OnNotificationSucceeded += (notification) =>
{
Console.WriteLine("Apple Notification Sent!");
};
// Start the broker
apnsBroker.Start();
string sendMessage = File.ReadAllText("iOS.json", System.Text.Encoding.UTF8);
// Queue a notification to send
apnsBroker.QueueNotification(new ApnsNotification
{
DeviceToken = deviceid,
Payload = JObject.Parse(sendMessage)
});
// Stop the broker, wait for it to finish
// This isn't done after every message, but after you're
// done with the broker
apnsBroker.Stop();
}
static void PushAndroid(string regId)
{
// Configuration GCM (use this section for GCM)
var config = new GcmConfiguration(Constants.GCM_SENDER_ID, Constants.AUTH_TOKEN, null);
var provider = "GCM";
// Configuration FCM (use this section for FCM)
// var config = new GcmConfiguration("APIKEY");
// config.GcmUrl = "https://fcm.googleapis.com/fcm/send";
// var provider = "FCM";
// Create a new broker
var gcmBroker = new GcmServiceBroker(config);
// Wire up events
gcmBroker.OnNotificationFailed += (notification, aggregateEx) =>
{
aggregateEx.Handle(ex =>
{
// See what kind of exception it was to further diagnose
if (ex is GcmNotificationException notificationException)
{
// Deal with the failed notification
var gcmNotification = notificationException.Notification;
var description = notificationException.Description;
Console.WriteLine($"{provider} Notification Failed: ID={gcmNotification.MessageId}, Desc={description}");
}
else if (ex is GcmMulticastResultException multicastException)
{
foreach (var succeededNotification in multicastException.Succeeded)
{
Console.WriteLine($"{provider} Notification Succeeded: ID={succeededNotification.MessageId}");
}
foreach (var failedKvp in multicastException.Failed)
{
var n = failedKvp.Key;
var e = failedKvp.Value;
Console.WriteLine($"{provider} Notification Failed: ID={n.MessageId}, Desc={e.Message}");
}
}
else if (ex is DeviceSubscriptionExpiredException expiredException)
{
var oldId = expiredException.OldSubscriptionId;
var newId = expiredException.NewSubscriptionId;
Console.WriteLine($"Device RegistrationId Expired: {oldId}");
if (!string.IsNullOrWhiteSpace(newId))
{
// If this value isn't null, our subscription changed and we should update our database
Console.WriteLine($"Device RegistrationId Changed To: {newId}");
}
}
else if (ex is RetryAfterException retryException)
{
// If you get rate limited, you should stop sending messages until after the RetryAfterUtc date
Console.WriteLine($"{provider} Rate Limited, don't send more until after {retryException.RetryAfterUtc}");
}
else
{
Console.WriteLine("{provider} Notification Failed for some unknown reason");
}
// Mark it as handled
return true;
});
};
gcmBroker.OnNotificationSucceeded += (notification) =>
{
Console.WriteLine("{provider} Notification Sent!");
};
// Start the broker
gcmBroker.Start();
string sendMessage = File.ReadAllText("Android.json", System.Text.Encoding.UTF8);
// Queue a notification to send
gcmBroker.QueueNotification(new GcmNotification
{
RegistrationIds = new List<string> { regId },
Data = JObject.Parse(sendMessage)
});
// Stop the broker, wait for it to finish
// This isn't done after every message, but after you're
// done with the broker
gcmBroker.Stop();
}
}
了解更多關於 [Xamarin.Android] 的使用方式
了解更多關於 [Xamarin.iOS] 的使用方式
了解更多關於 [Xamarin.Forms] 的使用方式
了解更多關於 [Hello, Android:快速入門] 的使用方式
了解更多關於 [Hello, iOS – 快速入門] 的使用方式
了解更多關於 [Xamarin.Forms 快速入門] 的使用方式
最近在幫客戶處理 Xamarin.Forms 推播 Push Notification 需求的時候,產生了一個問題,那就是原先的軟體都可以正常收到來自 Apple APNS 的推播訊息,突然間,客戶向我反映,現在正在開發的測試版本 App,突然間收不到來自後台伺服器推送出來的推播訊息,詢問我是不是我這裡程式做了甚麼修正,導致這樣的問題。由於整個系統規劃架構是,當 App 第一次啟動的時候,從來自遠端 PNS 取得了該裝置的 Token,會於使用者登入系統的時候,將此 Token 傳送到遠端 Web API 服務,接著,後端的 Web API 服務,則會將此 Token 再向 Azure Notification Hub 進行註冊;而當有狀況需要推送到 App 的時候,後端 API 服務需要呼叫 Azure Notification Hub 的 SDK,請求 Azure Notification Hub 幫忙向 Apple APNS 推送出這個訊息的推播內容。