Windows Phone 7 學習筆記 - 推送通知服務
大家都知道windows phone值允許一個第三方的應用程序在前臺運行,所以應用程序就不能在后臺從服務器上取數據。所以微軟提供推送通知服務給第三方應用程序取得更新通知的消息,讓用戶覺得這個程序運行在后臺。
熟悉C/S架構、B/S架構的朋友都知道,C/S架構中客戶端到服務器的消息傳輸可以是雙向的,客戶端即可以主動從服務器獲取消息,也可以被動 接受來自服務器通知。而B/S架構瀏覽器只能主動從服務器獲取消息,也就是說如果瀏覽器沒有請求,服務器是不可能傳輸數據給客戶端的。由此看來 windows phone是C/S模式,同時微軟不允許手機被動接收服務器的消息,但是這樣無法實現服務器通知。WP提供了一種代理的機制來實現服務器通知,這就是推送 通知。
過去移動應用程序需要經常主動去調查其相應的Web服務,以了解是否有任何等待處理的通知。這樣做雖然有效,但是會導致手機的無線設備頻繁打開,從而對電池續航時間帶來負面影響. 使用推送通知的方式取代主動調查,web service能夠提醒應用程序獲取所需要的重要更新。
1、推送消息的過程
推送通知是一種云服務器代理,服務器不能直接向手機客戶端發送消息,必須通過云服務器代理發送。
步驟如下:
(1)Window Phone客戶端應用程序請求與微軟推送通知服務(Microsoft Push Notification Services)建立通道連接,微軟推送通知服務(Microsoft Push Notification Services)使用通道URI響應。
(2)Window Phone客戶端應用程序向監視服務(Web Service或者Cloud Application)發送包含推送通知服務通道URI以及負載的消息。
(3)當監視服務檢測到信息更改時(如航班取消、航班延期或天氣警報),它會向微軟推送通知服務(Microsoft Push Notification Services)發送消息。
(4)微軟推送通知服務(Microsoft Push Notification Services)將消息中繼到Windows Phone設備,由Window Phone客戶端應用程序處理收到的消息。
(5)需要時WP設備往Cloud服務讀取更多的數據

當一個Web service有信息要發送到應用程序,它先發送一個通知到Push Notification Service,該服務隨后將通知路由到應用程序。根據推送通知的格式和裝載量,信息作為原始數據傳遞到應用程序,應用程序的標題明顯地更新或顯示一個Toast通知。然后如果需要的話應用程序可以使用自己的協議聯系web service以獲取更新。
Push Notification Service在推送通知發送后向你的web service發送一個回復碼.然而,Push Notification Service不能為你的推送提醒是否成功傳遞到應用程序提供端到端的確認。
另外一種圖解如下:
(1)客戶端從推送云服務(MPNS)獲取通知URI,提交給自己的第三方服務器。

(2)自己的第三方服務器的通過URI提交通知給推送云服務(MPNS),推送云服務(MPNS)推送通知到手機。

2、消息類型
(1)Raw Notification
- 可以發送任何格式的數據,格式可以任意設定;
- 應該程序可以根據需要加工數據;
- 應用程序相關(application-specific)的通知消息;
- 只有在應用程序運行時,才發送.如果當前沒有運行您的應用程序,Raw通知將被微軟推通知服務丟棄,不會傳遞到Windows Phone設備。
(2)Toast Notification
- 發送的數據為指定的xml格式;
- 如果應用程序正在運行,內容發送到應用程序中;
- 如果應用程序不在運行,彈出Tost消息框顯示消息;
a.App圖標加上兩個文本描述:標題與副標題,標題為粗體字顯示的字符串,副標題為非粗體字顯示的字符串;
b.打斷用戶當前的操作,但是是臨時的,且不破壞用戶的工作流,十秒鐘后自動消失;
c.用戶可以點擊進行跟蹤。

(3)Tile Notification
- 發送的數據為指定的XML格式;
- 不會往應用程序進行發送;
- 如果用戶把應用程序pin to start,那么更新數據發送到start screen的tile里面。
a.包含三個屬性,背景(background)、標題(title)和計算器(count);
b.每個屬性都有固定的格式與位置;
c.可以使用其中的屬性,不一定三個屬性一起使用。

