Universal App - 整合 Windows Notification Service (WNS) for Client

Universal App - 整合 Windows Notification Service (WNS) for Client

在<Universal App - 整合 Windows Notification Service (WNS) for Server>介紹如何實作 Server 串接 WNS 發送 push notification。

複習一下 WNS 的運作概念圖:

IC618819_thumb

藉由上圖說明該篇將針對 App 端如何取得 Channel URI 並向 Cloud Service 註冊與處理收到的 push notification。

以下內容參考<How to request, create, and save a notification channel (XAML)>加以說明。

 

[注意]

1. 建議在每一次啟動 App 時取得新的 channel 並且向 cloud service 註冊或更新

2. channel 在 30 天後會自動過期

3. 需要修改 Package.appxmanifest 的 <Identify /> 標籤的值,來自 Dev Center 所註冊該 App 的「應用程式設定」,如下圖:

     image

     或是藉由 Visual Studio 的 Associate App with Store 功能將 Project 與 Dev Center 上註冊的 App 綁定在一起。

4. 如果要搭配 cloud service 測試要改用手機進行測試才能拿到正確使用的 channel uri

 

A. 向 Notification Client Platform 請求取得 Channel URI

     如果 App 需要接收 push notification 需要在 App 加入宣告提醒用戶,這是上架 App 的審核條件之一。

     Package.manifest 設定 App 支持 Toast notification、Internet (Client) capability。藉由下列的程式碼取得 Channel URI。

public static async Task<Boolean> RequestPushNotificationChannel()
{
    try
    {
        var channel = await PushNotificationChannelManager.CreatePushNotificationChannelForApplicationAsync();
        // check new channel is the same the old channel
        String oldUrl = AppSettingManager.GetValue<String>("wns_channel", String.Empty);
        if (channel.Uri != oldUrl)
        {
            // need regist or update the chaneel on the cloud service
            await SendToCloudService(channel.Uri);
            AppSettingManager.SaveValue("wns_channel", channel.Uri);
        }
        return true;
    }
    catch (Exception ex)
    {
        // Could not create a channel. 
        throw;
    }
}

     每一次進入 App 的 Launched 事件時,建議重新取得 Channel URI 並且識別已存在的 Channel URI 是否過期或與新的不一致,

     如果有不一致或是過期均要向 Cloud Service 重新註冊。註冊成功後可以將它儲存在 Application Setting 裡。

 

    [補充說明]

    1. CreatePushNotificationChannelForApplicationAsync  請求取得 Channel 不會永遠回傳不一樣的 Channel 需要加以比對

    2. 一個 App 可以同時擁有多個有效的 Channel 以確保在其他 Channel 過期時仍保有一個 Channel 可以使用

    3. 可以建立一個 Background task 去定期檢查如果接近或超過 30 天的有效期限前自動請求取得新的 Channel 並加以註冊

    4. CreatePushNotificationChannelForApplicationAsync 請求可能發生錯誤,建議加入每隔 10 秒的 retry 機制,如果 retry 仍失敗,

         則依賴 Launched 事件時重新註冊。

    5. 如果用戶想要關掉 push notification 的使用,可使用 PushNotificationChannel.Close 取消 channel 的使用,

         並且使用 TileUpdater.Clear 將既有的 Tile/Badge 資訊加以清除。

         (建議也通知 Cloud Service 取消該帳號的 channel 記錄,以減少發送給已取消的 channel)

 

B. 取得 Channel URI 向 Cloud Service 註冊

    當 App 開啟時針對 toast 與 raw notification 會直接由 App 處理。

private static async Task SendToCloudService(String channel)
{
    // Create the web request.
    HttpWebRequest webRequest = (HttpWebRequest)HttpWebRequest.Create(CloudServiceUrl);
    webRequest.Method = "POST";
    webRequest.ContentType = "application/x-www-form-urlencoded";
    byte[] channelUriInBytes = System.Text.Encoding.UTF8.GetBytes("ChannelUri=" + channel);

 
    // Write the channel URI to the request stream.
    Stream requestStream = await webRequest.GetRequestStreamAsync();
    requestStream.Write(channelUriInBytes, 0, channelUriInBytes.Length);

 
    try
    {
        // Get the response from the server.
        WebResponse response = await webRequest.GetResponseAsync();
        StreamReader requestReader = new StreamReader(response.GetResponseStream());
        String webResponse = requestReader.ReadToEnd();
    }

 
    catch (Exception ex)
    {
        // Could not send channel URI to server.
    }
}

 

C. 接收並處理 push notification 的內容

     取得並註冊 channel 至 Cloud Service 後,接下來要處理收到的 push notification。首先了解一下二個重要的元素:

PushNotificationChannelManager

     負責建立一個物件來接收來自向 Windows Push Notifications Service 取得的 push notification channels。

重要的方法如下:

Method Description
CreatePushNotificationChannelForApplicationAsync() Creates an object, bound to the calling app, through which you retrieve a push notification channel from Windows Push Notification Services (WNS).
CreatePushNotificationChannelForApplicationAsync(String) Creates an object, bound to a specified app, through which you retrieve a push notification channel from Windows Push Notification Services (WNS).
String 參數為:applicationId
The Package Relative Application ID (PRAID) of the app to bind to the push notification channel.
CreatePushNotificationChannelForSecondaryTileAsync(tileId) Creates an object, bound to a secondary tile, through which you retrieve a push notification channel from Windows Push Notification Services (WNS).
tileId 參數:The ID of the secondary tile to bind to the push notification channel.
使用時需要指定要更新處理的 Secondary Tile,僅支援 Tile 與 Badge

