最近想给应用添加推送消息,主要是toast消息,所以就打算去了解一下wp消息推送机制以及实现方法,过程中,查了许多资料,也遇到过一些问题,做完后,自己就做个小笔记,总结一下,好记性不如烂笔头嘛,以后可以回头看看,也方便多了,废话不多说!
wp消息推送机制
用一幅图说明,因为官方是英文的,自己在上面添加了一些中文的解析上去,方便大家去理解!
这幅图的核心内容是,当你的应用请求手机Uri(注意:这里uri相当于一个ip或者一个物理地址,是唯一性的一个标识),手机的客户端服务会与微软推送中心联系,然后返回一个uri给客户端推送服务,然后客户端服务再把这个uri给你的应用,你的应用再把这个uri发回来给你的服务器,然后你的服务器再把这个uri和需要发送的消息发送给微软推送中心,最后微软推送中心再根据这个uri,把消息推送到指定的手机!
toast消息推送(wp端)
这个我不想多解释,直接上推送代码,下面的代码主要是查看在应用程序的早期实例中是否已设置 Toast 通知通道。如果找到通知通道,则通知通道连接到通知事件。如果未找到通知通道,则创建通知通道,然后将其连接到通知事件
// 构造函数 public MainPage() { HttpNotificationChannel myChannel = null; // 推送信道的名字,随便取一个就行了 string ChannelName = "ToastChannel"; InitializeComponent(); // Find静态方法可以根据名字查找信道 myChannel = HttpNotificationChannel.Find(ChannelName); // 因为系统有时候会删除通道,所以要判断是否存在,如果找不到,就要创建一个了 if (myChannel == null) { myChannel = new HttpNotificationChannel(ChannelName); // 注册事件 myChannel.ChannelUriUpdated += new EventHandler<NotificationChannelUriEventArgs>(myChannel_ChannelUriUpdated); myChannel.ErrorOccurred += new EventHandler<NotificationChannelErrorEventArgs>(myChannel_ErrorOccurred); myChannel.ShellToastNotificationReceived += new EventHandler<NotificationEventArgs>(myChannel_ShellToastNotificationReceived); // 打开信道 myChannel.Open(); // 绑定Toast通知,这样在程序不在前台时才会显示 // 屏幕上方的通知提示条 myChannel.BindToShellToast(); } else { // 如果存在,还要注册一次事件,因为在程序被扔到后台后可能会删除事件绑定 myChannel.ChannelUriUpdated+=new EventHandler<NotificationChannelUriEventArgs>(myChannel_ChannelUriUpdated); myChannel.ErrorOccurred+=new EventHandler<NotificationChannelErrorEventArgs>(myChannel_ErrorOccurred); myChannel.ShellToastNotificationReceived+=new EventHandler<NotificationEventArgs>(myChannel_ShellToastNotificationReceived); // 在“输出”窗输出URL,因为我们只是测试,这样一来方便一点 System.Diagnostics.Debug.WriteLine("通道URI为:{0}", myChannel.ChannelUri.ToString()); } } void myChannel_ShellToastNotificationReceived(object sender, NotificationEventArgs e) { //这里主要是当用户正在使用你的应用,而你刚好推送消息过来,执行此方法 string msg = ""; foreach (string key in e.Collection.Keys) { msg += key + " : " + e.Collection[key] + "\r\n"; } Dispatcher.BeginInvoke(() => { this.txtInfo.Text = msg; }); } void myChannel_ErrorOccurred(object sender, NotificationChannelErrorEventArgs e) { Dispatcher.BeginInvoke(() => MessageBox.Show(e.Message)); //错误产生的时候,执行这里面内容,实际情况,可以根据 自己需要处理 } void myChannel_ChannelUriUpdated(object sender, NotificationChannelUriEventArgs e) { // 当URL发生改变后,还要输出一次 // 保证我们得到的是最新版本的URI Dispatcher.BeginInvoke(() => { System.Diagnostics.Debug.WriteLine("通道URI:{0}", e.ChannelUri.ToString()); }); }
toast消息推送(server端)
这里我创建一个 ASP.NET 网页,该网页使用在设备上创建推送通道时返回的 URI 来发送 Toast 通知,当然你可以使用任何能发送网络消息的应用来推送,如winform jsp php等等
具体推送消息代码如下:
private void SendMsg() { //txtUrl.Tex该参数是手机的uri,要推送消息,首先要确定你要推送用户手机的uri HttpWebRequest myRequest = (HttpWebRequest)WebRequest.Create(txtUrl.Text); myRequest.ContentType = "text/xml"; myRequest.Headers.Add("X-WindowsPhone-Target", "toast"); /* * X-NotificationClass 处理间隔 * 2 - 立即发送 * 12 - 450秒内发送 * 22 - 900秒内发送 */ myRequest.Headers.Add("X-NotificationClass", "2"); // 要发送的内容 txtValue1.Text:标题,txtValue2.Text:推送内容,txtParam.Text:当用户点击消息的时候,导航的页面,如mainpage.xaml string toastMessage = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" + "<wp:Notification xmlns:wp=\"WPNotification\">" + "<wp:Toast>" + "<wp:Text1>" + txtValue1.Text + "</wp:Text1>" + "<wp:Text2>" + txtValue2.Text + "</wp:Text2>" + "<wp:Param>" + txtParam.Text + "</wp:Param>" + "</wp:Toast>" + "</wp:Notification>"; byte[] buffer = Encoding.UTF8.GetBytes(toastMessage);//注意此处官方是Encoding.default.GetBytes(toastMessage),我在使用的过程中,老是报错,下面会说原因 myRequest.ContentLength = buffer.Length; myRequest.Method = "POST"; using (Stream stream = myRequest.GetRequestStream()) { stream.Write(buffer, 0, buffer.Length); } // 发送消息和获取回应 HttpWebResponse response = (HttpWebResponse)myRequest.GetResponse(); string notificationStatus = response.Headers["X-NotificationStatus"]; string notificationChannelStatus = response.Headers["X-SubscriptionStatus"]; string deviceConnectionStatus = response.Headers["X-DeviceConnectionStatus"]; //判断是否成功推送到微软推送服务中心 // TextBoxResponse.Text = notificationStatus + " | " + deviceConnectionStatus + " | " + notificationChannelStatus; if (notificationStatus == "Received" && deviceConnectionStatus == "Connected" && notificationChannelStatus == "Active") { success++; } }
总结和注意
(1) 其中<wp:Param>" + txtParam.Text + "</wp:Param>,当param内容为空时,可以省略不写这一节点。同时,在xml中一些字符是要进行转换的:
<Text1> 和 <Text2> 都采用字符串格式。
<Param> 值允许以下格式:
- /page1.xaml – 定义应用程序启动时导航到的应用程序中的页面。该页面必须以“/”开头。
- /page1.xaml?value1=1234 &value2=9876 – 定义应用程序启动时导航到的页面,以及信息的名称/值对。该页面必须以“/”开头。
- ?value1=1234 &value2=9876 – 包含传递给应用程序默认开始页面的信息名称/值对。该页面必须以“?”开头。
字符 |
XML 编码 |
---|---|
< |
< |
> |
> |
& |
& |
‘ |
' |
“ |
" |
(2) 当服务端发送的toast通知中有xml格式错误或者非法内容时,微软推送服务会关闭此通道,并提示出错。我在运行时老是报错(“The XML payload contains invalid or improperly formatted XML or the notification type specified in the header does not match the payload type used. The channel has been closed. Check your XML payload for errors and reopen the channel to obtain a new URI.”)。
经过查资料,我把里面的Encoding.default.GetBytes(toastMessage)改为Encoding.UTF8.GetBytes(toastMessage),这样就把不报错了,此处可能是官方示例代码有些问题。
(3) 我们Server端想统计推送的成败情况的话,会比较困难。因为从微软推送服务中返回的相应代码中,只是简单的反映了推送通知到达代理服务器的情况,而非通知到达客户端时的结果。比如微软的代理服务器返回了响应码200,我们Server端只是知道了信息已经成功到达了它那里,并且符合转发到客户端程序的条件;至于客户端最终是否真的收到了通知,无法从这里获知。当然,当客户端程序接收到了通知后,可以向Server端汇报,但这并不准确,因为有些信息可能因为程序不在前台运行同时又被用户忽略了,此处我直接以三个信息头X-NotificationStatus X-SubscriptionStatus X-DeviceConnectionStatus来判断是否成功发到微软的推送中心来判断是否发送成功,至于有其他更准确方案,知道的话,请告诉我!
wp推送消息笔记