WNS消息推送

推送的运作流程

您的应用程序从通用Windows平台请求推送通知通道。

Windows要求WNS创建通知通道。该信道以统一资源标识符(URI)的形式返回给呼叫设备。

Windows将通知通道URI返回给您的应用。

您的应用将URI发送到您自己的云服务。然后,将URI存储在您自己的云服务上,以便在发送通知时可以访问URI。URI是您自己的应用程序和您自己的服务之间的接口; 您有责任使用安全可靠的Web标准实现此界面。

当您的云服务有要发送的更新时,它会使用通道URI通知WNS。这是通过在安全套接字层(SSL)上发出HTTP POST请求(包括通知有效负载)来完成的。此步骤需要身份验证。

WNS接收请求并将通知路由到适当的设备。

通过代码理解推送接入

第一步:使你的游戏能接收到推送消息,必须参数:应用程序机密 、程序包 SID、客户端URI

应用程序机密 、程序包 SID。需要应用提审通过后。在微软开发者平台获取
获取客户端 URI ,每个客户端URI唯一,客户端每次启动时记录一次该客户端的URI到服务器端,获取客户端URI代码:
服务器端,推送核心代码,此功能不限制语言,只需Http Post请求。这个案例使用C#。注意参数的使用。

具体代码如下

// Post to WNS
        /// 
        /// 推送接口
        /// 
        /// 应用程序机密
        /// 程序包 SID
        /// 客户端URI
        /// 推送的内容.xml格式
        /// 
        /// 
        /// 
        public static string PostToWns(string secret, string sid, string uri, string xml,
            string notificationType = "wns/toast", string contentType = "text/xml")
        {
            try
            {
                // 应该缓存此访问令牌。
                var accessToken = GetAccessToken(secret, sid);
                byte[] contentInBytes = Encoding.UTF8.GetBytes(xml);
                HttpWebRequest request = HttpWebRequest.Create(uri) as HttpWebRequest;
                request.Method = "POST";
                request.Headers.Add("X-WNS-Type", notificationType);
                request.ContentType = contentType;
                request.Headers.Add("Authorization", String.Format("Bearer {0}", accessToken.AccessToken));
                request.ContentLength = contentInBytes.Length;

                using (Stream requestStream = request.GetRequestStream())
                    requestStream.Write(contentInBytes, 0, contentInBytes.Length);

                using (HttpWebResponse webResponse = (HttpWebResponse)request.GetResponse())
                    return webResponse.StatusCode.ToString();
            }

            catch (WebException webException)
            {
                try
                {
                    if (webException.Response == null)
                        return "webException: " + webException.Message;
                    HttpStatusCode status = ((HttpWebResponse)webException.Response).StatusCode;

                    if (status == HttpStatusCode.Unauthorized)
                    {
                        //提供的访问令牌已过期。获得一个新的,然后再尝试发送通知。

                        //因为缓存的访问令牌在24小时后过期,所以你可以期望每天至少从WNS获得此响应一次。

                        GetAccessToken(secret, sid);

                        // We recommend that you implement a maximum retry policy.
                        return PostToWns(uri, xml, secret, sid, notificationType, contentType);
                    }
                    else if (status == HttpStatusCode.Gone || status == HttpStatusCode.NotFound)
                    {
                        // 通道URI不再有效。

                        // 从数据库中删除此通道,以防止向其发送通知的进一步尝试。

                        // 下次这个用户启动你的应用程序时,请求一个新的WNS频道。
                        // 你的应用程序应该检测到它的频道已经改变了,这应该会触发应用程序将新的通道URI发送到你的应用服务器。

                        return "无效的URI";
                    }
                    else if (status == HttpStatusCode.NotAcceptable)
                    {
                        // 这个频道被WNS切断了。

                        // 实现重试策略,以指数方式减少发送通知的数量,以防止再次节流。

                        // 此外,考虑导致您的通知被节流的方案。
                        // 您将通过限制发送给那些增加真正价值的通知来提供更丰富的用户体验。

                        return "WNS切断(被拒绝)";
                    }
                    else
                    {
                        // WNS以较不常见的错误作出响应。记录此错误以协助调试。

                        // 您可以在这里看到WNS响应代码的完整列表:
                        // http://msdn.microsoft.com/en-us/library/windows/apps/hh868245.aspx#wnsresponsecodes

                        string[] debugOutput = {
                                       status.ToString(),
                                       webException.Response.Headers["X-WNS-Debug-Trace"],
                                       webException.Response.Headers["X-WNS-Error-Description"],
                                       webException.Response.Headers["X-WNS-Msg-ID"],
                                       webException.Response.Headers["X-WNS-Status"]
                                   };
                        return string.Join(" | ", debugOutput);
                    }
                }
                catch (Exception e)
                {
                    return "EXCEPTION: WebException:" + e.Message;
                }
            }

            catch (Exception ex)
            {
                return "EXCEPTION: " + ex.Message;
            }
        }

        // 授权,批准
        [DataContract]
        public class OAuthToken
        {
            [DataMember(Name = "access_token")]
            public string AccessToken { get; set; }
            [DataMember(Name = "token_type")]
            public string TokenType { get; set; }
        }

        private static OAuthToken GetOAuthTokenFromJson(string jsonString)
        {
            using (var ms = new MemoryStream(Encoding.Unicode.GetBytes(jsonString)))
            {
                var ser = new DataContractJsonSerializer(typeof(OAuthToken));
                var oAuthToken = (OAuthToken)ser.ReadObject(ms);
                return oAuthToken;
            }
        }

        protected static OAuthToken GetAccessToken(string secret, string sid)
        {
            var urlEncodedSecret = HttpUtility.UrlEncode(secret);
            var urlEncodedSid = HttpUtility.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");
                response = client.UploadString("https://login.live.com/accesstoken.srf", body);
            }
            return GetOAuthTokenFromJson(response);
        }

推送的内容XML 配置,点击此处可下载工具,此工具可以对配置模板进行预览。

第二步:客户端接收到服务端推送的消息-> 用户点击此推送消息后要处理此交互。

App.xaml.cs 代码中。OnActivated 方法。用户点击推送消息后,会执行此方法。toast.Argument 。为 推送内容XML中的 launch=""。可以通过这个进行 传参数。