Windows Phone 7 - 推送通知服务

openkk 12年前
     <p>Windows Phone 中的 Microsoft Push Notification Service 向第三方开发人员提供了一个弹性,专注,而且持续的渠道,使得开发人员可以从Web Service 向移动应用程序发送信息和更新。</p>    <p>过去移动应用程序需要经常主动访问相应的WEB服务,以了解是否有任何等待处理的通知。这样做是有效的,但会导航手机无线设备频繁打开,从而对 电池续航时间或者用户的流量带来负面 影响。使用推送通知的方式取代主动调查,Web Service 能够提醒应用程序获取所需要的重要理更新。</p>    <p>当一个Web Service 有信息要发送到应用程序,它先发送一个通知到Push Notification Service ,该服务随后将通知应用程序,应用程序的标题明显地更新或者显示一个Toast 通知。然后,如果需要的话,应用程序可以使用自己的的协议联系Web service 以获取更新。</p>    <p>关于推送通知服务,看了Jake Lin 的视频他说的“好莱坞原则”己经说得很清楚了,不过我自己从现实中的淘宝购物也产生了一定的理解,下面跟大家分享一下,给出图示:</p>    <p><img style="width:693px;height:438px;" alt="Windows Phone 7 - 推送通知服务" src="https://simg.open-open.com/show/eee612bb6ffa34ef971edb2bf72f4209.png" /></p>    <p>如上图,我们可以把推送通知理解成,一部手机就相当于我们一个用 户,在淘宝注册了帐号并填写了送货地址(URI),在购买完自己需要的物品后,通知淘宝商家发货了,这时淘宝商家接收到我们给出的URI,就把货品打包, 可以使用万能打包把什么东西都放进去(Raw)或者根据我们的要求要打包成礼品的样子(Tokens或者Toast 需要的XML格式 ),之后通知快递公司(<span style="color:#ff0000;">微</span><span style="color:#ff0000;">软</span><span style="color:red;">--》不同的是,微软是免费的帮我们快递 </span><span style="color:#000000;">) 。而当我们收到快递公司给予我们的通知后,如打电话说:“先生,你的货品己经到达,请接收”,之后我们就根据打包方式进行接收啦。</span></p>    <p><span style="color:#000000;">大意的理解是这样的。</span></p>    <h2><span style="color:#000000;">Push notification 发送方式</span></h2>    <p><span style="color:#000000;">如上一段文字出现了几个英文单词就是Push notification 的三种发送方式,分别为:</span></p>    <ul>     <li><span style="color:#000000;">Raw Notification<br /> 1.可以发送任何格式的数据<br /> 2.应用程序可以根据需要加工数据<br /> 3.应用程序相关(application-specific)通知消息<br /> 4.只有在应用程序运行时,才发送。</span></li>     <li><span style="color:#000000;">Toast Notification<br /> 1.发送的数据为指定的XML 格式<br /> 2.如果应用程序正在运行,内容发送到应用程序中<br /> 3.如果应用程序没有运行,弹出Toast 消息框显示消息<br />    3.1App 图标加上两个描述文本<br /> 3.2打断用户当前操作,但是是临时的<br /> 3.3用户可以点击进行跟踪</span></li>     <li><span style="color:#000000;">Tokens (Tile) Notification<br /> 1.发送的数据为指定的XML格式<br /> 2.不会往应用程序进行发送<br /> 3.如果用户把应用程序PIN TO START ,那么更新数据发送到start screen 的tile 里面<br /> 3.1包含三个属性,背景,标题和计算器<br /> 3.2每个属性都有固定的格式与位置<br /> 3.3可以使用其中的属性,不一定三个属性一起使用</span></li>    </ul>    <p> </p>    <h2><span style="color:#000000;">Push Notification使用规范</span></h2>    <ul>     <li>当前版本的Windows Phone 只支持最多15 个第三方应用程序使用推送服务通知服务</li>     <li>应用程序必须内置询问用户是否使用推送通知服务的功能</li>     <li>应用程序必须内置用户可以取消推送通知服务的功能</li>    </ul>    <h2>Demo 演示</h2>    <p>关于Push Notification 的事件为如下:</p>    <p></p>    <pre class="brush:c#; toolbar: true; auto-links: false;"> //注册URI             httpChannel.ChannelUriUpdated += new EventHandler                        <notificationchannelurieventargs>                              (httpChannel_ChannelUriUpdated);              //发生错误的事件             httpChannel.ErrorOccurred += new EventHandler                              <notificationchannelerroreventargs>                                    (httpChannel_ErrorOccurred);             //Raw 推送通知服务事件             httpChannel.HttpNotificationReceived += new EventHandler                                    <httpnotificationeventargs>                                          (httpChannel_HttpNotificationReceived);              //toast 推送通知服务事件             httpChannel.ShellToastNotificationReceived += new EventHandler                                          <notificationeventargs>                                                (httpChannel_ShellToastNotificationReceived);                                             </notificationeventargs>                                    </httpnotificationeventargs>                              </notificationchannelerroreventargs>                        </notificationchannelurieventargs></pre>    <p></p>    <p>我们可以在需要注册的地方使用,Windows Phone 的大致使用代码为如下:</p>    <p></p>    <pre class="brush:c#; toolbar: true; auto-links: false;">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                        <notificationchannelurieventargs>                              (httpChannel_ChannelUriUpdated);              //发生错误的事件             httpChannel.ErrorOccurred += new EventHandler                              <notificationchannelerroreventargs>                                    (httpChannel_ErrorOccurred);             //Raw 推送通知服务事件             httpChannel.HttpNotificationReceived += new EventHandler                                    <httpnotificationeventargs>                                          (httpChannel_HttpNotificationReceived);              //toast 推送通知服务事件             httpChannel.ShellToastNotificationReceived += new EventHandler                                          <notificationeventargs>                                                (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;             });                     }     } }                                             </notificationeventargs>                                    </httpnotificationeventargs>                              </notificationchannelerroreventargs>                        </notificationchannelurieventargs></pre>    <p></p>    <p>之后,我们新建一个Windows Form 应用程序,做为Cloud server 。</p>    <p>首先,新建一个枚举,创建三个枚举项为如下:</p>    <p></p>    <pre class="brush:c#; toolbar: true; auto-links: false;"> public enum notificationType          {             raw,             toast,             tokens         }</pre>    <p></p>    <p>然后编写发送通知服务通用方法体:</p>    <p></p>    <pre class="brush:c#; toolbar: true; auto-links: false;">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);          }</pre>    <p></p>    <p>设置点击后,请求微软做推送服务:</p>    <p></p>    <pre class="brush:c#; toolbar: true; auto-links: false;">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 = "                        <!--?xml version=\"1.0\" encoding=\"utf-8\"?-->" +                         "                        <!--?xml:namespace prefix = wp /-->                    <wp:notification wpnotification\??="" xmlns:wp="\">                              " +                            "                              <wp:toast>                                    " +                               "                                    <wp:text1>                                          天气更新                                    </wp:text1>" +                               "                                    <wp:text2>                                          " + msg + "                                    </wp:text2>" +                            "                              </wp:toast>" +                         "                        </wp:notification>";                 byte[] strBytes = new UTF8Encoding().GetBytes(toastMessage);                 sendNotificationType(strBytes,notificationType.toast);             }             else if (type == "Tile")             {                 string tileMessage = "                        <!--?xml version=\"1.0\" encoding=\"utf-8\"?-->" +                     "                        <wp:notification wpnotification\??="" xmlns:wp="\">                              " +                        "                              <wp:tile>                                    " +                           "                                    <wp:backgroundimage>                                          /Images/" + WeatherComboBox.Text + ".png                                    </wp:backgroundimage>" +                           "                                    <wp:count>                                          " + TemperatureTextBox.Text + "                                    </wp:count>" +                           "                                    <wp:title>                                          " + LocationComboBox.Text + "                                    </wp:title>" +                        "                              </wp:tile> " +                     "                        </wp:notification>";                 byte[] strBytes = new UTF8Encoding().GetBytes(tileMessage);                 sendNotificationType(strBytes, notificationType.tokens);             }         }</pre>    <p></p>    <p>注:本篇URI是通过打印得到。然后赋值给Windows Form 应用程序,如下图:</p>    <p><img alt="Windows Phone 7 - 推送通知服务" src="https://simg.open-open.com/show/338c278e1a51b59c10cb08a51c7015c0.png" width="575" height="185" /></p>    <p>例子运行效果如下图:</p>    <p><img alt="Windows Phone 7 - 推送通知服务" src="https://simg.open-open.com/show/ae0f2203b9b6f96bae282ec944610ece.png" width="485" height="626" /></p>    <p>上图为Raw notification运行效果</p>    <p> </p>    <p><img alt="Windows Phone 7 - 推送通知服务" src="https://simg.open-open.com/show/fb3fa88cad25bcb8e1fce5fb0b57195c.png" width="431" height="650" /></p>    <p>运行时的Toast</p>    <p><img alt="Windows Phone 7 - 推送通知服务" src="https://simg.open-open.com/show/6453939b7b43557c91c77659b31beba9.png" width="382" height="228" /></p>    <p>不运行时的Taost</p>    <p> </p>    <p><img alt="Windows Phone 7 - 推送通知服务" src="https://simg.open-open.com/show/12d25278953205a9f70da6cbb0111ce7.png" width="340" height="268" /></p>    <p>Tokens 运行效果</p>    <p> </p>    <p>源码下载:</p>    <p><a href="/misc/goto?guid=4959500055507879949" rel="nofollow" target="_blank">推送通知服务</a></p>