Windows8 推送通知

Windows 推送通知服务 (WNS) 使第三方开发人员可从自己的云服务发送 Toast、磁贴、锁屏提醒和原始更新。这提供了一种高效而可靠地向用户提供新更新的机制。

相对于Windows Phone上的推送更为严格。先看看msdn上面怎么说

工作原理

下图显示了发送推送通知过程中涉及的完整数据流。其中包括以下步骤:

  1. 你的应用向通知客户端平台发送推送通知通道的请求。
  2. 通知客户端平台请求 WNS 创建一个通知通道。该通道以统一资源标识符 (URI) 的形式返回调用设备。
  3. 通知通道 URI 由 Windows 返回到你的应用。
  4. 你的应用将 URI 发送到你自己的云服务。此回调机制是你自己的应用与你自己的服务之间的一个接口。你需要负责以安全保密的 Web 标准实现此回调。
  5. 当你的云服务要发送一个更新时,它会使用该通道 URI 通知 WNS。此任务通过使用安全套接字层 (SSL) 发送 HTTP POST 请求(包括通知负载)来完成。此步骤要求进行身份验证。
  6. WNS 接收到请求并将该通知路由到相应的设备。

 

注册你的应用,并为你的云服务接收凭据

在使用 WNS 发送通知之前,你的应用必须先向 Windows 应用商店仪表板进行注册。这将为你的应用提供凭据,你的云服务在向 WNS 进行验证的过程中将使用该凭据。这些凭据由程序包安全标识符 (SID) 和密钥组成。若要执行此注册,请转到 Windows 开发人员中心的 Windows 应用商店应用开发页,并选择“仪表板”。

每个应用都有其各自的一组云服务凭据。这些凭据无法用于向其他任何应用发送通知。

若要详细了解如何注册你的应用,请参阅如何向 Windows 通知服务 (WNS) 进行验证

请求通知通道

当能够接收推送通知的应用运行时,它必须首先通过CreatePushNotificationChannelForApplicationAsync 请求通知通道。若要查看全面介绍和示例代码,请参阅如何请求、创建和保存通知通道。此 API 会返回一个与进行调用的应用程序及其磁贴唯一链接的通道 URI,所有通知类型均可通过此 URI 发送。

应用成功创建了通道 URI 之后,会将其与任何应该与该 URI 关联的特定于应用的元数据一起发送到它的云服务。

注意:通知通道自动于 30 天后过期。

msdn上介绍的很详细,简单的说应该是 首先你需要有一个许可(遵循 OAuth 2.0 协议,貌似这几年很流行),这个许可需要在你的开发者页面里面配置。稍后会介绍

然后你有了这个许可后还要获取应用的通信管道(熟悉的朋友应该知道 就是PushNotificationChannel)其实就是一个URL,有了这两个东西你就可以发送推送了,同样Windows8的推送和Windows Phone类似有磁帖,Toast,Raw,还多了个锁屏的

如下代码得到通信通道 url

 PushNotificationChannel ToastChannel =await PushNotificationChannelManager.CreatePushNotificationChannelForApplicationAsync();
   ToastChannel.PushNotificationReceived += ToastChannel_PushNotificationReceived;  //当有通知来的时候响应的事件 前提是程序处于运行状态

    Debug.WriteLine(ToastChannel.Uri);

得到这个url之后你要将他同步到你的服务端去 也就是消息推送端。

 在Windows Phone上只要有了这个url通道就行进行消息通信 而在Windows 8 上要更加的严格 还需要申请一个“令牌” 也就是我前面说过的 “注册你的应用,并为你的云服务接收凭据” 很简单 登入Windows8 应用商店开发页里面 随便创建个应用然后再高级功能栏目里面会有一个“推送通知和 Live Connect 服务信息”  点击进入后 按照前面说的步骤你就能够得到两个号码 一个是“程序包安全标识符(SID)” 一个是“客户端密钥” 通过这两个东西 然后再服务器通过一个post请求会得到一个最终的 “令牌” 每一次进行消息推送的时候首先通信Url 是前面在客户端得到的然后再他的 http 头里面添加这个 “令牌” 方能成功进行消息推送。

关于通过 “程序包安全标识符(SID)” 和“客户端密钥”得到最终的令牌的方法参照MSDN的写法是

 // Authorization  定义好 方便json
    [DataContract]
    public class OAuthToken
    {
        [DataMember(Name = "access_token")]
        public string AccessToken { get; set; }
        [DataMember(Name = "token_type")]
        public string TokenType { get; set; }
    }
    public class Authorization
    {
        public OAuthToken GetOAuthTokenFromJson(string jsonString)  //json解析
        {
            using (var ms = new MemoryStream(Encoding.Unicode.GetBytes(jsonString)))
            {
                var ser = new DataContractJsonSerializer(typeof(OAuthToken));
                var oAuthToken = (OAuthToken)ser.ReadObject(ms);
                return oAuthToken;
            }
        }
        public static string UrlEncode(string str)
        {
            StringBuilder sb = new StringBuilder();
            byte[] byStr = System.Text.Encoding.UTF8.GetBytes(str);
            for (int i = 0; i < byStr.Length; i++)
            {
                sb.Append(@"%" + Convert.ToString(byStr[i], 16));
            }

            return (sb.ToString());
        }
        public OAuthToken GetAccessToken(string secret, string sid)  //通过 “程序包安全标识符(SID)” 和“客户端密钥”得到最终的密钥
        {
            var urlEncodedSecret = UrlEncode(secret);
            var urlEncodedSid = UrlEncode(sid);
            var body = String.Format("grant_type=client_credentials&client_id={0}&client_secret={1}&scope=notify.windows.com",
                                     urlEncodedSid,
                                     urlEncodedSecret);

            string response;
            using (var client = new WebClient())
            {
                client.Headers.Add("Content-Type", "application/x-www-form-urlencoded"); //再Headers里面添加在 “推送通知和 Live Connect 服务信息” 里面得到的两个号码
                response = client.UploadString("https://login.live.com/accesstoken.srf", body);//走你~
            }
            return GetOAuthTokenFromJson(response);//json 反序列化
        }
    }

关于上面的头和解释 感兴趣的可以参考这里

这样就能够得到最终的令牌然后  服务器那边进行消息推送就和Windows Phone差不多也是post一些东西

 

