BES 10 企业推送详解

1. 背景

黑莓公司于2012年1月30号推出了新的BlackBerry 10 智能手机,与之相对的是黑莓企业服务器由之前的BES 5 升级到了BES 10.

在新的BlackBerry 10 平台上,推送依然是极为重要的一个功能,不过,因为平台的升级,BlackBerry 10 设备上的推送接受API和之前的推送接受API有一些细节的不同。所以,需要开发者根据新的API在BlackBerry 10 上开发新的推送接受程序。

值得开发人员感到开心的是,在新的BlackBerry 10 平台上,有关推送的服务器端代码可以完全不用修改,在服务器端只需要将推送服务器由之前的BES 5 转为新的BES 10服务器即可。

如我们所知道的,BlackBerry 10上的开发方式有很多,如Cascades,WebWorks,Adobe Air等,考虑到篇幅,这里主要介绍如何使用BlackBerry 10 Cascades开发工具开发一个可以在BlackBerry 10 平台上接受推送的应用程序。

2. 架构

BES 10 的推送架构和之前的BES5推送架构几乎完全相同,参见下图:

BES 10 企业推送详解_第1张图片

上图来自于黑莓官网,链接如下:

http://developer.blackberry.com/cascades/documentation/device_comm/push/index.html

需要注意的是,以上链接主要从BlackBerryInternet Service推送的角度讲述BlackBerry10上的推送,其中有些细节并不适合BES推送,所以以上链接对于BES推送开发者来讲仅供参考,用以了解基本的BlackBerry10推送架构即可。

BlackBerryEnterprise Service 10推送而言,可以对以上架构图做一些简化,同时用特定的组件更换其中的一般组件,从而更清晰地展现BES10推送原理,简化后的架构图如下:

BES 10 企业推送详解_第2张图片

可以发现,简化后的BES  10推送架构图和简化版的BES 5推送架构图也几乎相同,整体上由几部分构成,包括推送代码,BDS服务器和推送接收客户端。其中的BDS服务器是BES10服务器的一部分,全名是BlackBerryDevice Service,其作用和BES5推送架构中的BES服务器相同。BDS服务器上也有一个MDS服务器组件,缺省侦听8080端口,用于接收应用程序的推送请求。

推送代码通过HTTP协议和BDS服务器通讯,向BDS服务器的MDS组件发送推送请求。再次强调,BES10的服务器端推送请求格式和BES5的服务器端推送请求格式完全相同。所以,应用服务器端的推送代码可以沿用使用BES5服务器时的推送代码。

BDS服务器接收到应用服务器的推送请求后,会通过无线网络将数据推送到指定的客户端。需要注意的是,BlackBerry10 设备在BDS上激活以后设备会分为个人区(Personal)和工作区(Work),BES 10推送接收客户端必须运行在工作区才可以正常接收推送。

此外,因为工作区的应用只能通过BDS服务器来进行远程部署,所以测试BES10推送客户端的时候必须将应用打包部署到BDS服务器上,通过BDS服务器远程安装到BlackBerry10设备上以后才能进行测试。  

3. 步骤概要

因为整个推送应用的开发测试涉及比较多组件,过程比较复杂,所以在这里先总体讲述一下需要完成的各个步骤,让读者有一个相对清晰的思路。

Ø 首先我们需要准备好测试环境,包括:

·       搭建BlackBerry 10 Cascades开发环境

·       搭建测试的BDS服务器

·       将测试BlackBerry 10设备激活到上面搭建的BDS服务器上

·       尝试将一个简单的应用通过BDS服务器部署到测试设备上。

 

Ø 然后我们需要通过BlackBerry 10 Cascades开发环境创建一个基本的BlackBerry10应用,作为推送接收应用的基础。

 

Ø 接着我们需要对项目做一些特定的设置,以让该应用支持BES 10推送。

 

Ø 紧接着我们需要在项目中加入推送相关代码,以创建推送服务(PushService),然后创建对应的sessionchannel

 

Ø PushService准备好以后,我们需要在项目中添加推送响应代码,在应用接收到推送数据后进行响应。

 

Ø 完成以上工作后需要将应用打包部署到BDS服务器上,通过BDS服务器将这个测试应用部署到测试设备上。

 

Ø 准备好推送接收客户端后我们需要在BDS服务器旁构建推送代码,以向BDS服务器发送推送请求。

 

Ø 一切准备就绪后就可以开始推送测试了。

 

下面详细讲述以上所有步骤的具体操作过程。

 

4. 环境准备

环境准备包括开发环境的准备,测试服务器的搭建,测试设备的准备和应用部署的测试。

 

4.1. 开发环境准备

为了开发BlackBerry10推送接收客户端,我们需要一个BlackBerry10应用开发环境。如上文提到,虽然BlackBerry10应用开发环境有多种选择,我们在本文里只描述BlackBerry10 Cascade环境的使用。

为了搭建BlackBerry10 Cascades开发环境,需要到黑莓官网上下载开发环境安装文件和模拟器安装文件,按照官方文档进行安装。

同时,应为我们最终需要将应用部署到真机上进行测试,所以我们需要在黑莓官网申请应用签名,然后将签名安装到我们的开发环境中。

有关BlackBerry10 Cascades环境的安装和应用签名的安装,请参考我的博客文章:

http://blog.csdn.net/keyboardota/article/details/8003012

http://blog.csdn.net/keyboardota/article/details/8084131

搭建完开发环境后,创建并在模拟器上运行一下HelloWorld应用,以检验开发环境是否正常工作。

 

4.2. 测试服务器搭建

为配合推送应用测试,需要搭建BDS测试服务器。BDS服务器是BES10服务器的一部分,可以在黑莓官网申请测试证书并下载安装程序。

官网链接如下:

http://us.blackberry.com/business/software/bes-10.html

有关BDS的详细文档可以在以下链接中找到:

http://docs.blackberry.com/en/admin/subcategories/?userType=2&category=BlackBerry+Device+Service

有关BDS的安装可以参考下面的视频教程:

https://www.blackberry.com/blackberrytraining/web/_NewContent/indexExternal.html?cc=3732382d30383534365f4250415336325f496e7374616c6c&cx=3230393931323331&cl=656e

详细的安装文档链接如下:

http://docs.blackberry.com/en/admin/deliverables/48992/BlackBerry_Device_Service_6.2_Installation_and_Configuration_Guide_en.pdf

因为本文主要专注于推送应用的开发测试,所以在这里就不详细讲述BDS的安装过程,安装遇到问题请到黑莓官方论坛寻求帮助。

安装好BDS测试服务器后需要找一台BlackBerry10 测试设备进行激活,对邮件接收等功能进行测试,以验证BDS服务器是否安装成功。

 

4.3. 测试设备准备

如上所述,我们需要一台BlackBerry10真机进行测试,测试时可以使用BlackBerry10 开发机,也可以使用市面上开卖的Z10系列。

将设备的OS升级到最高版本,然后在以上步骤安装的BDS服务器上进行激活,激活过程参考BDS管理文档,大概步骤如下:

·       BDS上创建一个BlackBerry 10 账号

·       BlackBerry 10账号指定一个email profile

·       BlackBerry 10 账号指定一个激活密码

·       BlackBerry 10设备上添加一个账号,填写测试用户邮箱地址和激活密码进行激活。

激活后对企业邮件进行测试,以检验该设备激活是否成功。

同时,需要连接测试BlackBerry10设备到开发环境上,确认可以通过USB线将BlackBerry10设备连接到开发环境上进行调试。

 

4.4. 应用部署测试

准备好测试服务器和测试BlackBerry10设备后,需要创建一个简单的BlackBerry10应用对应用的无线部署进行测试。

首先在BlackBerry10 Cascades开发环境中创建Helloworld应用,对应用进行签名打包,形成bar文件。

有关Cascades中应用的签名和打包,请参考我的博客文章:

http://blog.csdn.net/keyboardota/article/details/8502920

打包好bar文件后,将该bar文件拷贝到BDS服务器上,完成以下操作:

·       BDS管理界面创建一个Application配置,选择以上打包好的bar文件作为应用程序安装文件

·       BDS管理界面创建一个Software Configuration,在该配置中指定以上创建的Application配置。

·       将以上创建的Software Configuration指定给测试设备对应的BDS账号。

 

测试成功的话,一段时间后你的测试BlackBerry10设备的工作区上将看到刚部署的Helloworld应用。  

 

5. 项目创建

通过以上的步骤准备好整体环境以后就开始创建推送客户端的项目了,纯粹项目创建而言是比较简单的,通过Cascades的项目创建向导可以很快创建一个类似于HelloWorld的应用。不过,因为我们的应用需要部署到BlackBerry10设备的工作区中,我们需要对项目做一些特定的工作。

根本原因是我们无法查看BlackBerry10工作区中的console日志,也无法通过USB线直接在设备工作区调试应用,所以我们需要在应用中添加一些组件以显示日志消息。基本的想法是创建一个类似于HelloWorld的应用,在显示HelloWorld的标签组件中显示日志消息,这样我们测试时可以清楚的知道后台发生什么事情。

Cascades开发比较熟悉的读者可以根据自己的喜好完成项目的创建,只要实现在前台界面展现后台日志消息即可,然后开始跳到第6步进行有关推送的工作。

我完成消息显示的任务是通过以下方式进行的:

main.qml中修改label组件,给它一个objectName,这样后台程序可以轻松获得这个组件并更新其内容:

          Label {
                    id: myLogLabel
                    objectName: "logLabel"
                    text: "default text"
                    multiline: true
                    horizontalAlignment: HorizontalAlignment.Fill
                }


然后在后台创建一个控制器类,我命名为PushController,在该类实例化的时候通过以下代码获得label组件:

        

debugLabel = app->findChild<Label*>("logLabel");

 

 

然后给PushController添加一个addLog方法,在该方法中记录日志消息,并更新label组件的内容:

 

void PushController::addLog(QString new_log) {

       qDebug() << "adding log:" << new_log;

       this->log_string = new_log + "\n" + this->log_string;

 

       debugLabel->setText(this->log_string);

 

}

这样就可以在前台显示后台的日志消息了。

完成以上工作后可以直接通过USB线对应用进行调试,确认后台消息可以在前台界面中展现。

 

6. 启用推送

接着我们需要对我们创建的项目进行一些配置修改,以支持BlackBerry10 推送。

首先打开项目的pro文件,文件名为 “<项目名>.pro”,在其中加入以下配置设置:

   

LIBS += -lbbnetwork -lbbplatform -lbbsystem -lbb

 

这样就可以让项目找到推送需要的network,system等二进制包文件。

 

接着打开bar-descriptor.xml文件,选择“source”标签页对该文件的源文件进行编辑,在文件最后的“</qnx>”标签前面加入以下配置:

 

      <invoke-target id="cn.damon.samples.cascades.bespush">       

      <type>APPLICATION</type>

      <filter>

         <action>bb.action.PUSH</action>

         <mime-type>application/vnd.push</mime-type>

      </filter>

</invoke-target>


 

其中的id="cn.damon.samples.cascades.bespush"”需要根据你自己的项目情况修改成唯一的ID号。这个ID号后面创建PushService对象时还需要使用。

 

需要特别注意的是,在官方文档中提到,需要使用BlackBerryInternet Service推送的应用必须在bar-descriptor.xml文件中加入以下内容,不过这个对于BES推送而言却相反,一定不能加入以下内容:

<action system=”true”>_sys_use_consumer_push</action>


 

7. 创建PushService

 

接着我们可以开始在客户端创建PushService对象了。

对于正常应用而言,需要在应用第一次启动时创建PushService对象,并完成对应的session创建,channel创建等工作。这里为了更清晰地展现推送应用创建过程,我在main.qml中加了一个按钮,点击后调用PushControllerstartPush方法,在这个方法中开始创建PushService对象的工作。

为了使用PushService,需要引入对应的PushService头文件,代码如下,加入到上面创建的PushController类头文件中:

#include <bb/network/PushService>


 

然后为PushController定义一个PushService属性,名为m_pushService,在startPush方法中通过以下代码创建PushService:

  

       m_pushService = new PushService("MyApplicationID",

                    "cn.damon.samples.cascades.bespush");

 

 

其中的“MyApplicationID”为应用ID,和BES 5推送中的端口号作用相同,同一台设备中这个应用ID号必须唯一,否则推送时不知道数据推送给哪个应用。

而其中的"cn.damon.samples.cascades.bespush"为调用ID,必须和bar-descriptor.xml文件中invoke-target标签定义的ID相同。

 

这里需要注意的一点是,因为我们在bar-descriptor.xml文件中没有加入“<actionsystem=”true”>_sys_use_consumer_push</action>”,所以直接通过USB线对应用进行调试的话会报错,错误如下:

 

/pps/services/push/ipc  open failure:  13 

Push pps file is not open.


解决这个错误的方法是将应用部署到设备的工作区上进行调试,有关部署应用到设备的工作区里,请参考上面的章节。

 

 

创建了PushService对象后就可以开始为该对象创建session了。

8. 创建Session

 

PushService创建Session比较简单,调用PushService对象的createSession方法就可以了,代码如下:

 

m_pushService->createSession();


 

 

另外,为了对createSession后的事件进行响应,我们需要在调用createSession之前将PushServicecreateSessionCompleted信号和createChannelCompleted信号绑定到指定方法中。

首先在PushController.h文件中加入以下代码声明信号槽:

private slots:

       void createSessionCompleted(const bb::network::PushStatus&);

       void createChannelCompleted(const bb::network::PushStatus&, const QString&);


 

 

然后在PushController.cpp中定义信号槽方法,下面的代码只是在日志标签中显示消息,没有对事件做进一步的处理:

void PushController::createSessionCompleted(

             const bb::network::PushStatus& status) {

       if (!status.isError() && m_pushService) {

             this->addLog("Session creation completed successfully");

 

       } else {

            this->addLog("Session creation failed: " + status.errorDescription());

       }

}

 

 

void PushController::createChannelCompleted(const bb::network::PushStatus& status,

             const QString& token) {

       Q_UNUSED(token);

       if (!status.isError() && m_pushService) {

             this->addLog("Channel creation completed successfully");

             

       } else {

            this->addLog("Channel creation failed: " + status.errorDescription());

       }

}


 

 

 

最后在startPush方法中将信号和信号槽连接起来,连接了信号槽之后才调用PushServicecreateSession方法,代码片段如下:

 

connect(m_pushService,SIGNAL(createSessionCompleted (const bb::network::PushStatus &)),this,SLOT(createSessionCompleted(const bb::network::PushStatus&)));

 

             

connect(m_pushService,SIGNAL(createChannelCompleted (const bb::network::PushStatus&, const QString &)), this,SLOT(createChannelCompleted(const bb::network::PushStatus&, const QString &)));

 

this->addLog("trying to create session for PushService");

m_pushService->createSession();

this->addLog("after calling creatSession method of PushService");


 

 

完成以上工作以后可以将应用部署到设备的工作区进行测试,看createSession是否能成功调用。

 

9. 创建Channel

如果createSession调用完成,系统会调用刚才定义的createSessionCompleted方法,在该方法中我们可以判断session是否创建成功,如果创建成功的话我们可以紧接着开始创建Channel,所以需要对createSessionCompleted方法进行修改,修改后的代码如下:

 

void PushController::createSessionCompleted(

             const bb::network::PushStatus& status) {

       if (!status.isError() && m_pushService) {

             this->addLog("Session creation completed successfully");

 

 

                    m_pushService->createChannel(

                                 QUrl(""));

 

       } else {

            this->addLog("Session creation failed: " + status.errorDescription());

       }

}


 

 

注意这里的m_pushService->createChannel里的参数是空的QUrl对象。在BlackBerryInternet Service推送文档里要求这里填写推送服务器的地址,对于BES 企业推送来讲这里不需要填写地址,只需要填写空的QUrl对象即可。

如果Channel创建完成,系统会调用createChannelCompleted方法,在该方法中我们同样可以判断channel创建是否成功,如果成功的话就可以调用PushServiceregisterToLaunch()方法开始侦听推送,修改后的createChannelCompleted方法代码如下:

 

 

void PushController::createChannelCompleted(const bb::network::PushStatus& status,

             const QString& token) {

       Q_UNUSED(token);

       if (!status.isError() && m_pushService) {

             this->addLog("Channel creation completed successfully");

             m_pushService->registerToLaunch();

       } else {

            this->addLog("Channel creation failed: " + status.errorDescription());

             QString message = QString("Create channel failed with error code: %0").arg(status.code());

             this->addLog(message);

       }

}


 

 

这样我们的应用就可以开始侦听推送了,这时可以再次将应用部署到设备的工作区进行测试,一切顺利的话日志标签中会显示创建session成功和创建channel成功的消息。不过这时还不会响应推送事件。

10. 推送响应

 

 

为了让客户端应用程序响应推送事件,我们需要将系统的invoke消息和本类的对应消息槽连接起来。为此,我们在先PushController.h中声明一个消息槽,代码如下:

 

private slots:

       void invoked(const bb::system::InvokeRequest&);


 

接着我们在startPush方法中添加消息槽连接的代码,代码先创建一个InvokeManager实例,赋予对象属性invokeManager,然后调用connect方法将系统的invoked事件和本类的invoked方法连接起来,代码如下:

 

invokeManager = new InvokeManager(this);

       connect(invokeManager,

                    SIGNAL(invoked(const bb::system::InvokeRequest&)), this,

                    SLOT(invoked(const bb::system::InvokeRequest&)));


 

