作者:马宁
示例代码下载:
Windows Phone上支持Push Notification,用户可以使用微软的推送服务器(MPNS)向安装了自己软件的Windows Phone设备上推送三种不同的通知消息。
Push Notification的机制大致是这样的:
1. 运行在Windows Phone设备端的应用注册一个Push Notification Channel,获得一个唯一标识这个Channel的URI;
2. 将URI传回到开发者自己的服务器;
3. 当开发者需要发送Push Notification消息时,将规定格式的数据发送到之前获得的URI上;
4. 微软的推送服务器(MPNS)获得开发者发送的请求后,会通知到对应的Windows Phone设备上。
整个过程如下图所示:
在整个过程中,对于开发者来说,有一个难点很难克服——必须有自己的服务器,否则无法接收从Windows Phone应用中发送过来的URI。这个问题对于那些没有自己服务器的Windows Phone开发者来说,他们只能放弃在自己的应用中加入Push Notification的功能。
OpenXLive为了解决这个问题,为开发者提供了Push Notification Hosting服务(OpenXLive Push Notification Hosting Server,简称OPNHS),允许开发者将OpenXLive的服务器作为自己的Push Notification服务器。只要开发者调用OpenXLive SDK中的API,就可以让OpenXLive的服务器来保存URI,当开发者需要发送Push Notification消息时,只需要登录OpenXLive开发者后台就可以发送了。
Silverlight应用中添加Push Notification
接下来,我们以Silverlight for Windows Phone应用为例,看看如何使用OpenXLive Push Notification Hosting功能,向 Silverlight应用发送三种不同的Push Notification。
1. 添加OpenXLive功能
首先,我们要为创建好的Silverlight应用添加OpenXLive引用。如果没有安装OpenXLive SDK的话,请在下面的链接中下载SDK。请注意,只有在0.9.8及其以上版本中,才包含OpenXLive Push Notification Hosting功能。
http://developer.openxlive.net/sdk/download/
如果您已经安装了OpenXLive SDK,可以在安装路径(默认为C:\Program Files (x86)\Fulcrum Mobile Networks, Inc\OpenXLiveSDK\Bin\Silverlight)下找到OpenXLive.dll和OpenXLive.Silverlight.dll。
找到这两个DLL后,我们需要将其拷贝到Silverlight应用的目录下,否则会产生一个访问异常。
在Visual Studio的Solution Explorer中,选择Add References,添加OpenXLive.dll和OpenXLive.Silverlight.dll的引用。
然后,打开App.xaml.cs文件,添加下面的代码:
using OpenXLive; using OpenXLive.Features; private void Application_Launching(object sender, LaunchingEventArgs e) { if (XLiveGameManager.CurrentSession == null) { GameSession session = XLiveGameManager.CreateSession("enMQ3rEC5jsw8XygdFHuGpfk"); session.CreateSessionCompleted += new AsyncEventHandler(session_CreateSessionCompleted); session.Open(); } } void session_CreateSessionCompleted(object sender, AsyncEventArgs e) { AsyncProcessResult result = e.Result; if (!result.ReturnValue) { // TODO: Error Handler } } private void Application_Activated(object sender, ActivatedEventArgs e) { XLiveGameManager.Activated(); } private void Application_Deactivated(object sender, DeactivatedEventArgs e) { XLiveGameManager.Deactivated(); } private void Application_Closing(object sender, ClosingEventArgs e) { if (XLiveGameManager.CurrentSession != null) { XLiveGameManager.CurrentSession.Close(); } }
代码具体的解释可以参考《在Windows Phone应用中添加OpenXLive数据分析功能》,链接如下:http://www.cnblogs.com/aawolf/archive/2011/10/03/2198607.html
当OpenXLive的引用和功能调用添加完成后,我们就可以添加Push Notification代码了。
2. 发送Tile Notification
为了保证足够的灵活性,所以,开发者仍然调用Push Notification的API来注册Push Notification的Channel。我们首先来演示,如何创建并发送Tile Notification。关于Tile Notification的详细信息,可以参考MSDN上的文章:
http://msdn.microsoft.com/en-us/library/hh202970(VS.92).aspx
在Visual Studio中打开MainPage.xaml,添加三个ToggleSwitch控件,分别对应三种不同的Notification类型,选中控件添加Checked事件处理函数,然后进入代码编辑界面,添加如下的代码来创建Push Notification的Channel。
首先在MainPage.xaml.cs文件的顶部,添加引用:
using Microsoft.Phone.Notification; using OpenXLive;
接下来,在与Tile Notification对应的ToggleSwitch控件Checked事件中,添加创建Push Notification Channel的代码:
// The name of our push channel. string channelName = "OpenXLivePushNotificationHostingChannel"; private void toggleSwitchTile_Checked(object sender, RoutedEventArgs e) { // Try to find the push channel. HttpNotificationChannel pushChannel = HttpNotificationChannel.Find(channelName); // If the channel was not found, then create a new connection to the push service. if (pushChannel == null) { pushChannel = new HttpNotificationChannel(channelName); // Register for all the events before attempting to open the channel. pushChannel.ChannelUriUpdated += new EventHandler<NotificationChannelUriEventArgs>(PushChannel_ChannelUriUpdated); pushChannel.ErrorOccurred += new EventHandler<NotificationChannelErrorEventArgs>(PushChannel_ErrorOccurred); pushChannel.Open(); // Bind this new channel for Tile events. if (pushChannel != null && !pushChannel.IsShellTileBound) { var allowedDomains = new Collection<Uri> { new Uri("http://picture.openxlive.com/") }; pushChannel.BindToShellTile(allowedDomains); } } else { // The channel was already open, so just register for all the events. pushChannel.ChannelUriUpdated += new EventHandler<NotificationChannelUriEventArgs>(PushChannel_ChannelUriUpdated); pushChannel.ErrorOccurred += new EventHandler<NotificationChannelErrorEventArgs>(PushChannel_ErrorOccurred); } RegisterNotificationUri(pushChannel.ChannelUri); }
创建Push Notification Channel的代码与MSDN上的一致,三种不同的Notification在创建时其实是一样的,只是在创建之后进行了不同的操作,所以才会分成不同的Notification。比如,Tile Notification就需要在创建后,调用BindToShellTile方法,将其绑定到Tile上;在关闭Notification Channel前,还要记得调用UnbindToShellTile方法,解除绑定。
特别要强调的是,如果您的背景图片是放在OpenXLive服务器上的话,需要在调用BindToShellTile方法之前,首先将OpenXLive的图片服务器(picture.openxlive.com)添加到允许访问的域名列表中。当然,如果您的图片来自其他域名的服务器,您也要将对应的域名加入这个列表中。
接下来,我们来看将Notification Channel的Uri注册到OpenXLive服务器上的代码:
private void RegisterNotificationUri(Uri uri) { // Send Channel Uri to OpenXLive Hosting Server if (OpenXLive.XLiveGameManager.CurrentSession != null && OpenXLive.XLiveGameManager.CurrentSession.IsValid && uri != null) { OpenXLive.XLiveGameManager.CurrentSession.RegistNotificationUriCompleted += new OpenXLive.Features.AsyncEventHandler(CurrentSession_RegistNotificationUriCompleted); OpenXLive.XLiveGameManager.CurrentSession.RegisterNotificationUri(uri); } } void CurrentSession_RegistNotificationUriCompleted(object sender, OpenXLive.AsyncEventArgs e) { OpenXLive.Features.AsyncProcessResult result = e.Result; if (result.ReturnValue) { Debug.WriteLine("Channel Uri has been send to OpenXLive Hosting Server"); } else { Debug.WriteLine(result.ErrorMessage); } }
调用OpenXLive Push Notification Hosting的方法非常简单,首先判断一下XLiveGameManager对象中CurrentSession属性中的GameSession对象是否有效,如果有效则首先添加RegistNotificationUriCompleted事件处理方法,然后调用GameSession的RegisterNotificationUri方法,将Push Notification Channel的Uri传递到OpenXLive Notification Hosting服务器(OPNHS)上即可。OPNHS没有提供解除绑定的方法,因为Notification Channel在解除绑定后会自动失效,OPNHS会将失效的Uri自动抛弃,所以客户端引用就没有必要解除绑定了。
还有两个需要提示的最佳实践:因为Push Notification Channel的注册需要GameSession有效,所以,在XLiveGameManager的CreateSession方法的CreateSessionCompleted事件处理函数中创建Push Notification Channel,并将其注册到OPNHS中,是最为安全的。
另外,由于HttpNotificationChannel创建Notification Channel本身也是一个异步调用,在某些情况下,如果我们在创建Notification Channel之后,马上注册到OPNHS上,Uri可能为空。所以,我们必须在HttpNotificationChannel的ChannelUriUpdated事件处理函数中增加注册代码,防止注册处理被漏掉。
好了,接下来看一下HttpNotificationChannel的ChannelUriUpdated事件处理函数的代码:
void PushChannel_ChannelUriUpdated(object sender, NotificationChannelUriEventArgs e) { if (e.ChannelUri != null) { RegisterNotificationUri(e.ChannelUri); } Dispatcher.BeginInvoke(() => { // Display the new URI for testing purposes. Normally, the URI would be passed back to your web service at this point. System.Diagnostics.Debug.WriteLine(e.ChannelUri.ToString()); }); }
虽然有一些Push Notification Channel创建的代码没有完整展示,这部分代码不影响OPNHS的使用,您可以在示例代码中看到完整的代码。
好了,到这里,我们就完成了客户端的代码工作,接下来就可以看一下运行的效果了。在客户端代码运行前,您必须确认已经在OpenXLive的开发者网站上创建了OpenXLive的游戏/应用,并且已经取得了有效的API Secrecy Key,具体的做法您可以参考《在开发者网站上创建OpenXLive游戏》:
http://wiki.openxlive.net/Tutorial-4-Create-OpenXLive-Game-in-website.ashx
客户端程序开始运行之后,我们会看到下面的界面,并打开Tile Notification对应的ToggleSwitch控件:
然后点击模拟器上的Windows键,回到主界面,并切换到应用程序列表界面,将我们的示例程序pin到主界面上来显示:
好了,我们现在已经打开了Tile Notification的Channel,并且将其注册到了OPNHS上,而且把应用程序的Tile pin到主界面上。客户端的工作就完成了。
作为开发者,想向客户端发送Tile Notification的时候,只需要登录到OpenXLive的开发者网站,在开发者后台的控制面板中选择对应的游戏/应用,然后在右侧的功能选项中,选择“推送通知”(Push Notification),在二级菜单中,选择“Tile推送通知”,我们会看到如下界面:
Tile Notification一共能够传递六个参数,分为两组。前景部分,是标题(Title)、数字(Count)和前景图片(BackgroundImage),需要指出的是,数字的现实范围是0-99之间的整形数字;而背景组,是背景标题(BackTitle)、内容(BackContent)和背景图片(BackBackgroundImage)。Tile显示的布局与基本样式无法修改,如下图所示:
背景图片即可以是应用程序内部的资源图片,也可以是来自网络的图片。所以,OpenXLive的服务器也提供了图片上传的功能,开发者可以将Tile图片上传至OpenXLive服务器,然后再推送至Windows Phone手机。
如果使用应用程序内部的资源图片,在BackgroundImage栏输入图片在xap包中的相对路径即可。将图片添加到程序中作为背景图片,可以按以下步骤操作:
1. 右键项目,单击 添加,然后再单击 添加现有项
2. 选中要添加的图片,单击 打开
3. 鼠标右键单击添加的图片,然后选择 属性
4. 找到 属性 对话框中的 生成操作 属性,并设置为 内容
5. 将 复制到输出目录 设置为 如果较新则复制
发送Tile Notification 时,要使用该图片只需在BackgroundImage栏输入图片名称(包括后缀名)即可。如果图片不在根目录下则输入 Folder/Image.jpg。
目前OPNHS的功能相对简单,每次发送Push Notification时,开发者只能登录OpenXLive服务器,手工发送,还没有实现定时发送的功能。复杂功能会随着开发者的要求,在后续的版本中逐步实现。
好了,当您填写好Tile Notification的内容后,点击“发送”按钮。在Windows Phone的主界面上,您很快就可以看到推送过来的Tile内容了。
3. 发送Toast Notification
第二个推送通知类型是Toast Notification,当程序运行在后台时,Toast Notification会在屏幕的最上端显示一个提示条,和来短信、发现无线网络的系统提示一致。Toast Notification一般用在需要唤醒应用程序的时候,比如应用程序现在有新的内容等。
需要指出的是,每个应用程序最多支持打开一个Notification Channel,在示例程序中,我们并没有做几个Notification Channel的互斥,打开一个新的Channel前,应该关闭另外的Channel,否则会引发异常。
我们先来看一下表示Toast的ToggleSwitch控件的Checked和Unchecked事件处理函数:
private void toggleSwitchToast_Checked(object sender, RoutedEventArgs e) { // Try to find the push channel. HttpNotificationChannel pushChannel = HttpNotificationChannel.Find(ToastChannelName); // If the channel was not found, then create a new connection to the push service. if (pushChannel == null) { pushChannel = new HttpNotificationChannel(ToastChannelName); // Register for all the events before attempting to open the channel. pushChannel.ChannelUriUpdated += new EventHandler<NotificationChannelUriEventArgs>(PushChannel_ChannelUriUpdated); pushChannel.ErrorOccurred += new EventHandler<NotificationChannelErrorEventArgs>(PushChannel_ErrorOccurred); // Register for this notification only if you need to receive the notifications while your application is running. pushChannel.ShellToastNotificationReceived += new EventHandler<NotificationEventArgs>(PushChannel_ShellToastNotificationReceived); pushChannel.Open(); // Bind this new channel for Tile events. pushChannel.BindToShellToast(); } else { // The channel was already open, so just register for all the events. pushChannel.ChannelUriUpdated += new EventHandler<NotificationChannelUriEventArgs>(PushChannel_ChannelUriUpdated); pushChannel.ErrorOccurred += new EventHandler<NotificationChannelErrorEventArgs>(PushChannel_ErrorOccurred); // Register for this notification only if you need to receive the notifications while your application is running. pushChannel.ShellToastNotificationReceived += new EventHandler<NotificationEventArgs>(PushChannel_ShellToastNotificationReceived); } // Send Channel Uri to OpenXLive Hosting Server RegisterNotificationUri(pushChannel.ChannelUri); } private void toggleSwitchToast_Unchecked(object sender, RoutedEventArgs e) { // Try to find the push channel. HttpNotificationChannel pushChannel = HttpNotificationChannel.Find(ToastChannelName); if (pushChannel != null) { pushChannel.UnbindToShellToast(); // Remove push notification channel pushChannel.Close(); } }
大部分代码与之前的Tile Notification相同,只是增加了Notification Channel的ShellToastNotificationReceived事件处理函数,并且调用BindToShellToast方法,将Notification Channel绑定到Toast上。
接下来,我们要处理两种情况:第一种,接收到Toast Notification时,应用程序正在运行;第二种,接收到Toast Notification时,应用程序在后台。当程序运行在后台时,Toast提示条会显示,当用户点击时,会跳转到Toast Notification中包括的命令行所指定的应用程序页面中。如果应用在前台,我们就要处理Notification Channel的ShellToastNotificationReceived事件处理函数,代码如下:
void PushChannel_ShellToastNotificationReceived(object sender, NotificationEventArgs e) { StringBuilder message = new StringBuilder(); string relativeUri = string.Empty; message.AppendFormat("Received Toast {0}:\n", DateTime.Now.ToShortTimeString()); // Parse out the information that was part of the message. foreach (string key in e.Collection.Keys) { message.AppendFormat("{0}: {1}\n", key, e.Collection[key]); if (string.Compare( key, "wp:Param", System.Globalization.CultureInfo.InvariantCulture, System.Globalization.CompareOptions.IgnoreCase) == 0) { relativeUri = e.Collection[key]; } } // Display a dialog of all the fields in the toast. Dispatcher.BeginInvoke(() => MessageBox.Show(message.ToString())); }
为了处理第二种情况,我们要创建一个新的页面,命名为Page2.xaml。我们要在Page2的OnNavigatedTo方法中增加一段代码,以显示导航来源是哪里:
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e) { base.OnNavigatedTo(e); textBlockFrom.Text = "Navigated here from " + this.NavigationContext.QueryString["NavigatedFrom"]; }
好了,到这里,我们客户端的代码写完了。我们运行代码示例,并且打开Toast Notification的开关,然后将应用切换到后台。
然后,我们打开OpenXLive的开发者后台,切换至“推送消息”界面的“Toast推送消息”中。界面截图如下:
Toast Notification有三个参数:Text1,是Toast消息的标题;Text2,是副标题;Param,是需要传递给应用程序的命令行参数,所以必须保证这个参数能够被应用程序解析,否则会引起应用程序崩溃,如果不填,则默认打开应用程序的主界面。
好了,接下来看运行效果如何了。当应用程序在后台的情况下,首先会显示Toast提示条,点击提示条后,会进入命令行指定的应用程序页面。
在应用程序运行在前台的情况下,我们会用一个MessageBox来显示收到的消息:
好了,我们完成了第二个Toast Notification的全部工作。
4. 发送Raw Notification
Raw Notification是三种推送通知中用的比较少的一种,因为Raw Notification只有在应用程序在前台的情况下才有用。在这种情况下,一般的开发者会倾向于使用自己更加能够掌控的Pull方式,而不是由服务器端发起的Push方式。无所谓了,反正对于Raw Notification,我们是要介绍的。
首先还是客户端的代码,已经是轻车熟路了:
private void toggleSwitchRaw_Checked(object sender, RoutedEventArgs e) { // Try to find the push channel. HttpNotificationChannel pushChannel = HttpNotificationChannel.Find(RawChannelName); // If the channel was not found, then create a new connection to the push service. if (pushChannel == null) { pushChannel = new HttpNotificationChannel(RawChannelName); // Register for all the events before attempting to open the channel. pushChannel.ChannelUriUpdated += new EventHandler<NotificationChannelUriEventArgs>(PushChannel_ChannelUriUpdated); pushChannel.ErrorOccurred += new EventHandler<NotificationChannelErrorEventArgs>(PushChannel_ErrorOccurred); pushChannel.HttpNotificationReceived += new EventHandler<HttpNotificationEventArgs>(PushChannel_HttpNotificationReceived); pushChannel.Open(); } else { // The channel was already open, so just register for all the events. pushChannel.ChannelUriUpdated += new EventHandler<NotificationChannelUriEventArgs>(PushChannel_ChannelUriUpdated); pushChannel.ErrorOccurred += new EventHandler<NotificationChannelErrorEventArgs>(PushChannel_ErrorOccurred); pushChannel.HttpNotificationReceived += new EventHandler<HttpNotificationEventArgs>(PushChannel_HttpNotificationReceived); // Display the URI for testing purposes. Normally, the URI would be passed back to your web service at this point. System.Diagnostics.Debug.WriteLine(pushChannel.ChannelUri.ToString()); MessageBox.Show(String.Format("Channel Uri is {0}", pushChannel.ChannelUri.ToString())); } // Send Channel Uri to OpenXLive Hosting Server RegisterNotificationUri(pushChannel.ChannelUri); } void PushChannel_HttpNotificationReceived(object sender, HttpNotificationEventArgs e) { string message; using (System.IO.StreamReader reader = new System.IO.StreamReader(e.Notification.Body)) { message = reader.ReadToEnd(); } Dispatcher.BeginInvoke(() => MessageBox.Show(String.Format("Received Notification {0}:\n{1}", DateTime.Now.ToShortTimeString(), message)) ); } private void toggleSwitchRaw_Unchecked(object sender, RoutedEventArgs e) { // Try to find the push channel. HttpNotificationChannel pushChannel = HttpNotificationChannel.Find(RawChannelName); // If the channel was not found, then create a new connection to the push service. if (pushChannel != null) { pushChannel.Close(); } }
唯一需要多说的是,增加了Notification Channel的HttpNotificationReceived事件处理方法,我们从e.Notification.Body中获取到发送的Raw消息,然后使用StreamReader将其读取为文本,还可以继续进行进一步的处理。
运行客户端程序,打开Raw Notification的选项,将应用程序保持在运行状态。登录OpenXLive开发者后台,“推送消息”界面的“Raw推送消息”中,将想要发送的文本粘贴到文本框中,点击“发送”按钮。
手机客户端的运行效果如下:
好了,到这里,我们就将OpenXLive Push Notification Hosting Server(OPNHS)的功能,如何发送三种Push Notification,以及在Silverlight for Windows Phone应用中如何创建Notification Channel、注册到OPNHS中和接收推送通知等。
XNA游戏中添加Push Notification
接下来,我们会介绍,如何在XNA游戏中实现与Silverlight应用中相同的功能。其实,XNA中绝大部分功能与Silverlight类似,只是XNA是一个事件驱动的应用程序框架,而Silverlight是事件驱动,所以在选择创建Notification Channel的时间点上略有差异。
1. 添加OpenXLive功能
首先,我们还是首先添加OpenXLive的引用,在OpenXLive SDK的安装路径(默认为C:\Program Files (x86)\Fulcrum Mobile Networks, Inc\OpenXLiveSDK\Bin\XNA)下找到OpenXLive.dll和OpenXLive.Form.dll。这两个DLL是在XNA程序中使用的。
XNA游戏中,我们必须首先在Solution Explorer中打开Properties目录下的WMAppManifest.xml文件,找到下面这句代码,Publisher的名字不能为空,否则无法正确获得Push Notification的消息:
<App xmlns="" ProductID="{aee39b6f-5faf-41e6-a992-5055fdf3a13e}" Title="PushDemoXNA" RuntimeType="XNA" Version="1.0.0.0" Genre="Apps.Normal" Author="" Description="" Publisher="OpenXLive">
我们打开Game1.cs文件,首先,在文件顶部添加引用:
using OpenXLive; using OpenXLive.Features; using OpenXLive.Forms; using Microsoft.Phone.Notification;
然后,声明一个XLiveFormManger变量,该对象主要是用来控制XNA中所有的UI Framework,如果不需要显示OpenXLive的XNA UI,该变量也可以不加:
XLiveFormManager manager;
接下来,定位到Initialize方法,接下来添加下面的代码:
protected override void Initialize() { // TODO: Add your initialization logic here if (XLiveGameManager.CurrentSession == null) { GameSession session = XLiveGameManager.CreateSession("enMQ3rEC5jsw8XygdFHuGpfk"); session.CreateSessionCompleted += new AsyncEventHandler(session_CreateSessionCompleted); manager = new XLiveFormManager(this, session); session.Open(); Components.Add(manager); } base.Initialize(); }
在OpenXLive SDK 0.9.8及以上版本中,我们修改了创建XNA UI框架的方法,您可以先创建GameSession对象,然后再将GameSession对象传递给XLiveFormManger,这样可以保证Silverlight和XNA调用方式的基本一致。如果您的游戏中只适用了OpenXLive的逻辑代码,而没有使用UI代码的话,也可以不必创建XLiveFormManger对象。但是,调用GameSession的Open方法是必须的。然后,将XLiveFormManger对象作为Game Compoent添加到系统中,也能够保证OpenXLive的XNA UI系统能够被系统释放掉。
好了,短短几句话,我们就可以将OpenXLive加入到我们的XNA游戏中了。接下来,我们就要在GameSession创建成功的事件处理函数中添加Push Notification的代码了。
void session_CreateSessionCompleted(object sender, AsyncEventArgs e) { AsyncProcessResult result = e.Result; if (result.ReturnValue) { // TODO: Error Handler CreateNotificationChannel(); } }
2. 发送Tile Notification
由于XNA的UI控制代码写起来比较费事,所以,我们就在这里简化了调用流程,每次运行程序,只能创建一种Push Notification,代码如下:
private void CreateNotificationChannel() { CreateTileNotification(); //CreateToastNotification(); //CreateRawNotification(); }
而创建Notification Channel的代码与Silverlight版本是一模一样的:
private void CreateTileNotification() { if (XLiveGameManager.CurrentSession != null && XLiveGameManager.CurrentSession.IsValid) { // Try to find the push channel. HttpNotificationChannel pushChannel = HttpNotificationChannel.Find(TileChannelName); // If the channel was not found, then create a new connection to the push service. if (pushChannel == null) { pushChannel = new HttpNotificationChannel(TileChannelName); // Register for all the events before attempting to open the channel. pushChannel.ChannelUriUpdated += new EventHandler<NotificationChannelUriEventArgs>(PushChannel_ChannelUriUpdated); pushChannel.ErrorOccurred += new EventHandler<NotificationChannelErrorEventArgs>(PushChannel_ErrorOccurred); pushChannel.Open(); // Bind this new channel for Tile events. if (pushChannel != null && !pushChannel.IsShellTileBound) { var allowedDomains = new Collection<Uri> { new Uri("http://picture.openxlive.com/") }; pushChannel.BindToShellTile(allowedDomains); } } else { // The channel was already open, so just register for all the events. pushChannel.ChannelUriUpdated += new EventHandler<NotificationChannelUriEventArgs>(PushChannel_ChannelUriUpdated); pushChannel.ErrorOccurred += new EventHandler<NotificationChannelErrorEventArgs>(PushChannel_ErrorOccurred); } RegisterNotificationUri(pushChannel.ChannelUri); } } void PushChannel_ChannelUriUpdated(object sender, NotificationChannelUriEventArgs e) { if (e.ChannelUri != null) { RegisterNotificationUri(e.ChannelUri); } // Display the new URI for testing purposes. Normally, the URI would be passed back to your web service at this point. System.Diagnostics.Debug.WriteLine(e.ChannelUri.ToString()); } void PushChannel_ErrorOccurred(object sender, NotificationChannelErrorEventArgs e) { // Error handling logic for your particular application would be here. MessageBox.Show(String.Format("A push notification {0} error occurred. {1} ({2}) {3}", e.ErrorType, e.Message, e.ErrorCode, e.ErrorAdditionalData)); }
需要提示的是,这里的MessageBox是OpenXLive封装的MessageBox,用法和Silverlight中系统提供的一致。
最后,也是最核心的代码是注册Uri的部分代码:
private void RegisterNotificationUri(Uri uri) { // Send Channel Uri to OpenXLive Hosting Server if (OpenXLive.XLiveGameManager.CurrentSession != null && OpenXLive.XLiveGameManager.CurrentSession.IsValid && uri != null) { OpenXLive.XLiveGameManager.CurrentSession.RegistNotificationUriCompleted += new OpenXLive.Features.AsyncEventHandler(CurrentSession_RegistNotificationUriCompleted); OpenXLive.XLiveGameManager.CurrentSession.RegisterNotificationUri(uri); } } void CurrentSession_RegistNotificationUriCompleted(object sender, OpenXLive.AsyncEventArgs e) { OpenXLive.Features.AsyncProcessResult result = e.Result; if (result.ReturnValue) { Debug.WriteLine("Channel Uri has been send to OpenXLive Hosting Server"); } else { Debug.WriteLine(result.ErrorMessage); } }
好了,我们运行程序,然后将程序切换到后台,将游戏图标pin到主界面上,最后发送Tile Notification的效果如下:
3. 发送Toast Notification
发送Toast Notification的代码如下:
private void CreateToastNotification() { // Try to find the push channel. HttpNotificationChannel pushChannel = HttpNotificationChannel.Find(ToastChannelName); // If the channel was not found, then create a new connection to the push service. if (pushChannel == null) { pushChannel = new HttpNotificationChannel(ToastChannelName); // Register for all the events before attempting to open the channel. pushChannel.ChannelUriUpdated += new EventHandler<NotificationChannelUriEventArgs>(PushChannel_ChannelUriUpdated); pushChannel.ErrorOccurred += new EventHandler<NotificationChannelErrorEventArgs>(PushChannel_ErrorOccurred); // Register for this notification only if you need to receive the notifications while your application is running. pushChannel.ShellToastNotificationReceived += new EventHandler<NotificationEventArgs>(PushChannel_ShellToastNotificationReceived); pushChannel.Open(); // Bind this new channel for Tile events. pushChannel.BindToShellToast(); } else { // The channel was already open, so just register for all the events. pushChannel.ChannelUriUpdated += new EventHandler<NotificationChannelUriEventArgs>(PushChannel_ChannelUriUpdated); pushChannel.ErrorOccurred += new EventHandler<NotificationChannelErrorEventArgs>(PushChannel_ErrorOccurred); // Register for this notification only if you need to receive the notifications while your application is running. pushChannel.ShellToastNotificationReceived += new EventHandler<NotificationEventArgs>(PushChannel_ShellToastNotificationReceived); } // Send Channel Uri to OpenXLive Hosting Server RegisterNotificationUri(pushChannel.ChannelUri); }
如果发送Toast Notification时,XNA游戏在运行,会调用下面的ShellToastNotificationReceived事件处理函数,显示MessageBox:
void PushChannel_ShellToastNotificationReceived(object sender, NotificationEventArgs e) { StringBuilder message = new StringBuilder(); string relativeUri = string.Empty; message.AppendFormat("Received Toast {0}:\n", DateTime.Now.ToShortTimeString()); // Parse out the information that was part of the message. foreach (string key in e.Collection.Keys) { message.AppendFormat("{0}: {1}\n", key, e.Collection[key]); if (string.Compare( key, "wp:Param", System.Globalization.CultureInfo.InvariantCulture, System.Globalization.CompareOptions.IgnoreCase) == 0) { relativeUri = e.Collection[key]; } } // Display a dialog of all the fields in the toast. MessageBox.Show(message.ToString()); }
需要特别提示的是,在XNA游戏中,命令行是无效的,如果添加一个无效的命令行参数,会造成程序崩溃,建议将命令行设为空即可。OpenXLive服务器发送Toast Notification后,运行效果如下:
4. 发送Raw Notification
最后是Raw Notification,代码如下:
private void CreateRawNotification() { // Try to find the push channel. HttpNotificationChannel pushChannel = HttpNotificationChannel.Find(RawChannelName); // If the channel was not found, then create a new connection to the push service. if (pushChannel == null) { pushChannel = new HttpNotificationChannel(RawChannelName); // Register for all the events before attempting to open the channel. pushChannel.ChannelUriUpdated += new EventHandler<NotificationChannelUriEventArgs>(PushChannel_ChannelUriUpdated); pushChannel.ErrorOccurred += new EventHandler<NotificationChannelErrorEventArgs>(PushChannel_ErrorOccurred); pushChannel.HttpNotificationReceived += new EventHandler<HttpNotificationEventArgs>(PushChannel_HttpNotificationReceived); pushChannel.Open(); } else { // The channel was already open, so just register for all the events. pushChannel.ChannelUriUpdated += new EventHandler<NotificationChannelUriEventArgs>(PushChannel_ChannelUriUpdated); pushChannel.ErrorOccurred += new EventHandler<NotificationChannelErrorEventArgs>(PushChannel_ErrorOccurred); pushChannel.HttpNotificationReceived += new EventHandler<HttpNotificationEventArgs>(PushChannel_HttpNotificationReceived); // Display the URI for testing purposes. Normally, the URI would be passed back to your web service at this point. System.Diagnostics.Debug.WriteLine(pushChannel.ChannelUri.ToString()); MessageBox.Show(String.Format("Channel Uri is {0}", pushChannel.ChannelUri.ToString())); } // Send Channel Uri to OpenXLive Hosting Server RegisterNotificationUri(pushChannel.ChannelUri); } void PushChannel_HttpNotificationReceived(object sender, HttpNotificationEventArgs e) { string message; using (System.IO.StreamReader reader = new System.IO.StreamReader(e.Notification.Body)) { message = reader.ReadToEnd(); } MessageBox.Show(String.Format("Received Notification {0}:\n{1}", DateTime.Now.ToShortTimeString(), message) ); }
运行效果如下:
写在最后
到这里,我们就介绍了OpenXLive Push Notification Hosting Server的全部功能,需要指出的是,OpenXLive并没有提供自己的Push Notification服务,我们仍旧使用微软提供的Push Notification机制。OpenXLive Push Notification Hosting Server只是帮助那些没有服务器、又希望能够使用Push Notification服务的开发者,来管理Push Notification Channel,给他们一个友好的Web界面,供他们来发送自己的Push Notification消息。
如果您还有任何的疑问,或者需要更详细的帮助,欢迎您访问OpenXLive的官方网站