//发送通知到Windows 8上  具体参数可以参考 http://msdn.microsoft.com/zh-cn/library/windows/apps/hh465435.aspx
        /// <summary>
        /// 发送通知到Windows8 上面
        /// Author:Beyondblog
        /// </summary>
        /// <param name="url">Windows 8 客户端上的Url</param>
        /// <param name="accessToken">授权 Authorization</param>
        /// <param name="title">标题</param>
        /// <param name="message">消息内容</param>
        /// <returns></returns>
        public static string SendToastMessage(string url, string accessToken, string title, string message)
        {
            try
            {
                HttpWebRequest myRequest = (HttpWebRequest)WebRequest.Create(url);
                myRequest.ContentType = "text/xml";
                myRequest.Headers.Add("X-WNS-Type", "wns/tile");//发送消息的类型 这里是Tile 磁铁  

                myRequest.Headers.Add("Authorization", String.Format("Bearer {0}", accessToken)); //这里面需要添加一个授权 这就是 得到的最终“令牌”
                //请求参数
                //头名称    必需/可选    描述
                //授权    必需    标准 HTTP 授权头用于对通知请求进行验证。云服务在此头中提供了其访问令牌。
                //Content-Type    必需    标准 HTTP 授权头。对于 Toast、磁贴以及锁屏提醒通知,此标头应设置为“text/xml”。对于原始通知,此标头应设置为“application/octet-stream”。
                //Content-Length    必需    表示请求负载大小的标准 HTTP 授权头。
                //X-WNS-Type    必需    定义负载中的通知类型:磁贴、Toast、锁屏提醒或原始。
                //X-WNS-Cache-Policy    可选    启用或禁用通知缓存。此标头仅应用于磁贴、锁屏提醒和原始通知。
                //X-WNS-RequestForStatus    可选    通知响应中的请求设备状态和 WNS 连接状态。
                //X-WNS-Tag    可选    用于为通知提供识别标签、用作支持通知队列的磁贴的字符串。此头仅应用于磁贴通知。
                //X-WNS-TTL    可选    指定生存时间 (TTL) 的整数值(用秒数表示)。

                // 要发送的内容  这里是发送一个 带有图片和文字的Toast通知  注意如果使用Toast需要把X-WNS-Type修改成 WNS/Toast
                //string toastMessage = "<toast launch=\"\">" +
                //                        "<visual lang=\"en-US\">" +
                //                             "<binding template=\"ToastImageAndText01\">" +
                //                                "<image id=\"1\" src=\"ms-appx:///images/1.png\" />" +
                //                                "<text id=\"1\">恭喜成功了!</text>" +
                //                            "</binding>" +
                //                        "</visual>" +
                //                       "</toast>";

                //发送一个Tile类型磁贴通知
                string toastMessage = "<tile><visual version=\"1\"><binding template=\"TileSquareImage\"><image id=\"1\" src=\"ms-appx:///images/1.png\" alt=\"Beyond\"/></binding></visual></tile>";
                byte[] buffer = Encoding.UTF8.GetBytes(toastMessage); //得到数据流

                myRequest.ContentLength = buffer.Length;
                myRequest.Method = "POST";//Post 走你~

                using (Stream stream = myRequest.GetRequestStream())
                {
                    stream.Write(buffer, 0, buffer.Length);
                }
                using (HttpWebResponse webResponse = (HttpWebResponse)myRequest.GetResponse())
                {
                    return webResponse.StatusCode.ToString(); //如果成功应该是返回 200 ok
                }
                //响应代码
                //每个 HTTP 消息都包含这些响应代码中的一个响应代码。WNS 建议开发者记录响应代码以便用于调试。当开发者向 WNS 报告问题时,要求他们提供响应代码和头信息。
                //HTTP 响应代码    描述    建议的操作
                //200 OK    WNS 已接收通知。    不需要任何信息。
                //400 错误的请求    一个或多个头指定错误或与其他头发生冲突。    记录请求的详细信息。检查你的请求并与此文档进行比较。
                //401 未授权    云服务未提供有效的验证票据。OAuth 票据可能无效。    请求有效的访问令牌,方法是对使用访问令牌请求的云服务进行验证。
                //403 已禁止    未授权云服务将通知发送至此 URI,即便这些通知经过验证。    请求中提供的访问令牌与请求信道 URI 的应用的凭据不匹配。确保应用清单中的包名称与提供给仪表板中应用的云服务凭据匹配。
                //404 未找到    信道 URI 无效或 WNS 无法识别该 URI。    记录请求的详细信息。不将以后的通知发送至此信道;发送至此地址的通知将失败。
                //405 方法不允许    方法无效(GET、DELETE、CREATE);仅允许使用 POST。    记录请求的详细信息。切换到使用 HTTP POST。
                //406 无法接受    云服务已超出其中止值。    记录请求的详细信息。降低发送通知的速率。
                //410 不存在    信道已过期。    记录请求的详细信息。请勿将以后的通知发送至此信道。让应用请求新的通道 URI。
                //413 请求实体太大    通知负载超出 5000 字节大小限制。    记录请求的详细信息。检查负载以确保该负载位于大小限制值之内。
                //500 内部服务器错误    内部故障已导致通知传递失败。    记录请求的详细信息。通过开发人员论坛报告此问题。
                //503 服务不可用    服务器当前无法使用。    记录请求的详细信息。通过开发人员论坛报告此问题。
            }
            catch (WebException webException)
            {
                string exceptionDetails = webException.Response.Headers["WWW-Authenticate"];
                if (exceptionDetails.Contains("Token expired"))
                {
                    return "";
                }
                else
                {
                    // Log the response
                    return "EXCEPTION: " + webException.Message;
                }
            }
            catch (Exception ex)
            {
                return "EXCEPTION: " + ex.Message;
            }
        }

补充一点就是如果您的应用程序处于允许状态的时候 当有推送来的时候会响应前面说的 PushNotificationReceived 事件 在这里可以进行一系列的处理 如判断类型 读写io等

如果您的应用没有运行的话默认的话如果是toast消息会弹出来 如果是锁屏的 会锁屏 徽章的一样  磁帖的会自动更新的。

 

总结

  Windows8的推送相对于Windows Phone 确实麻烦一些但是相对的安全那么一点 各有所长吧 在做推送的时候一定要声明应用程序具有访问网络的功能还有能够使用Toast

欢迎转载,转载请注明来自BeyondBlog的博客

posted @ 2013-01-22 11:02  BeyondBlog  阅读(855)  评论(2编辑  收藏  举报