PushNotificationChannel

     藉由 PushNotificationChannelManager 類別的 CreatePushNotificationChannelForApplicationAsync 所建立的 Channel 物件。

Channel Uniform Resource Identifier (URI) 代表一個單位可接由第三方來針對該 channel 進行 push notification 的發送。

重要的屬性/方法/事件如下:

類型 名稱 說明
Event PushNotificationReceived Fires when a push notification has arrived on this channel.

在 App 開啟並取得 Channel 物件後要記得註冊該事件才能在 App 裡收到 push notification 加以處理。不然開啟 App 收到 push notification 預設是不處理的。

PushNotificationReceivedEventArgs
Property Access type Description
BadgeNotification Read-only Gets the content of a badge update to perform in response to this push notification.
Cancel Read/write Gets or sets whether Windows should perform its default handling of the notification.
NotificationType Read-only Gets the type of push notification that has been received from the app server.
RawNotification Read-only Gets the app-defined content contained in this push notification, the contents of which are used to perform a background task on the app.
TileNotification Read-only Gets the content of a tile update to perform in response to this push notification.
ToastNotification Read-only Gets the content of a toast to display in response to this push notification.
Method Close Explicitly invalidates this channel. Any notifications pushed to this channel after this method is called are not delivered.
Property

ExpirationTime

Read-only. Gets the time at which the channel expires. Notifications sent to this channel after this time are rejected.
  Uri Read-only. Gets the Uniform Resource Identifier (URI) to which an app server sends a push notification intended for an application or secondary tile bound to this channel. This Uniform Resource Identifier (URI) is transmitted to and stored by the third-party app server.

由於 CreatePushNotificationChannelForApplicationAsync 實作了 IAsyncOperation interface 所以可以在 operation completes  successfully 後,

取得回傳的 PushNotificationChannel 物件。

 

以下是將註冊拿到的 PushNotificationChannel 加上 PushNotificationReceived 的處理:

private async void OnGetChannelURI(object sender, RoutedEventArgs e)
{
    var result = await PushNotificationHelper.RequestPushNotificationChannel();
    if (result)
    {
        txtChannel.Text = PushNotificationHelper.CurrentChannel.Uri;
        PushNotificationHelper.CurrentChannel.PushNotificationReceived += CurrentChannel_PushNotificationReceived;
    }
    else
    {
        txtChannel.Text = "Get channel uri failed";
    }
}

 
void CurrentChannel_PushNotificationReceived(PushNotificationChannel sender, PushNotificationReceivedEventArgs args)
{
    string typeString = String.Empty;
    string notificationContent = String.Empty;
    // 針對收到的 push notification 類型進行處理。
    switch (args.NotificationType)
    {
        case PushNotificationType.Toast:
            notificationContent = args.ToastNotification.Content.GetXml();
            typeString = "Toast";
            // ToastNotificationManager.CreateToastNotifier().Show(args.ToastNotification);
            // Setting the cancel property prevents the notification from being delivered. 
            // It's especially important to do this for toasts:
            // if your application is already on the screen, 
            // there's no need to display a toast from push notifications.
            args.Cancel = true;
            break;
        case PushNotificationType.Badge:
            typeString = "Badge";
            notificationContent = args.BadgeNotification.Content.GetXml();
            break;
        case PushNotificationType.Tile:
            notificationContent = args.TileNotification.Content.GetXml();
            typeString = "Tile";
            break;
        case PushNotificationType.Raw:
            // 注意 raw 拿到的是實際由 cloud service 送出的內容
            notificationContent = args.RawNotification.Content;
            typeString = "Raw";
            break;
    }

 
    string text = "Received a " + typeString + " notification, containing: " + notificationContent;
    var ignored = this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
    {
        txtContent.Text = text;
    });
}

在 App 裡如果收到 ToastNotification 建議可以加上 .Cancle = true,避免往下傳給系統又再一次跳出 Toast 的訊息

記得在離開 App 或是有註冊 PushNotificationReceived 的 Page 取消對 PushNotificationReceived 的註冊,以下是用 OnNavigatedFrom 為例:

protected override void OnNavigatedFrom(NavigationEventArgs e)
{
    base.OnNavigatedFrom(e);
    if (PushNotificationHelper.CurrentChannel != null)
    {
        // 要記得取消註冊讓訊息可以被系統處理
         // 減少不必要的資源
        PushNotificationHelper.CurrentChannel.PushNotificationReceived -= CurrentChannel_PushNotificationReceived;
    }
}

 

如果本身沒有打算實作 Cloud Service 來測試發送的話,也可以藉由內鍵 Emulator 的 Additional Tools 測試 push notification。

如下圖範例:

image

 

[範例程式]

======

以上是分享在 Client 端怎麼請 notification client platform 向 WNS 取得 channel,以及處理各種接收到各種不同的 notifications 希望對大家有所幫助。

謝謝。

 

References:

How to request, create, and save a notification channel (XAML)

Windows Push Notification Services (WNS) overview

Quickstart: Intercepting push notifications for running apps (重要)

Quickstart: Creating and registering a raw notification background task (重要)

Guidelines and checklist for push notifications

Delivering scheduled, periodic, and push notifications (XAML)

Push and periodic notifications sample

Windows Push Notification Services (WNS) overview (Windows Runtime apps)

Quickstart: Sending a push notification (XAML)

Quickstart: Creating a default tile using the Microsoft Visual Studio manifest editor (Windows Runtime apps)

 

Dotblogs Tags: ,