作者: 杨江
第三 部分 手机端 代 码导 入 E clip se
1 . 打开 Eclip se ,
2 . Fi le – I m p o r t , 选 择 Gene ral à Existin g P r o jec ts t o Wo r kspace
第四 部分 核心代码 分析
Bl ac kB e rr y Pu s h 架构
在分析样例代码之前,首先让我们从整体上了解 B lack B err y Pu sh 架构 。
更加详细的 B lack B err y 推送机制的分析和介绍,请参考黑莓官方网站,以及参考资 料“ B ES 服务器推送机制分析”。
从示意图中,我们可以看到,在 B lack B err y 应 用平台上的数据推送从整体上可以分
为六步,按时间顺序分别为:
1 . 应用服务器向 MD S/ B E S 服务器发送推送请求,该请求为 H TTP POST 请求。
2/3 : M D S/ B ES 服务器 做必要的权限和数据监测,告知应用服务器推送请求是否被 接受并将被执行。
4 : MD S / B ES 服务器通过 B lack B err y Inf rast ru ct u re 和无线网络把数据 推送到手持设 备端。
5 : 手持设备收到数据 后,向 MD S/ B ES 服务 器反馈。
6 : MD S / B ES 服务器告知应用服务器其推送数据是否送达手持 设备。
ECL 系 统架 构
从 B lack B err y Pu sh 系统架构上看,从服务器端 Pu sh 数据到手机端 ,要经过多个服 务器和网络甚至无线基站,整个流程相当复杂。幸运的是,从应用开发的角度,程 序员可以不考虑 Pu sh 的复杂底层实现,而只需简单地发送 Pu sh 请 求并监听 Pu sh 请求的处理状态,客户端监听并接受推送数据即可:
1 . 服务器程序向 MD S/ B E S 服务器发送推送请求,所发送的请求为 H TTP POST
请求。
2 . 手持设备上的 Java 客户端程序接收 pu sh 过 来的数据,做出灯光闪烁 / 振铃 等提示,甚至修改桌面图标提示用户,用 户打开程序界面查看数据。
3 . 服务器程序从 MD S/ B E S 服务器获得推送请求是否完成的状态信息。
Ja v a 版 本 E CL 服务器代码 分析
核心代码说 明, Ja v a 类列表
Java 版本 ECL 服务器程序是一个命令行程序,根据命令行参数把指定 exc el 表格中 的联系人列表 c ont act li st 数据推送给指定的手机上。
1 . 主程序:是 ec lTim e dU pda te.ja va ,这是一个包 含 main() 方法的控制程 序,根 据不同参数调用两个 P usher 类做 Brow se r Push 和 Custom i z e P ush 。
2 . 核心 P ush 代码 :由
B row s e rCha nne lP usher .j a va/Custom AppPushe r.ja va/P usher .java 三个类构 成。
3 . 服务器配置信息: MdsP rope rties.ja va 等四个类 用于读取配置文本文件,让
EC L 服务器主程序获 得 MDS/B ES 服务器 I P 地址端口号等信息。
4 . 数据访问: Da taRea d e r. java 通过 J DB C - OD B C 接口读取 Ex ce l 表单数据。
EC L 服务器程序各个 J a va 类的功能说明列表如 下:
Java Class |
De scr ip tion |
eclTi m edUpdate. j ava |
包含 main() 方法的控制 程序,根据不同参数调 用两个 P usher 类做 B ro wse r Push 和 Custom iz e P ush |
Bro w s erChannel P usher. j ava
Custom AppPushe r.ja va
Pushe r .java |
核心的服务器 P ush 代码,包括 B row s e r pushe r 和 c ustom 应用 pushe r 。
B row s e r pushe r 和 c usto m 应用 pushe r 的共同父 类是 P usher .java |
MdsP rope rties.ja va Ca tche rPrope rties.java Cha nne lP rope rties.ja va S trong l y T y pe dP ropertiesSet.java |
MdsP rope rties.ja va 读取 MDS 服务器参数,比如 B ES 服务器主机名 / I P 地址 / 端口号。
Ca tche rPrope rties.ja va 读取手机端监听端口。
Cha nne lP rope rties.ja va 读取浏览器 P ush 相关参 数。
配置文件 样本: # The name of the machine that hosts the MDS push server BesHostName = localhost |
|
# The port on which the MDS Push service is listening. # (Set equal to the "WebServer.listen.port" property for the MDS.) BesPushPort = 8080
# The port that the device -side catcher app is listening on. DeviceListenPort = 911 |
Da taRea d e r.ja v a S prea dshee tP rop e rties.ja va |
Da taRea d e r 通过 J DB C - OD B C 接口读取 Ex ce l 表 单数据 — 紧急情况联系人列表。 |
e c lTime d U pd a te .j a v a 代码分析
根 据参 数构造 P us her 类 (BrowserC ha nn elP us her 或者 C ust omAp pPusher ) 作为整个服务器端推送数据程序的入口, eclTimed Up d at e.java 是一个 标准的 J2 SE 程序。
在 main ( ) 方法中首先分析第一个参数。如果参数值是 c h ann el ,则构 造 pu sh er 为 B ro w serCh ann el Pu sh er 类;如果参数值是 c at c h er ,则构造 p u sh er 为 Cust omAp p P u sh er 类。
public static void main(String[] args)
…
// Process command-line arguments
if (args. length >= 1) {
if (args[0].equalsIgnoreCase( "channel" )) {
// Construct a pusher that sends to a browser channel.
pusher = new BrowserChannelPusher (); //Browser push 也是一个很有 趣的话 题
} else if (args[0].equalsIgnoreCase( "catcher" )) {
// Construct a pusher that sends to a custom catcher.
pusher = new CustomAppPusher ();
}
}
根 据参 数从文 本文 件中读 取 Bl a ckBe rry 手 机 P IN 码 列表
例如从 simu lat o remail.tx t 文件中读取到的 PIN 码为黑莓模拟器的 PIN 码
21 00 00 0a 。
提示: B lack B err y MD S/B ES 服务器支持以手机 PIN 码和 email 地址识 别要推送的目 标手机。在 ECL 样例程序中是使用手机 PIN 码。
if (args.length >= 2) {
emailListFile = args[1];
}
… …
// Get the list of emails to push to.
List recipientEmails = getRecipients(emailListFile);
根 据参 数从 ex cel 表格 文 件中 读取 ECL 联系人 列表
在这里调用 D at aRea d er 类访问 Exc el 表,读取每个组和每个人的联系方式,并通过 pu sh e r.add Co nt ac t ( d at a Field s) ; 方法把数据传递 给 pu sh e r ,最后调用 pu sh e r.f in is h ed Co n st r u c t ion () ; 方法告诉 pu sh er 数据全部读取完毕。 P u sh er 会把所有 联系人方式构造成一个 x ml 字符串保存起来以备下一步调用 pu sh e r.sen d ToH an dh el d(c u rRec ip ient ) ; 进行发送 。
// Fetch the group names from the spreadsheet.
Vector groupDescription = dataReader.getGroupList();
// Assemble the data of all contacts (from all groups) that we
// will push to handhelds.
for ( int i = 0; i < groupDescription.size(); i++) {
// Define the current group.
pusher.beginGroup((String)groupDescription.elementAt(i));
// Add all its members.
Vector groupContactList = dataReader.getContactList(
(String)groupDescription.elementAt(i));
for ( int j = 0; j < groupContactList.size(); j++) {
String[] dataFields = dataReader.getContactData(
(String)groupContactList.elementAt(j));
pusher.addContact(dataFields);
}
}
// Indicate that we're done building the contacts list. After,
// the pusher is ready to send the message multiple times.
pusher.finishedConstruction();
调 用 p us her.sen dT oH a n dh eld () 推送 数据 到每 一部 黑莓手 机上 面
做一个 Fo r 循环,多次调用 pu sh e r.sen d ToH an dh el d (c u rRec ip ie nt ) 通 过 B ES/MD S 服 务器把数据发送到各个手机上面。
// Push the message we just built to all recipients.
for ( int i = 0; i < recipientEmails.size(); i++) {
String curRecipient = (String)recipientEmails.get(i);
try {
System. out .print( "Contacting BES for " + curRecipient);
pusher.sendToHandheld(curRecipient); System. out .println( " - successful push." );
} catch (Pusher.MDSConnectionException ex) {
// Unable to connect to MDS. The condition is unlikely
// to be temporary so abort.
System. out .println( " - " + ex.getMessage());
Pu s he r.j av a 代码分析 |
} catch (Pusher.MDSResponseException ex) {
// Connected OK but MDS responded with error. Log it and
// try the next email.
System. out .println( " - MDS responded with "
+ ex.getMessage());
} catch (Exception ex) {
// Unexpected error. Log a full stack trace and try the
// next email.
System. out .println( " - unexpected error:" );
ex.printStackTrace();
}
}
Pu sh e r.java 代码实际上包括两部分内容,一部分是准备要推送的数据,一部分是真
正的推送操作。
B egin Group ( ) , ad d Cont a c t ( ) , f in ish e d Con s t ru ct ion ( ) 三个方法是用来准备要推送的数 据。主逻辑程序多次调用这三个方法 告诉 Pusher 有哪些联系人数据要推送。 Pusher 会把这些数据拼装成一个 html 或者是一个大文本,并最终推送给手机浏 览器或者手机客户端程序。 writeTo(OutputStream) 方法用来把前面三个方法 构造出来的数据写到输出流中。
注意:以上 4 个方法和 push 无关,更好的做法应该是把他们分离出去做一个独 立的数据构造类。
Pusher.java 代码的核心方法是 sendToHandheld(String recipientEmail) 。该方法构造标准的 http POST 请求给 MDS/BES 服务器,通 过参数 DESTINATION 指定要把数据 push 给哪些人(参数值可以是 email 地址或 者是手机 PIN 码),参数 PORT 告知要把数据推送到手机上面哪个端口(例子代码 中是端口 911 )。
/**
* Pushes the already - constructed message to the indicated recipient. May
* be used many times, but only in the "sending" state.
*/
public void sendToHandheld(String recipientEmail)
throws IOException, MDSConnectionException, MDSResponseException
{
HttpURLConnection conn = null ;
OutputStream out = null ;
try {
// Build the URL to define our connection to the BES.
URL url = new URL( "http" , _props .getBesHostName(),
_props .getBesPushPort(),
"/push?DESTINATION=" + recipientEmail
+ "&PORT=" + getDevicePort()
+ "&REQUESTURI=/" );
conn = (HttpURLConnection)url.openConnection(); |
||
conn.setDoOutput(true ); //to post data |
|
|
conn.setRequestMethod("POST" ); |
|
|
establishRequestHeaders(conn);
//write the data to the http connection
out = conn.getOutputStream();
writeTo(out);
// Check the MDS's response so that we report an error if the push
// was unsuccessful.
int responseCode = conn.getResponseCode();
if (responseCode != HttpURLConnection. HTTP_OK ) {
String serverMessage = conn.getResponseMessage();
throw new MDSResponseException(
"HTTP-" + responseCode + ": " + serverMessage);
}
核心代码说 明, Ja v a 类列表
客户端代码由三个 Java 类,两个图标文件, B lack B err y 应用描述文件 构成。
EC L 客户端程序三个 J a va 类的功能说明列表如 下:
Java Class |
|
|
|
Pushe d D a t a Lis t ener |
在指定端口 911 上监听 push 过来的数据。收到 后调用 Da taSt or e ,修 改手机上应用的图标以提 示用户有更新过的联系人列表。 |
EC LApplic a t i on |
客户端主程序,通过配置,最终会在客户端启 动两个 J a va 进程:后台运行的 P ushed Da ta L ist e ne r 用 来监听 push 过来的数据; 前台 GU I 界面 EC L App li ca ti on 和内部类 Ec lS c re e n 用于展现收 到的 push 数据 — 联系人列 表。 |
Da taSt or e |
使用 net.rim.device.api.system.PersistentStore 保存最新 的 ECL 联系 人员列 表数据。 |
E C L 客户端程序的 两个入口 点 (A lt e r nat e E n t ry P o i nt s )
EC L 客户端程序是如何 自动启动监听程序的?又是如何区分点击 icon 启动 GU I 界 面程序的呢?答案在应用描述文件 B lac k B e rr y _App_De sc riptor.x ml 和主程序的 main() 方法上。
打开 B lac k B e rr y _App_ De sc riptor.x ml ,在 Applica ti on 标签栏目里面,你会看到
Auto- run o n sta rtup 被选 中。这样, EC L S a mpl e 程序会在手机启动过程中自动地启 动,产生一个后台 J a va 进程监听 P ush 数据。
在 Alter na te En tr y P oint s 栏目中,设置了一个参数 Applica ti on a r g ume nt 为 g ui ,并 单独设置了程序 Titl e 和 I c on ,因此程序安装 后在“下载”目录里面出现一个应用 图标。点击图标将产生一个前台 GU I 进程来读 取并显示 P ush 过来的数据。
BlackBerry SDK下载
BES 推送应用实例演示与分析(一)
BES 推送应用实例演示与分析(二)
BES 推送应用实例演示与分析(三)