、推送 Tile 通知 客户端 PushTile.xaml
<phone:PhoneApplicationPage x:Class="Demo.PushNotification.PushTile" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone" xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" FontFamily="{StaticResource PhoneFontFamilyNormal}" FontSize="{StaticResource PhoneFontSizeNormal}" Foreground="{StaticResource PhoneForegroundBrush}" SupportedOrientations="Portrait" Orientation="Portrait" mc:Ignorable="d" d:DesignHeight="768" d:DesignWidth="480" shell:SystemTray.IsVisible="True"> <StackPanel Orientation="Vertical"> <Button Name="btnRegister" Content="Get Channel Uri" Click="btnRegister_Click" /> <TextBox Name="txtUrl" /> <TextBlock Name="lblMsg" TextWrapping="Wrap" /> </StackPanel> </phone:PhoneApplicationPage>
PushTile.xaml.cs
/* * 演示推送 Tile 通知 * * HttpNotificationChannel - 推送通知 channel * HttpNotificationChannel.Find(string channelName) - 查找并返回 channel,一个 app 只能有一个 channel * * ChannelUri - 推送通知的 channel URI * ChannelName - channel 的名称 * ConnectionStatus - channel 的连接状态,ChannelConnectionStatus.Connected 或 ChannelConnectionStatus.Disconnected * * ChannelUriUpdated - 获取到了 channel URI 后所触发的事件 * ErrorOccurred - 发生异常时所触发的事件 * ConnectionStatusChanged - 连接状态发生改变时所触发的事件 * ShellToastNotificationReceived - 程序运行中如果收到 Toast 是不会显示的,但是会触发此事件。 * 什么叫运行中:程序在前台显示,且调用了 HttpNotificationChannel.Find(channelName)(没有则创建一个),同时 channel 是在连接的状态 * HttpNotificationReceived - 接收到自定义信息通知后所触发的事件(仅在程序运行中才能接收到此信息) * * Open() - 打开 channel * Close() - 关闭 channel * * BindToShellToast() - 将此 channel 绑定到 Toast 通知 * BindToShellTile() - 将此 channel 绑定到 Tile 通知,只能引用本地资源 * BindToShellTile(Collection<Uri> baseUri) - 将此 channel 绑定到 Tile 通知,允许引用远程资源(当使用远程图像时,不能是https,要小于80KB,必须30秒内下载完) * baseUri - 允许引用的远程资源的域名集合(最大 256 个字符) * IsShellToastBound - 此 channel 是否绑定到了 Toast 通知 * IsShellTileBound - 此 channel 是否绑定到了 Tile 通知 */ 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.Text; using System.Diagnostics; using System.Collections.ObjectModel; namespace Demo.PushNotification { public partial class PushTile : PhoneApplicationPage { public PushTile() { InitializeComponent(); } private void btnRegister_Click(object sender, RoutedEventArgs e) { // 在当前应用程序中查找指定的 channel string channelName = "myChannel"; HttpNotificationChannel channel = HttpNotificationChannel.Find(channelName); // 允许引用的远程资源的域名集合 Collection<Uri> allowDomains = new Collection<Uri>(); allowDomains.Add(new Uri("http://www.cnblogs.com/")); allowDomains.Add(new Uri("http://images.cnblogs.com/")); if (channel == null) // 未发现则创建一个 channel { channel = new HttpNotificationChannel(channelName); channel.ChannelUriUpdated += new EventHandler<NotificationChannelUriEventArgs>(channel_ChannelUriUpdated); channel.ErrorOccurred += new EventHandler<NotificationChannelErrorEventArgs>(channel_ErrorOccurred); channel.Open(); channel.BindToShellTile(allowDomains); } else // 已存在则使用这个已存在的 channel { channel.ChannelUriUpdated += new EventHandler<NotificationChannelUriEventArgs>(channel_ChannelUriUpdated); channel.ErrorOccurred += new EventHandler<NotificationChannelErrorEventArgs>(channel_ErrorOccurred); if (channel.ConnectionStatus == ChannelConnectionStatus.Disconnected) channel.Open(); if (!channel.IsShellTileBound) channel.BindToShellTile(allowDomains); // 获取通知 uri txtUrl.Text = channel.ChannelUri.ToString(); Debug.WriteLine(channel.ChannelUri.ToString()); } } void channel_ChannelUriUpdated(object sender, NotificationChannelUriEventArgs e) { Dispatcher.BeginInvoke(() => { // 获取通知 uri txtUrl.Text = e.ChannelUri.ToString(); Debug.WriteLine(e.ChannelUri.ToString()); }); } void channel_ErrorOccurred(object sender, NotificationChannelErrorEventArgs e) { Dispatcher.BeginInvoke(() => MessageBox.Show(e.Message)); } } }
服务端 SendTileNotification.aspx
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="SendTileNotification.aspx.cs" Inherits="Web.PushNotification.SendTileNotification" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head runat="server"> <title></title> </head> <body> <form id="form1" runat="server"> <div> 通知 url: <asp:TextBox ID="txtUrl" runat="server"></asp:TextBox> </div> <div> 正面 Tile 的标题: <asp:TextBox ID="txtTitle" runat="server" Text="正面 Tile 的标题"></asp:TextBox> </div> <div> 正面 Tile 的背景图地址: <asp:TextBox ID="txtBackgroundImage" runat="server" Text="http://images.cnblogs.com/xml.gif"></asp:TextBox> </div> <div> 正面 Tile 的 Badge: <asp:TextBox ID="txtCount" runat="server" Text="10"></asp:TextBox> </div> <div> 反面 Tile 的标题: <asp:TextBox ID="txtBackTitle" runat="server" Text="反面 Tile 的标题"></asp:TextBox> </div> <div> 反面 Tile 的背景图地址: <asp:TextBox ID="txtBackBackgroundImage" runat="server" Text="http://images.cnblogs.com/mvpteam.gif"></asp:TextBox> </div> <div> 反面 Tile 的内容: <asp:TextBox ID="txtBackContent" runat="server" Text="反面 Tile 的内容"></asp:TextBox> </div> <div> 回应信息: <asp:TextBox ID="txtMsg" runat="server" TextMode="MultiLine" Rows="20" Columns="100"></asp:TextBox> </div> <div> <asp:Button ID="btnSend" runat="server" Text="发送 Tile 通知" OnClick="btnSend_Click" /> </div> </form> </body> </html>
SendTileNotification.aspx.cs
/* * 演示服务端如何推送 Tile 通知 */ using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.UI; using System.Web.UI.WebControls; using System.Text; using System.Net; using System.IO; namespace Web.PushNotification { public partial class SendTileNotification : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { } protected void btnSend_Click(object sender, EventArgs e) { try { HttpWebRequest request = (HttpWebRequest)WebRequest.Create(txtUrl.Text); request.Method = "POST"; // 构造用于推送 Tile 信息的 xml string tileMessage = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" + "<wp:Notification xmlns:wp=\"WPNotification\">" + "<wp:Tile>" + // "<wp:Tile ID=\"/SecondaryTile.xaml?param=abc\">" + 如果需要更新次要磁贴,则需要配置此 ID 为次要磁贴的导航 URI(不配置,则默认更新应用程序磁贴) "<wp:BackgroundImage>" + txtBackgroundImage.Text + "</wp:BackgroundImage>" + // 正面 Tile 的背景图地址 "<wp:Count>" + txtCount.Text + "</wp:Count>" + // 正面 Tile 的 Badge "<wp:Title>" + txtTitle.Text + "</wp:Title>" + // 正面 Tile 的标题 "<wp:BackBackgroundImage>" + txtBackBackgroundImage.Text + "</wp:BackBackgroundImage>" + // 反面 Tile 的背景图地址 "<wp:BackTitle>" + txtBackTitle.Text + "</wp:BackTitle>" + // 反面 Tile 的标题 "<wp:BackContent>" + txtBackContent.Text + "</wp:BackContent>" + // 反面 Tile 的内容 "</wp:Tile> " + "</wp:Notification>"; /* // 可以使用如下方式清除磁贴的相关信息,正面 Tile 的背景图不能清除 tileMessage = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" + "<wp:Notification xmlns:wp=\"WPNotification\">" + "<wp:Tile>" + "<wp:BackgroundImage></wp:BackgroundImage>" + "<wp:Count Action=\"Clear\">" + txtCount.Text + "</wp:Count>" + "<wp:Title Action=\"Clear\">" + txtTitle.Text + "</wp:Title>" + "<wp:BackBackgroundImage Action=\"Clear\">" + txtBackBackgroundImage.Text + "</wp:BackBackgroundImage>" + "<wp:BackTitle Action=\"Clear\">" + txtBackTitle.Text + "</wp:BackTitle>" + "<wp:BackContent Action=\"Clear\">" + txtBackContent.Text + "</wp:BackContent>" + "</wp:Tile> " + "</wp:Notification>"; */ byte[] requestMessage = Encoding.UTF8.GetBytes(tileMessage); // 推送 Tile 信息时的 Http Header 信息 request.ContentLength = requestMessage.Length; request.ContentType = "text/xml"; request.Headers.Add("X-WindowsPhone-Target", "token"); request.Headers.Add("X-NotificationClass", "1"); // 1 - 立即发送;11 - 450秒内发送;21 - 900秒内发送 using (Stream requestStream = request.GetRequestStream()) { requestStream.Write(requestMessage, 0, requestMessage.Length); } // 处理 MPNS 的回应信息 HttpWebResponse response = (HttpWebResponse)request.GetResponse(); string notificationStatus = response.Headers["X-NotificationStatus"]; string notificationChannelStatus = response.Headers["X-SubscriptionStatus"]; string deviceConnectionStatus = response.Headers["X-DeviceConnectionStatus"]; txtMsg.Text = "Http Status Code: " + response.StatusCode + Environment.NewLine + "X-NotificationStatus: " + notificationStatus + Environment.NewLine + "X-SubscriptionStatus: " + deviceConnectionStatus + Environment.NewLine + "X-DeviceConnectionStatus: " + notificationChannelStatus; // 各个状态的具体描述信息,详见如下地址 // http://msdn.microsoft.com/en-us/library/ff941100(v=vs.92) } catch (Exception ex) { txtMsg.Text = ex.ToString(); } } } }
2、推送自定义信息 服务端 PushRaw.xaml
<phone:PhoneApplicationPage x:Class="Demo.PushNotification.PushRaw" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone" xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" FontFamily="{StaticResource PhoneFontFamilyNormal}" FontSize="{StaticResource PhoneFontSizeNormal}" Foreground="{StaticResource PhoneForegroundBrush}" SupportedOrientations="Portrait" Orientation="Portrait" mc:Ignorable="d" d:DesignHeight="768" d:DesignWidth="480" shell:SystemTray.IsVisible="True"> <StackPanel Orientation="Vertical"> <Button Name="btnRegister" Content="Get Channel Uri" Click="btnRegister_Click" /> <TextBox Name="txtUrl" /> <TextBlock Name="lblMsg" TextWrapping="Wrap" /> </StackPanel> </phone:PhoneApplicationPage>
PushRaw.xaml.cs
/* * 演示推送自定义信息通知(程序运行中,才能接收到此通知) * * HttpNotificationChannel 的具体信息参见 /PushNotification/PushToast.xaml 或 /PushNotification/PushTile.xaml */ 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.Text; using System.Diagnostics; namespace Demo.PushNotification { public partial class PushRaw : PhoneApplicationPage { public PushRaw() { InitializeComponent(); } private void btnRegister_Click(object sender, RoutedEventArgs e) { // 在当前应用程序中查找指定的 channel string channelName = "myChannel"; HttpNotificationChannel channel = HttpNotificationChannel.Find(channelName); if (channel == null) // 在当前应用程序中查找指定的 channel { channel = new HttpNotificationChannel(channelName); channel.ChannelUriUpdated += new EventHandler<NotificationChannelUriEventArgs>(channel_ChannelUriUpdated); channel.ErrorOccurred += new EventHandler<NotificationChannelErrorEventArgs>(channel_ErrorOccurred); channel.HttpNotificationReceived += new EventHandler<HttpNotificationEventArgs>(channel_HttpNotificationReceived); channel.Open(); } else // 已存在则使用这个已存在的 channel { channel.ChannelUriUpdated += new EventHandler<NotificationChannelUriEventArgs>(channel_ChannelUriUpdated); channel.ErrorOccurred += new EventHandler<NotificationChannelErrorEventArgs>(channel_ErrorOccurred); channel.HttpNotificationReceived += new EventHandler<HttpNotificationEventArgs>(channel_HttpNotificationReceived); // 获取通知 uri txtUrl.Text = channel.ChannelUri.ToString(); Debug.WriteLine(channel.ChannelUri.ToString()); } } void channel_ChannelUriUpdated(object sender, NotificationChannelUriEventArgs e) { Dispatcher.BeginInvoke(() => { // 获取通知 uri txtUrl.Text = e.ChannelUri.ToString(); Debug.WriteLine(e.ChannelUri.ToString()); }); } void channel_ErrorOccurred(object sender, NotificationChannelErrorEventArgs e) { Dispatcher.BeginInvoke(() => MessageBox.Show(e.Message)); } // 接收到自定义信息通知后所触发的事件(仅在程序运行中才能接收到此信息) // 什么叫运行中:程序在前台显示,且调用了 HttpNotificationChannel.Find(channelName)(没有则创建一个),同时 channel 是在连接的状态 void channel_HttpNotificationReceived(object sender, HttpNotificationEventArgs e) { string msg; using (System.IO.StreamReader reader = new System.IO.StreamReader(e.Notification.Body)) { msg = reader.ReadToEnd(); } // 显示接收到的自定义信息 Dispatcher.BeginInvoke(() => lblMsg.Text = msg.ToString()); } } }
服务端 SendRawNotification.aspx
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="SendRawNotification.aspx.cs" Inherits="Web.PushNotification.SendRawNotification" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head runat="server"> <title></title> </head> <body> <form id="form1" runat="server"> <div> 通知 url: <asp:TextBox ID="txtUrl" runat="server"></asp:TextBox> </div> <div> 回应信息: <asp:TextBox ID="txtMsg" runat="server" TextMode="MultiLine" Rows="20" Columns="100"></asp:TextBox> </div> <div> <asp:Button ID="btnSend" runat="server" Text="发送自定义信息通知(Raw Message)" OnClick="btnSend_Click" /> </div> </form> </body> </html>
SendRawNotification.aspx.cs
/* * 演示服务端如何推送自定义信息通知 */ using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.UI; using System.Web.UI.WebControls; using System.Text; using System.Net; using System.IO; namespace Web.PushNotification { public partial class SendRawNotification : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { } protected void btnSend_Click(object sender, EventArgs e) { try { HttpWebRequest request = (HttpWebRequest)WebRequest.Create(txtUrl.Text); request.Method = "POST"; // 构造需要推送的自定义信息 string tileMessage = "i am webabcd"; byte[] requestMessage = Encoding.Default.GetBytes(tileMessage); // 也可以直接推送字节流 // byte[] requestMessage = new byte[] { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 }; // 推送自定义信息时的 Http Header 信息 request.ContentLength = requestMessage.Length; request.ContentType = "text/xml"; request.Headers.Add("X-NotificationClass", "3"); // 3 - 立即发送;13 - 450秒内发送;23 - 900秒内发送 using (Stream requestStream = request.GetRequestStream()) { requestStream.Write(requestMessage, 0, requestMessage.Length); } // 处理 MPNS 的回应信息 HttpWebResponse response = (HttpWebResponse)request.GetResponse(); string notificationStatus = response.Headers["X-NotificationStatus"]; string notificationChannelStatus = response.Headers["X-SubscriptionStatus"]; string deviceConnectionStatus = response.Headers["X-DeviceConnectionStatus"]; txtMsg.Text = "Http Status Code: " + response.StatusCode + Environment.NewLine + "X-NotificationStatus: " + notificationStatus + Environment.NewLine + "X-SubscriptionStatus: " + deviceConnectionStatus + Environment.NewLine + "X-DeviceConnectionStatus: " + notificationChannelStatus; // 各个状态的具体描述信息,详见如下地址 // http://msdn.microsoft.com/en-us/library/ff941100(v=vs.92) } catch (Exception ex) { txtMsg.Text = ex.ToString(); } } } }