例子,有點長哈:
用一個WebForm作為服務器端:

Form1.cs
private void SendButton_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);
SendRawNotification(strBytes);
}
else if (type == "Toast")
{
string toastMessage = "" +
"" +
"" +
"天氣更新 " +
"" + msg + " " +
" " +
" ";
byte[] strBytes = new UTF8Encoding().GetBytes(toastMessage);
SendToastNotification(strBytes);
}
else if (type == "Tile")
{
string tileMessage = "" +
"" +
"" +
"/Images/" + WeatherComboBox.Text + ".png " +
"" + TemperatureTextBox.Text + " " +
"" + LocationComboBox.Text + " " +
" " +
" ";
byte[] strBytes = new UTF8Encoding().GetBytes(tileMessage);
SendTileNotification(strBytes);
}
}
private void SendTileNotification(byte[] Payload)
{
// 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();
// 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.
// 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 SendToastNotification(byte[] Payload)
{
// 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();
// 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 SendRawNotification(byte[] Payload)
{
// 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();
// 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.
// 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);
}
windows phone端

MainPages.xaml.cs
private HttpNotificationChannel httpChannel;
private const string channelName = "Channel1";
private void button1_Click(object sender, RoutedEventArgs e)
{
httpChannel = HttpNotificationChannel.Find(channelName);
//Delete the Channel if exists
if (httpChannel != null)
{
httpChannel.Close();
httpChannel.Dispose();
}
//Create the channel
httpChannel = new HttpNotificationChannel(channelName, "NotificationService");
//Register to UriUpdated event - occurs when channel successfully opens
httpChannel.ChannelUriUpdated += new EventHandler(httpChannel_ChannelUriUpdated);
//general error handling for push channel
httpChannel.ErrorOccurred += new EventHandler(httpChannel_ErrorOccurred);
//Subscribed to Raw Notification
httpChannel.HttpNotificationReceived += new EventHandler(httpChannel_HttpNotificationReceived);
//Open the channel
httpChannel.Open();
//subscrive to toast notification when running app
httpChannel.ShellToastNotificationReceived += new EventHandler(httpChannel_ShellToastNotificationReceived);
//subscrive to toast notification
httpChannel.BindToShellToast();
//subscrive to tile notification
httpChannel.BindToShellTile();
}
void httpChannel_ShellToastNotificationReceived(object sender, NotificationEventArgs e)
{
string msg = "";
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)
{
using (var reader = new StreamReader(e.Notification.Body))
{
string msg = reader.ReadToEnd();
Dispatcher.BeginInvoke(() =>
{
MsgTextBlock.Text = msg;
});
}
}
void httpChannel_ErrorOccurred(object sender, NotificationChannelErrorEventArgs e)
{
Dispatcher.BeginInvoke(() =>
{
MsgTextBlock.Text = e.Message;
});
}
void httpChannel_ChannelUriUpdated(object sender, NotificationChannelUriEventArgs e)
{
Debug.WriteLine("ChannelUri: {0}", e.ChannelUri);
} 3、不使用推送通知定時更新Tile
(1)定時自動更新Tile
(2)支持Update一次或者多次
(3)只支持網絡圖片,圖片小雨80k,而且最多使用15秒鐘下載
(4)最短間隔為1小時
4、使用規范
(1)當前版本的Window Phone只支持最多15個第三方應用程序使用推送通知服務
(2)詢問用戶是否使用推送通知服務
(3)為用戶提供取消訂閱的選項
參考鏈接:How to: Send a Push Notification for Windows Phone
http://msdn.microsoft.com/en-us/library/ff402545(VS.92).aspx
How to: Receive Push Notifications in an Application for Windows Phone
http://msdn.microsoft.com/zh-cn/library/ff402556%28v=VS.92%29.aspx
推送通知服務
http://www.cnblogs.com/dnso/articles/1961814.html
Windows Phone 7編程實踐—推送通知_剖析推送通知實現架構
http://www.cnblogs.com/xuesong/archive/2011/04/08/2008987.html
WP7應用開發筆記(15) 推送通知
http://www.cnblogs.com/kiminozo/archive/2012/01/28/2330516.html
原文鏈接:http://www.cnblogs.com/zhangkai2237/archive/2012/02/19/2358331.html