最后,我们实现本类的invoked方法,在该方法中首先判断请求的action名称是否为"bb.action.PUSH",如果是则开始处理推送消息,如果不是则退出。

推送消息的处理也很简单,只是将消息在日志标签中显示出来而已。

具体代码如下:

 

 

void PushController::invoked(const InvokeRequest& request) {

       //Check whether the app was invoked via a push

       if (request.action().compare("bb.action.PUSH") != 0) {

             this->addLog("Not a push invocation :("); //Nope, so we return

             return;

       }

       //If the app is here we know the InvokeRequest contains push data

       PushPayload payload(request);

       if (payload.isValid()) {

             this->addLog("payload is valid, processing now");

             if (payload.isAckRequired()) { //This section is only useful for Push Plus

                    this->addLog("ACK required, sending");

                    m_pushService->acceptPush(payload.id());

             }

             //Read all the push data from the payload

             QString message = payload.data();

 

             this->addLog("Got message:\n"+message);

       }

}


 

 

完成以上代码后客户端程序就准备好了,可以部署到BlackBerry 10测试设备上进行测试了。

11. 客户端部署

 

如上所述,为了对BES 10企业推送应用程序进行测试,需要将客户端应用程序部署到测试设备的工作区才可以正常工作。为了将测试客户端部署到测试设备的工作区,我们需要将以上完成的客户端程序签名打包,通过BDS服务器部署到测试设备上。客户端部署的工作我们在4.4章已经讲述,请参考该章节完成测试客户端的部署。

12. 服务器代码

完成客户端应用的开发和部署以后,就需要考虑服务器端的推送代码了。如果之前熟悉BES5服务器端推送代码的话会发现BES10的服务器端推送代码很简单,因为它们几乎是一样的。

从文档上我们知道,所谓推送代码,就是向BDS服务器所在机器的8080端口发送一段post请求。不论你使用什么语言,什么平台,最终的目的就是向服务器发送特定格式post请求。本例为了简化应用结构,不使用什么复杂的编程语言,也不使用什么服务器,只是简单构建一个html网页,通过浏览器打开该网页,然后向BDS服务器发送post请求。

BDS服务器要求推送请求的URL符合以下格式:

http://<服务器地址>:<服务器端口号>/push?DESTINATION=<目标用户邮件地址>&PORT=<客户端应用ID>&REQUESTURI=/

其中<>号内的是必选项,对应解释如下

<服务器地址>:就是BDS服务器的服务器地址,可以是DNS名称,也可以是IP地址

<服务器端口号>:就是BDSMDS组件的端口号,缺省是8080

<目标用户邮件地址>:就是测试设备激活时使用的邮件地址

<客户端应用ID>:就是我们在开发客户端程序时创建PushService过程中指定的应用ID

 

所以我们对应的html网页框架如下:

 

<html>

<body>

<form action="http://mybds.mydomain:8080/[email protected]&PORT=MyApplicationID&REQUESTURI=/" method=post>

<input name="title" value="my title" />

<br />

<textarea id="content" name="mydata" rows="8" cols="50" >Enter Push Data Here</textarea>

<br />

<input type=submit />

</form>

</body>

</html>



 

其中的titlemydata字段将被作为推送内容推送出去。

以上网页就是一个最简单的推送应用了。当然,在你的实际项目中,你需要根据你使用的平台和编程语言完成post请求,而不是简单通过一个网页来完成。

13. 推送测试

最后进入测试阶段,在BlackBerry10测试设备上进入工作区,打开推送客户端应用,点击开始侦听推送的按钮,检查客户端日志标签,确认sessionchannel都成功创建。

然后打开上面创建的html网页,点击提交按钮向BDS服务器发送推送请求,一切顺利的话,很快你就会在客户端看到你的推送数据了。

需要注意的是,因为BDS服务器端对推送请求不直接返回html结果,所以以上网页点击提交请求成功后,在浏览器上不回有成功提交的提示,只显示空白的网页,这是正常结果,不要误以为出现问题。

 

14. 后续工作

通过以上步骤,你已经完成了BES10的推送客户端开发和测试,不过,如果需要在现实项目中使用BES10企业推送,还需要完成许多完善工作,一些基本的工作包括:

·       在应用启动时启动推送侦听

·       在应用退出,最小化等状态完成对推送消息的响应

·       通过notification功能提示用户推送消息到达

·       通过对话框提示用户推送消息到达

·       。。。

希望各位好运,开发一个功能强大的黑莓10企业应用。

你可能感兴趣的:(BES 10 企业推送详解)