推送通知服务【WP7学习札记之十三】
为什么使用推送通知服务
Windows Phone执行模型决定只有一个第三方的应用程序可以在前台运行,应用程序不能再后台运行,不断的往Cloud拉数据。微软提供推送通知服务(Push Notification)给第三方应用程序取得更新通知的消息。由于服务器能够主动的发起通信,因此可以有效的降低手机电池的消耗。
Windows Phone 的推送通知的完整权威描述见MSDN文档描述见:http://msdn.microsoft.com/zh-cn/library/ff402537(v=vs.92).aspx。
本节内容
上图显示了手机上运行的客户端应用程序如何从推送客户端服务 (1) 请求推送通知 URI。然后,推送客户端服务与 Microsoft 推送通知服务 (MPNS) 协商并向客户端应用程序(2 和 3)返回一个通知 URI。之后,客户端应用程序将此 URI 发送给云服务 (4)。当 Web 服务有要发送到客户端应用程序的信息时,该服务使用此 URI 向 Microsoft 推送通知服务 (5) 发送推送通知,Microsoft 推送通知服务又将此推送通知发送给在 Windows Phone 设备 (6) 上运行的应用程序。
根据推送通知的格式以及连接到通知的负载,信息作为原始数据发送到应用程序、应用程序的磁贴在视觉上得到更新或显示 Toast 通知。发送推送通知之后,Microsoft 推送通知服务向您的 Web 服务发送一个响应代码,指示此通知已接收并且下次有机会会发送到设备。但是,Microsoft 推送通知服务不提供将推送通知从 Web 服务发送到设备的端到端通信。
Jake Lin的描述是:
使用规范:
windows phone 7目前只允许15个第三方应用程序使用推送通知服务;
询问用户是否使用推送通知服务;
为用户提供取消订阅的选项。
s消息类型:
Raw Notification:
可以发送任何格式的数据;
应用程序可以根据需要加工数据;
应用程序相关的通知消息;
★只有在应用程序运行时才发送。
Toast Notification:
发送的数据为指定的xml格式;
★如果应用程序正在运行,内容发送到应用程序中;
★如果应用程序不在运行,弹出toast消息框显示消息:
App图标加上两个文本描述;
打断用户当前操作,但是是临时的;
用户可以点击进行跟踪。
Tile Notification:
发送的数据为指定的xml格式;
★不会往应用程序进行发送;
★如果用户把应用程序Pin to Start,那么更新数据会发送到start screen 的tile里面:
包含三个属性,背景、标题和计数器;
每个属性都有固定的格式和位置;
可以使用其中的属性,不一定三个属性一起用。
示例程序示例(Raw):手机客户端代码:
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;
namespace 推送通知服务
{
public partial class MainPage : PhoneApplicationPage
{
// Constructor
public MainPage()
{
InitializeComponent();
//Holds the push channel that is created or found.
HttpNotificationChannel pushchannel;
//The name of our push channel.
string channelName = "RawSampleChannel";
//Try to find the push channel
pushchannel = HttpNotificationChannel.Find(channelName);
// If the channel was not found, then create a new connection to the push service.
if (pushchannel == null)
{
pushchannel = new HttpNotificationChannel(channelName);
// Register for all the events before attempting to open the channel.
pushchannel.ChannelUriUpdated += new EventHandler<NotificationChannelUriEventArgs>(pushchannel_ChannelUriUpdated);
pushchannel.ErrorOccurred += new EventHandler<NotificationChannelErrorEventArgs>(pushchannel_ErrorOccurred);
pushchannel.HttpNotificationReceived += new EventHandler<HttpNotificationEventArgs>(pushchannel_HttpNotificationReceived);
pushchannel.Open();
}
else
{
// The channel was already open, so just register for all the events.
pushchannel.ChannelUriUpdated+=new EventHandler<NotificationChannelUriEventArgs>(pushchannel_ChannelUriUpdated);
pushchannel.ErrorOccurred+=new EventHandler<NotificationChannelErrorEventArgs>(pushchannel_ErrorOccurred);
pushchannel.HttpNotificationReceived+=new EventHandler<HttpNotificationEventArgs>(pushchannel_HttpNotificationReceived);
// Display the URI for testing purposes. Normally, the URI would be passed back to your web service at this point.
System.Diagnostics.Debug.WriteLine(pushchannel.ChannelUri.ToString());
MessageBox.Show(String.Format("Channel Uri is {0}",
pushchannel.ChannelUri.ToString()));
}
}
void pushchannel_HttpNotificationReceived(object sender, HttpNotificationEventArgs e)
{
string message;
using (System.IO.StreamReader reader = new System.IO.StreamReader(e.Notification.Body))
{
message = reader.ReadToEnd();
}
Dispatcher.BeginInvoke(() =>
MessageBox.Show(String.Format("Received Notification {0}:\n{1}",
DateTime.Now.ToShortTimeString(), message))
);
}
void pushchannel_ErrorOccurred(object sender, NotificationChannelErrorEventArgs e)
{
// Error handling logic for your particular application would be here.
Dispatcher.BeginInvoke(() =>
MessageBox.Show(String.Format("A push notification {0} error occurred. {1} ({2}) {3}",
e.ErrorType, e.Message, e.ErrorCode, e.ErrorAdditionalData))
);
}
void pushchannel_ChannelUriUpdated(object sender, NotificationChannelUriEventArgs e)
{
Dispatcher.BeginInvoke(() =>
{
// Display the new URI for testing purposes. Normally, the URI would be passed back to your web service at this point.
System.Diagnostics.Debug.WriteLine(e.ChannelUri.ToString());
MessageBox.Show(String.Format("Channel Uri is {0}",
e.ChannelUri.ToString()));
});
}
}
}
云端:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Net;
using System.Text;
using System.IO;
namespace SendRaw
{
public partial class SendRaw : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
protected void ButtonSendRaw_Click(object sender, EventArgs e)
{
try
{
// Get the URI that the Microsoft Push Notification Service returns to the push client when creating a notification channel.
// Normally, a web service would listen for URIs coming from the web client and maintain a list of URIs to send
// notifications out to.
string subscriptionUri = TextBoxUri.Text.ToString();
HttpWebRequest sendNotificationRequest = (HttpWebRequest)WebRequest.Create(subscriptionUri);
// Create an HTTPWebRequest that posts the raw notification to the Microsoft Push Notification Service.
// HTTP POST is the only method allowed to send the notification.
sendNotificationRequest.Method = "POST";
// Create the raw message.
string rawMessage = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
"<root>" +
"<Value1>" + TextBoxValue1.Text.ToString() + "<Value1>" +
"<Value2>" + TextBoxValue2.Text.ToString() + "<Value2>" +
"</root>";
// Set the notification payload to send.
byte[] notificationMessage = Encoding.Default.GetBytes(rawMessage);
// Set the web request content length.
sendNotificationRequest.ContentLength = notificationMessage.Length;
sendNotificationRequest.ContentType = "text/xml";
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.
using (Stream requestStream = sendNotificationRequest.GetRequestStream())
{
requestStream.Write(notificationMessage, 0, notificationMessage.Length);
}
// Send the notification and get 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"];
// Display the response from the Microsoft Push Notification Service.
// Normally, error handling code would be here. In the real world, because data connections are not always available,
// notifications may need to be throttled back if the device cannot be reached.
TextBoxResponse.Text = notificationStatus + " | " + deviceConnectionStatus + " | " + notificationChannelStatus;
}
catch (Exception ex)
{
TextBoxResponse.Text = "Exception caught sending update: " + ex.ToString();
}
}
}
}
运行效果截图:
Channel Uri:
手机端:
云端: