Windows Phone 7 - 推送通知服務
Windows Phone 中的 Microsoft Push Notification Service 向第三方開發人員提供了一個彈性,專注,而且持續的渠道,使得開發人員可以從Web Service 向移動應用程序發送信息和更新。
過去移動應用程序需要經常主動訪問相應的WEB服務,以了解是否有任何等待處理的通知。這樣做是有效的,但會導航手機無線設備頻繁打開,從而對 電池續航時間或者用戶的流量帶來負面 影響。使用推送通知的方式取代主動調查,Web Service 能夠提醒應用程序獲取所需要的重要理更新。
當一個Web Service 有信息要發送到應用程序,它先發送一個通知到Push Notification Service ,該服務隨后將通知應用程序,應用程序的標題明顯地更新或者顯示一個Toast 通知。然后,如果需要的話,應用程序可以使用自己的的協議聯系Web service 以獲取更新。
關于推送通知服務,看了Jake Lin 的視頻他說的“好萊塢原則”己經說得很清楚了,不過我自己從現實中的淘寶購物也產生了一定的理解,下面跟大家分享一下,給出圖示:

如上圖,我們可以把推送通知理解成,一部手機就相當于我們一個用 戶,在淘寶注冊了帳號并填寫了送貨地址(URI),在購買完自己需要的物品后,通知淘寶商家發貨了,這時淘寶商家接收到我們給出的URI,就把貨品打包, 可以使用萬能打包把什么東西都放進去(Raw)或者根據我們的要求要打包成禮品的樣子(Tokens或者Toast 需要的XML格式 ),之后通知快遞公司(微軟--》不同的是,微軟是免費的幫我們快遞 ) 。而當我們收到快遞公司給予我們的通知后,如打電話說:“先生,你的貨品己經到達,請接收”,之后我們就根據打包方式進行接收啦。
大意的理解是這樣的。
Push notification 發送方式
如上一段文字出現了幾個英文單詞就是Push notification 的三種發送方式,分別為:
- Raw Notification
1.可以發送任何格式的數據
2.應用程序可以根據需要加工數據
3.應用程序相關(application-specific)通知消息
4.只有在應用程序運行時,才發送。 - Toast Notification
1.發送的數據為指定的XML 格式
2.如果應用程序正在運行,內容發送到應用程序中
3.如果應用程序沒有運行,彈出Toast 消息框顯示消息
3.1App 圖標加上兩個描述文本
3.2打斷用戶當前操作,但是是臨時的
3.3用戶可以點擊進行跟蹤 - Tokens (Tile) Notification
1.發送的數據為指定的XML格式
2.不會往應用程序進行發送
3.如果用戶把應用程序PIN TO START ,那么更新數據發送到start screen 的tile 里面
3.1包含三個屬性,背景,標題和計算器
3.2每個屬性都有固定的格式與位置
3.3可以使用其中的屬性,不一定三個屬性一起使用
Push Notification使用規范
- 當前版本的Windows Phone 只支持最多15 個第三方應用程序使用推送服務通知服務
- 應用程序必須內置詢問用戶是否使用推送通知服務的功能
- 應用程序必須內置用戶可以取消推送通知服務的功能
Demo 演示
關于Push Notification 的事件為如下:
//注冊URI
httpChannel.ChannelUriUpdated += new EventHandler
(httpChannel_ChannelUriUpdated);
//發生錯誤的事件
httpChannel.ErrorOccurred += new EventHandler
(httpChannel_ErrorOccurred);
//Raw 推送通知服務事件
httpChannel.HttpNotificationReceived += new EventHandler
(httpChannel_HttpNotificationReceived);
//toast 推送通知服務事件
httpChannel.ShellToastNotificationReceived += new EventHandler
(httpChannel_ShellToastNotificationReceived);
我們可以在需要注冊的地方使用,Windows Phone 的大致使用代碼為如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Microsoft.Phone.Controls;
///引用通知服務命名空間
using Microsoft.Phone.Notification;
using System.Diagnostics;
using System.IO;
namespace PushNotificationDemo
{
public partial class MainPage : PhoneApplicationPage
{
private HttpNotificationChannel httpChannel;
private const string channelName = "Channel";
// Constructor
public MainPage()
{
InitializeComponent();
}
private void linkButton_Click(object sender, RoutedEventArgs e)
{
httpChannel = HttpNotificationChannel.Find(channelName);
//如果存在就刪除
if (httpChannel!=null)
{
httpChannel.Close();
httpChannel.Dispose();
}
httpChannel = new HttpNotificationChannel(channelName, "NotificationServer");
//注冊URI
httpChannel.ChannelUriUpdated += new EventHandler
(httpChannel_ChannelUriUpdated);
//發生錯誤的事件
httpChannel.ErrorOccurred += new EventHandler
(httpChannel_ErrorOccurred);
//Raw 推送通知服務事件
httpChannel.HttpNotificationReceived += new EventHandler
(httpChannel_HttpNotificationReceived);
//toast 推送通知服務事件
httpChannel.ShellToastNotificationReceived += new EventHandler
(httpChannel_ShellToastNotificationReceived);
//打開連接
httpChannel.Open();
//綁定toast 推送服務
httpChannel.BindToShellToast();
//綁定Tokens (tile) 推送服務
httpChannel.BindToShellTile();
}
void httpChannel_ShellToastNotificationReceived(object sender, NotificationEventArgs e)
{
string msg = string.Empty;
foreach (var key in e.Collection.Keys)
{
msg += key + " : " + e.Collection[key] + Environment.NewLine;
}
Dispatcher.BeginInvoke(() =>
{
msgTextBlock.Text = msg;
});
}
void httpChannel_HttpNotificationReceived(object sender, HttpNotificationEventArgs e)
{
//Raw 支持任意格式數據
using (var reader=new StreamReader(e.Notification.Body))
{
string msg = reader.ReadToEnd();
Dispatcher.BeginInvoke(() =>
{
msgTextBlock.Text = msg;
});
}
}
void httpChannel_ErrorOccurred(object sender, NotificationChannelErrorEventArgs e)
{
//子線程中更新UI
Dispatcher.BeginInvoke(() =>
{
msgTextBlock.Text = e.Message;
} );
}
void httpChannel_ChannelUriUpdated(object sender, NotificationChannelUriEventArgs e)
{
Debug.WriteLine("CahnnelUri:{0}",e.ChannelUri);
Dispatcher.BeginInvoke(() =>
{
linkButton.IsEnabled = false;
});
}
}
}
之后,我們新建一個Windows Form 應用程序,做為Cloud server 。
首先,新建一個枚舉,創建三個枚舉項為如下:
public enum notificationType
{
raw,
toast,
tokens
}
然后編寫發送通知服務通用方法體:
void sendNotificationType(byte[] payLoad,notificationType type)
{
// The URI that the Push Notification Service returns to the Push Client when creating a notification channel.
HttpWebRequest sendNotificationRequest = (HttpWebRequest)WebRequest.Create(NotificationUriTextBox.Text);
// HTTP POST is the only allowed method to send the notification.
sendNotificationRequest.Method = WebRequestMethods.Http.Post;
// The optional custom header X-MessageID uniquely identifies a notification message. If it is present, the
// same value is returned in the notification response. It must be a string that contains a UUID.
sendNotificationRequest.Headers["X-MessageID"] = Guid.NewGuid().ToString();
if (type==notificationType.raw)
{
// Sets raw notification
sendNotificationRequest.ContentType = "text/xml; charset=utf-8";
sendNotificationRequest.Headers.Add("X-NotificationClass", "3");
// Possible batching interval values:
// 3: The message is delivered by the Push Notification Service immediately.
// 13: The message is delivered by the Push Notification Service within 450 seconds.
// 23: The message is delivered by the Push Notification Service within 900 seconds.
}
else if (type == notificationType.tokens)
{
// Sets toast notification
sendNotificationRequest.ContentType = "text/xml; charset=utf-8";
sendNotificationRequest.Headers.Add("X-WindowsPhone-Target", "token");
sendNotificationRequest.Headers.Add("X-NotificationClass", "1");
// Possible batching interval values:
// 1: The message is delivered by the Push Notification Service immediately.
// 11: The message is delivered by the Push Notification Service within 450 seconds.
// 21: The message is delivered by the Push Notification Service within 900 seconds.
}
else if (type==notificationType.toast)
{
// Sets toast notification
sendNotificationRequest.ContentType = "text/xml; charset=utf-8";
sendNotificationRequest.Headers.Add("X-WindowsPhone-Target", "toast");
sendNotificationRequest.Headers.Add("X-NotificationClass", "2");
// Possible batching interval values:
// 2: The message is delivered by the Push Notification Service immediately.
// 12: The message is delivered by the Push Notification Service within 450 seconds.
// 22: The message is delivered by the Push Notification Service within 900 seconds.
}
// Sets the web request content length.
sendNotificationRequest.ContentLength = payLoad.Length;
// Sets the notification payload to send.
byte[] notificationMessage = payLoad;
// Sends the notification.
using (Stream requestStream = sendNotificationRequest.GetRequestStream())
{
requestStream.Write(notificationMessage, 0, notificationMessage.Length);
}
// Gets the response.
HttpWebResponse response = (HttpWebResponse)sendNotificationRequest.GetResponse();
string notificationStatus = response.Headers["X-NotificationStatus"];
string notificationChannelStatus = response.Headers["X-SubscriptionStatus"];
string deviceConnectionStatus = response.Headers["X-DeviceConnectionStatus"];
MsgLabel.Text = String.Format("通知狀態:{0},管道狀態:{1},設備狀態:{2}",
notificationStatus, notificationChannelStatus, deviceConnectionStatus);
}
設置點擊后,請求微軟做推送服務:
private void button1_Click(object sender, EventArgs e)
{
string msg = String.Format("{0}{1}, {2}度", LocationComboBox.Text,
WeatherComboBox.Text, TemperatureTextBox.Text);
string type = NotificationTypeComboBox.Text as string;
if (type == "Raw")
{
byte[] strBytes = new UTF8Encoding().GetBytes(msg);
sendNotificationType(strBytes,notificationType.raw);
}
else if (type == "Toast")
{
string toastMessage = "
" +
"
" +
"
" +
"
天氣更新
" +
"
" + msg + "
" +
"
" +
"
";
byte[] strBytes = new UTF8Encoding().GetBytes(toastMessage);
sendNotificationType(strBytes,notificationType.toast);
}
else if (type == "Tile")
{
string tileMessage = "
" +
"
" +
"
" +
"
/Images/" + WeatherComboBox.Text + ".png
" +
"
" + TemperatureTextBox.Text + "
" +
"
" + LocationComboBox.Text + "
" +
"
" +
"
";
byte[] strBytes = new UTF8Encoding().GetBytes(tileMessage);
sendNotificationType(strBytes, notificationType.tokens);
}
}
注:本篇URI是通過打印得到。然后賦值給Windows Form 應用程序,如下圖:

例子運行效果如下圖:

上圖為Raw notification運行效果

運行時的Toast

不運行時的Taost

Tokens 運行效果
源碼下載: