马宁的嵌入式开发研究

Windows Phone, XNA, Windows Embedded, Windows Mobile

导航

OpenXLive Push Notification Hosting服务开发指南

Posted on 2012-05-16 19:43  马宁  阅读(2429)  评论(5编辑  收藏  举报

作者:马宁

示例代码下载:

Download

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设备上。

整个过程如下图所示:

Ff402558_AP_Push_NotificationArch(en-us,VS_92)

在整个过程中,对于开发者来说,有一个难点很难克服——必须有自己的服务器,否则无法接收从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的引用。

clip_image003

然后,打开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控件:

3

然后点击模拟器上的Windows键,回到主界面,并切换到应用程序列表界面,将我们的示例程序pin到主界面上来显示:

 24

好了,我们现在已经打开了Tile Notification的Channel,并且将其注册到了OPNHS上,而且把应用程序的Tile pin到主界面上。客户端的工作就完成了。

作为开发者,想向客户端发送Tile Notification的时候,只需要登录到OpenXLive的开发者网站,在开发者后台的控制面板中选择对应的游戏/应用,然后在右侧的功能选项中,选择“推送通知”(Push Notification),在二级菜单中,选择“Tile推送通知”,我们会看到如下界面:

z1

Tile Notification一共能够传递六个参数,分为两组。前景部分,是标题(Title)、数字(Count)和前景图片(BackgroundImage),需要指出的是,数字的现实范围是0-99之间的整形数字;而背景组,是背景标题(BackTitle)、内容(BackContent)和背景图片(BackBackgroundImage)。Tile显示的布局与基本样式无法修改,如下图所示:

clip_image013

背景图片即可以是应用程序内部的资源图片,也可以是来自网络的图片。所以,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内容了。

clip_image015

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推送消息”中。界面截图如下:

z4

Toast Notification有三个参数:Text1,是Toast消息的标题;Text2,是副标题;Param,是需要传递给应用程序的命令行参数,所以必须保证这个参数能够被应用程序解析,否则会引起应用程序崩溃,如果不填,则默认打开应用程序的主界面。

好了,接下来看运行效果如何了。当应用程序在后台的情况下,首先会显示Toast提示条,点击提示条后,会进入命令行指定的应用程序页面。

 56

在应用程序运行在前台的情况下,我们会用一个MessageBox来显示收到的消息:

7

好了,我们完成了第二个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推送消息”中,将想要发送的文本粘贴到文本框中,点击“发送”按钮。

手机客户端的运行效果如下:

8

好了,到这里,我们就将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的效果如下:

clip_image026

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后,运行效果如下:

clip_image028

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)

);

}

运行效果如下:

clip_image030

写在最后

到这里,我们就介绍了OpenXLive Push Notification Hosting Server的全部功能,需要指出的是,OpenXLive并没有提供自己的Push Notification服务,我们仍旧使用微软提供的Push Notification机制。OpenXLive Push Notification Hosting Server只是帮助那些没有服务器、又希望能够使用Push Notification服务的开发者,来管理Push Notification Channel,给他们一个友好的Web界面,供他们来发送自己的Push Notification消息。

如果您还有任何的疑问,或者需要更详细的帮助,欢迎您访问OpenXLive的官方网站

英文版:http://www.openxlive.com/

中文版:http://www.openxlive.net/

中文论坛:http://bbs.openxlive.com/