Win8 Metro应用开发:如何使用Push notification来更新你的Metro style app

Win8 Metro应用开发:如何使用Push notification来更新你的Metro style app

目录:

1.        Push notification 简介

2.        Push notification工作流程

3.        Cloud Service服务器搭建

4.        Push notification客户端的实现

5.        Push notification演示

 

 

1. Push notification简介

何为"Push notification"? 顾名思义,"Push notification"就是"推送消息"的意思。那它和传统的App内容更新机制有什么区别呢?

传统的App通过向云端发送请求的方式来获取更新消息,然后利用它们来更新自己的内容。Push notification是指当服务器端有更新时,服务器可以将消息推送至终端设备,不需要客户端发送请求来获取消息。Push notification有多种实现:iOS的消息推送机制(通过Apple Push Notification Service),Android等等。在Win8上,微软通过WNS(windows push notification service)来实现。即服务器发送消息给微软的WNS服务器,然后WNS把消息推送给App,让App完成更新。

在微软最新发布的Windows 8 Release Preview中,微软提供了Windows Push Notification Service(WNS)来支持第三方开发人员从自己的服务器发送toast, tile和badge的更新消息给metro style app。Push notification的工作原理如下图所示:

 

图1:

在图1中,包含"Windows"字样的紫色框即为运行metro app的客户端,它由两部分组成:metro style app和push notification的客户端。开发者可以将push notification客户端集成到metro style app中去,作为app的一个单独模块。在下面的例子中,笔者就使用了这种方式。

包含"Cloud Service"的绿色框代表你自己的云服务器,作用是:负责和WNS的加密验证和发送更新消息。搭建这个服务器将是我们接下来工作的重点。

而包含"WNS"字样的蓝色框代表微软的Push Notification服务器,它将把从Cloud Service接受到的更新消息推送给你的App客户端。

2. Push notification工作流程

发送一个push notification的大致流程如下:

1)      Metro app向WNS请求一个push notification的channel,这一步将通过app调用WNS的接口方法得到。

2)      WNS收到App的请求后,返回一个channel的URI。这个URI之后会被Cloud Server使用到,用来给WNS发送POST请求。

3)      App将这个URI发送给Cloud Server

4)      Cloud Server向WNS发送一个HTTP请求。这个请求是POST形式的,包含channel URI和更新的消息。(在Cloud Server和WNS之间采用OAuth2.0协议进行验证)

5)      WNS将更新消息发送给metro app,完成更新。

从上面的原理图不难看出,WNS,即Windows Push Notification的服务器,已经由微软实现并开始提供服务了。那么作为第三方开发者,我们的主要任务就是实现用来接收消息的Push Notification Client(集成到metro style app中) 和 Cloud Service服务器的搭建了。

3. Cloud Service服务器的搭建

在服务器的搭建这一环节,笔者使用了微软的IIS(Internet Information Services)和ASP.NET框架来部署这个服务器。将控制面板中的Turn Windows features on or off面板中IIS和.NET Framework选中,系统会自动进行安装。安装完成后,重启计算机,然后就可以开始server端的编程内容了。

Step 1. 新建一个网站项目

打开visual studio(笔者在win8上搭建了这个服务器,所以选择了visual studio 2012 RC),点击文件 -> 选择新建网站 -> 模板选择Visual C# -> 类型选择ASP.NET空网站 -> 将新建的网站命名为Cloud Service -> 确定。


图2

Step 2. 创建接收URI的页面AddNotificationChannel

Metro style app将从WNS请求到的URI发送给Cloud Server,在Server端由本页面对该URI进行处理和转发。

在右边"解决方案资源管理器"中 -> 选中"Cloud Service" ->右键 -> 添加 -> 添加新项 -> 在"已安装"中选择Visual C# -> Web窗体 -> 在"名称"文本框中输入AddNotificationChannel.aspx -> 确定。

 

本页面接受从app发送来的带有URI的POST请求,从这个请求中取出channelUri这个参数,把它赋给全局对象Application["channelUri"]:


using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.UI; using System.Web.UI.WebControls; public partial class aspPage_AddNotificationChannel : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { if (Request.HttpMethod != "POST") { Response.StatusCode = 405; Response.StatusDescription = "Incorrect syntax"; Response.Write("You should use this in a POST to set the channel URI"); Response.End(); } else { byte[] aByteReq = new byte[Request.ContentLength]; Request.InputStream.Read(aByteReq, 0, Request.ContentLength); //delete .upper() function invoke string aStrReq = System.Text.UTF8Encoding.UTF8.GetString(aByteReq); int i = aStrReq.IndexOf("channelUri="); if (i == 0) { aStrReq = aStrReq.Substring(i + 11); Response.Write("Successfully got channelUri: " + aStrReq); if (Application["channelUri"] != null) { Application["channelUri"] = aStrReq; } else { Application.Add("channelUri", aStrReq); } } else { Response.Write("Could not find 'channelUri=' in your posted data. This is required: " + aStrReq); } Response.End(); } } } 



Step 3. 创建发送POST请求给WNS的页面SendPushNotification

按照step2中的方法,创建SendPushNotification.aspx页面。SendPushNotification.aspx.cs文件中C#代码如下:

using System.Linq; using System.Web; using System.Net; using System.IO; using System.Runtime.Serialization; using System.Runtime.Serialization.Json; using System.Text; using System.Web.UI; using System.Web.UI.WebControls; public partial class aspPage_SendPushNotification : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { if (Application["channelUri"] != null) { Response.Write(Application["channelUri"] as string); Response.Write("<br/>"); string secret = "xxxxxxxxxxxxxxxxxxxx"; //your app secret string sid = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; //your app sid string uri = Application["channelUri"] as string; string xml = "<?xml version="1.0" encoding="utf-16"?><tile><visual lang="en-US"><binding template="TileWideText01"><text id="1">" + "Hello,Intel" + "</text><text id="2"></text><text id="3"></text><text id="4"></text><text id="5"></text></binding></visual></tile>"; string response = PostToWns(secret, sid, uri, xml, "wns/tile"); Response.Write("Result:" + response); } else { Response.Write("uri in Application is null"); } }

 

 

当载入SendPushNotification.aspx时,调用Page_Load方法。Page_Load方法调用了类中封装好的方法PostToWns,这个方法用来向WNS发送POST请求,通知WNS发送Push Notification给app。PostToWns方法有5个参数:uri, xml, secret, sid,type。

1)      uri从步骤2中全局对象Application["channelUri"]中取出;

2)      xml是一个字符串形式的xml文件,包含着要更新的信息。在这里,笔者把它设为将tile更新成"Hello,Intel"字样。第三方开发者可以选取遵循微软tile template规范的其他样式,详见:http://msdn.microsoft.com/en-us/library/windows/apps/Hh761491.aspx

3)      secret (secret key)和sid (security identifier)是app在WNS端的唯一验证码,用于Cloud Service和WNS进行验证(获取app的secret和sid的方法在之后的例子中会有说明);

4)      type是push notification的消息的类型,有四个可选的属性wns/tile, wns/toast, wns/badge,  wns/raw。关于这四种notification消息类型的的详细信息,请参考:http://msdn.microsoft.com/en-us/library/windows/apps/hh779725.aspx

 

PostToWns方法的代码如下:

// Post to WNS public string PostToWns(string secret, string sid, string uri, string xml, string type) { try { // You should cache this access token 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", type); request.Headers.Add("Authorization", String.Format("Bearer {0}", accessToken.AccessToken)); using (Stream requestStream = request.GetRequestStream()) requestStream.Write(contentInBytes, 0, contentInBytes.Length); using (HttpWebResponse webResponse = (HttpWebResponse)request.GetResponse()) return webResponse.StatusCode.ToString(); } catch (WebException webException) { string exceptionDetails = webException.Response.Headers["WWW-Authenticate"]; if (exceptionDetails.Contains("Token expired")) { GetAccessToken(secret, sid); // Implement a maximum retry policy return PostToWns(uri, xml, secret, sid, type); } else { // Log the response return "EXCEPTION: " + webException.Message; } } catch (Exception ex) { return "EXCEPTION: " + ex.Message; } }

 

在Cloud Service和WNS之间采用OAuth2.0验证协议。Cloud Service发送一个包含secret和sid在内,基于OAuth2.0规范的HTTPS请求给WNS,如果验证成功,WNS就会返回一个access token给Cloud Service。以后Cloud Service向WNS发送push notification请求都会使用到这个access token。实现这一验证过程的代码如下:

 // Authorization [DataContract] public class OAuthToken { [DataMember(Name = "access_token")] public string AccessToken { get; set; } [DataMember(Name = "token_type")] public string TokenType { get; set; } } private 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 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); } }

 

图7

Step 4. 编辑Web.config文件

打开Web.config文件,将 <machineKey compatiblityMode="Framework45">这行代码删除或注释掉,否则请求网页时会报错。下图中红框所示即为被注释掉的部分

图3

Step 5. 把网站部署到IIS服务器上

在visual studio的工具条上选择生成 -> 发布网站 -> 目标位置文本框中输入C:\inetpub\wwwroot\CloudService -> 确定。

C:\inetpub\wwwroot\CloudService是IIS服务器读取网页的默认路径,把网站部署到这个路径下,就可以通过IIS来访问这个网站了。

IIS服务器默认从C:\inetpub\wwwroot\路径下读取网站的预编译的C#文件,所以为了让IIS能识别到C#文件,必须把C:\inetpub\wwwroot\CloudService中的bin文件夹剪切出来,复制到C:\inetpub\wwwroot\路径下。

上述操作完成时,打开浏览器,在地址栏输入http://localhost/CloudService/SendPushNotification.aspx,看到如下网页,说明Cloud Server已经成功运行。

图4

4. Push notification客户端的实现

今年5月31号,微软发布Windows 8 Release Preview的同时,也发布了一系列的metro style app sample。笔者从中挑出了Push and Periodic notification client-side sample这个sample,作为push notification的客户端。

在此之前,为了简便起见,笔者对这个sample的源代码进行了小小的修改,删减了它在发送POST请求给Cloud Service中对URI的编码过程,以减少服务器端的工作量。但是不推荐不加密的方式进行数据传输,应用开发者有责任保护客户端和Cloud Server端数据传输的安全性。

打开Push and Periodic notification client-side sample中的notification.js文件,把下图中红线框出来的部分替换成:Data:  "channnelUri="+newChannel.uri

图5

在之前Cloud Service服务器搭建的章节中,笔者提到过在SendPushNotification.aspx.cs文件中PostToWns方法所需要的两个参数secret和sid,下面我们就会讨论这两个参数是如何获得的。

secret (secret key)和sid (security identifier)是App相关的,第三方开发者在Windows Dev Center上注册你的App,缴纳相应的费用,提交你的App相关信息,就可以获得你的App的secret和sid。Windows Dev Center的链接如下:http://msdn.microsoft.com/en-us/windows/apps/

如果仅仅是为了测试你App的push notification功能,而不是发布到Windows store上,那么微软提供了一种更经济快捷的方式获取你的secret和sid。

打开你的app(在这里是Push and Periodic notification client-side sample)的package.appxmanifest文件 -> 选择打包标签 -> 记录下包显示名称发布者这两栏中的信息 -> 打开Windows Live Application Management这个链接 -> 登录你的windows live message账户 -> 在页面的对应位置(红线框出的部分)输入刚才记录下来的包显示名称发布者


图6

输入完毕,点击我接受。在接下来的页面中,将会显示微软给你的App分配的secret和sid。把SendPushNotification.aspx中相应代码(红线框出来的部分)修改成上面得到的secret和sid。

图7

最后一步,也是一定不能漏掉的一步:重新把网站部署到IIS服务器上。流程和之前一样。

5. Push notification演示

Step 1.

安装push notification客户端。打开PushAndPeriodicNotificationSample.sln,按F5运行,Visual studio就自动把它装到计算机上。这里切记装完之后切回visual studio,点击停止调试,然后在开始屏幕重启app。否则visual studio会用本地的虚拟机来运行app,这样会导致app收不到push notification。

Step 2.

在开始屏幕打开app,在URL of the server一栏填入 http://localhost/CloudService/AddNotificationChannel.aspx (第三步中搭建的Cloud Service网址),点击"Reopen Channel and send to server"按钮,然后可以看到Output中"Uploaded to server. Response: Successfully got channelUri: ..."字样。如果没有把 app和服务器装到一台计算机上,可以把上面URL中的"localhost"替换成服务器的可访问的地址。

 

图8

Step 3.  选择Listening for push notifications标签,点击"Start listening for push notifications"按钮。Output输出"Now listening for push notification events"字样。

图10

Step 4.

打开你的IE浏览器,在地址栏中输入http://localhost/CloudServer/SendPushNotification.aspx,按下回车。网页显示了URI和Result:OK的字样,表示WNS已经成功接收到了这个请求。

图11

然后回到开始屏幕(start screen),tile上显示出了"Hello,Intel"的字样,push notification已经成功更新了app的tile!

图12

Nähere Informationen zur Compiler-Optimierung finden Sie in unserem Optimierungshinweis.