下载本文的 PDF 版本 PDF

茶杯中的 Java

STEPHEN JOHNSON,泰雷兹-雷神公司

使用 J2ME 进行蓝牙设备编程

很少有技术领域像无线行业这样快速发展。随着市场和设备的成熟,移动应用的需求(和潜力)也在增长。越来越多的移动设备安装了 Java 平台,这使得大量的 Java 程序员可以尝试嵌入式编程。不幸的是,并非所有的 Java 移动设备都是相同的,这给新的 J2ME(Java 2 平台,微型版)程序员带来了许多挑战。本文通过一个示例游戏应用程序,说明了与 J2ME 和蓝牙编程相关的一些挑战。

J2ME 入门

J2ME 是用于嵌入式设备和消费电子产品的 Java。图 1 显示了 J2ME 组件堆栈:配置在最低层,其次是配置文件,顶部是可选软件包。给定设备提供的功能(和 API)取决于支持的配置、配置文件和可选软件包的组合。

J2ME 世界大致分为两类:一类服务于内存小于 512 KB 的设备(您可以握在手中的东西),另一类服务于内存占用更大的设备(您可以插入墙壁插座的东西)。这些设备类别是两种 J2ME 配置的基础:CDC(连接设备配置)和 CLDC(连接受限设备配置)。配置决定了嵌入在设备中的 VM(虚拟机)和底层 Java API。

CDC 可以被认为是“精简版的 J2SE”。由于它是为 J2SE(Java 2 平台,标准版)兼容性而设计的,因此为 CDC 平台编写的源代码与标准 J2SE 代码无法区分。CDC 使用的 VM 符合标准版 VM 规范。

CLDC 是 CDC 的受限子集,仅提供标准版中可用功能的一小部分。一个显着的区别是 CLDC VM(称为 KVM)未实现 JVM 的所有功能,例如字节码验证器。

配置文件位于 J2ME 堆栈中的配置层之上。配置文件是面向一类设备的功能集合。例如,汽车计算机等嵌入式设备可能不需要 GUI API,但 PDA 手机需要。随着 Java 设备数量的增长,通过 JCP(Java 社区流程)添加了更多配置文件。配置文件的选择决定了使用的配置(CDC 或 CLDC)。在较小程度上,所用配置文件的版本决定了所用配置的版本。配置文件通常针对设备类别。MIDP(移动信息设备配置文件)针对手机和小型 PDA 应用程序,而 PBP(个人基础配置文件)主要基于 Java TV API,针对机顶盒应用程序。

J2ME 配置和配置文件的组合构成了设备的完整开发环境。每个配置文件决定了环境支持的托管应用程序类型。大多数 Java 开发人员都熟悉 Web 小程序。开发人员编写一个特殊的类(小程序扩展),该类实现由小程序执行环境(通常在 Web 浏览器中)调用的回调。MIDP 应用程序称为 MIDlet,PBP 应用程序称为 Xlet,但它们通常遵循相同的模式。这些应用程序类型之间的主要区别在于特定的回调和执行环境。

J2ME 设备还可以实现一个或多个可选软件包,例如蓝牙支持、RMI(远程方法调用)和移动媒体 API。

蓝牙简介

蓝牙是一种基于无线电的网络协议,允许设备参与即时网络。这些网络称为微微网,最多由八个设备组成。其中一个设备充当主设备,协调整个微微网的通信时序。微微网可以菊花链式连接形成更大的散射网,前提是每个参与的微微网都有一个唯一的主设备。蓝牙设备在未经许可的 2.4 GHz 频谱中运行,范围约为 30 米。相对较短的范围允许低电压和电池供电设备进行通信。蓝牙无线电使用频率跳变算法,时序由微微网中的主设备决定。蓝牙会并且将会干扰此频谱中的其他通信设备,最显着的是无绳电话和 802.11 网络。

也许您听说过蓝牙的安全问题,例如未经授权浏览他人的地址簿。然而,蓝牙有一个基本假设,即即时网络是一件好事,并且发现匿名设备上的服务的能力是一项功能,而不是一个错误。好消息是,大多数漏洞都很容易关闭——通过使设备“不可发现”并使用共享密码与其他设备配对。然而,在我们超前之前,我们应该检查蓝牙连接是如何建立的。

每个蓝牙设备都有一个服务信息注册表,称为 SDD(服务发现数据库),其中包含有关设备支持的服务的详细信息。如果蓝牙设备设置为“可发现”,则其他设备可以通过广播查询找到它(列为“不可发现”的设备不会响应查询)。请求设备然后可以查询每个设备的 SDD,并找出是否支持给定的服务。如果查询成功,设备将通过将服务记录信息(从 SDD 中提取)发送到请求设备来回复。请求者然后可以使用服务记录信息与另一设备建立连接。

蓝牙的官方 Java API (JSR 82) 以优雅的方式处理此发现过程。API 使用现有的连接框架在符合 JSR 82 的设备之间建立连接。每个兼容设备都提供一个 LocalDevice 单例,它是设备本身的代理。LocalDevice 包含一个 DiscoveryAgent,用于查询其他设备的蓝牙设备和服务。蓝牙服务提供商必须创建服务记录并将其添加到 SDD。JSR 82 将服务记录、服务应用程序和连接捆绑在一起以简化操作。当您的应用程序准备好接受对您服务的传入连接时,服务记录将添加到 SDD。不幸的是,这意味着您的应用程序必须运行,服务记录才能存在于 SDD 中。这剥夺了蓝牙更有用的功能之一,即使应用程序未运行也能发现服务。

目标开发

J2ME 开发人员面临的第一个挑战是选择目标设备。许多 Java 编码人员都被标准 Java 平台的“一次编写,随处运行”的可移植性宠坏了。这里不是这样。J2ME 设备像雪花一样种类繁多。除了设备和供应商特定的 API 之外,还有许多配置、配置文件和可选软件包的组合需要处理。与标准 Java 不同,您不能假设您正在编码的功能集在所有设备上都存在。

对于商业开发,最可行的 J2ME 平台是 CLDC。手机应用程序(尤其是手机游戏)是一个快速扩张的市场。根据 Screen Digest 的一项研究,到 2010 年,手机游戏下载收入预计将达到全球 84 亿美元。大多数支持 Java 的手机都使用某种版本的 CLDC 平台,并且通常支持某种版本的 MIDP。虽然大多数手机游戏目前都是单人游戏,但多人游戏离我们并不遥远。即使是像扑克这样畅销的游戏,如果与真人对手一起玩也会更有趣。蓝牙将允许在没有手机信号的情况下进行多人游戏,依靠手机的内部蓝牙无线电进行通信。

J2ME 网站 (http://www.java.sun.com/j2me) 的设备部分提供了一个合理的设备供应商和产品列表。大多数列表都包含设备上存在的配置和配置文件,以及供应商网站的链接,该链接可能会或可能不会提供更多详细信息。选择功能丰富的设备使开发更容易,但商业开发人员更关注设备的市场渗透率。毫不奇怪,最受欢迎的设备通常是最便宜的设备——附带两年合同的 49 美元奇迹。另一方面,发行商对知道如何让这些设备“唱歌”的开发人员感兴趣。这需要对 Java 的基本知识:线程、垃圾回收和操作原始数据类型。这也意味着对您可能已经习惯的许多面向对象的最佳实践视而不见:一旦针对性能进行优化,J2ME 代码通常并不漂亮。

尖端功能通常会被应用程序的潜在市场性所抵消。在我们的示例中,我们开发了一个 Java 蓝牙应用程序。查看支持 JSR 82 的设备数量相当令人沮丧。许多手机都支持蓝牙,但您必须仔细查找专门支持 JSR 82 的设备。我们的示例应用程序使用西门子 SL66 手机。它支持 MIDP 2.0,这是嵌入在大多数支持 Java 的手机中的最新版本的配置文件。西门子拥有一个活跃的开发人员社区,该公司通过其网站提供支持。并非所有制造 J2ME 设备的供应商都提供如此容易访问的开发人员支持。一些无线运营商(如 Sprint PCS)也拥有开发社区。在选择设备之前,值得查看支持级别。

选择您的工具

当您开发嵌入式软件时,没有比在目标设备上运行它更好的替代方案。虽然仿真和调试的最新技术令人印象深刻,但在真实世界的设备上运行您的代码既令人感到卑微又令人兴奋。由于硬件调试环境非常昂贵,因此仿真是最流行的选择。J2ME 仿真具有三个级别的设备保真度递增:具有默认仿真配置文件的 JWTK(Java Wireless Toolkit);具有供应商提供的仿真配置文件的 JWTK;以及供应商提供的仿真器。每个仿真级别的质量差异非常明显:仅显示就有很多差异;行为上的差异甚至更大——而且难以调试。对于新的 J2ME 程序员,我们推荐带有 JWTK 的供应商配置文件。这种组合将使您达到大约 90% 的目标。我们将在本文后面讨论将完成的应用程序放在设备上。

JWTK 可以作为独立的执行环境运行,也可以与 Java IDE(如 Sun 的 NetBeans)集成。JWTK 与 NetBeans 的集成是无缝且相当稳健的。JWTK 还支持可选的蓝牙 API,这使您无需购买第三方开发环境。

编写应用程序

对手机游戏“剪纸”的分析使我们能够演示一个在蓝牙通信中同时实现客户端和服务器角色的程序。在游戏中,玩家轮流从四行剪纸中移除剪纸。每个玩家必须从选定行中移除至少一个剪纸。被迫移除最后一个剪纸的玩家输。回合制游戏是一个很好的例子,因为它很容易理解。与大多数 PC 或游戏机游戏是快节奏动作游戏不同,手机鼓励较慢节奏的游戏风格。至少,手机游戏应该可以用一只手玩,并且非常宽容控制输入错误。并非所有手机都具有游戏友好的界面。按下按键和处理事件之间的输入延迟可能会使“抽搐”游戏非常令人沮丧。这并不是说您不能制作动作游戏。只要屏幕上的动画有限,正确使用 Java 线程就可以获得令人满意的结果。大多数当前的手机都可以处理一个输入线程和一个或两个动画/屏幕绘制线程。您可以在每个线程中动画化多个精灵。例如,我的第一个游戏之一是打鸭子,它动画化了多达三个鸭子精灵和一个十字准星。许多 J2ME 书籍详细介绍了这类应用程序。

“剪纸”应用程序包含两个线程:一个服务器线程,用于响应连接请求;以及一个客户端线程,用于响应本地用户输入。像“剪纸”这样的回合制游戏的优点在于它是对称的。一旦两个设备之间的连接建立,行为是相同的,游戏逻辑只需要关注生成一个 GameTurn 对象并将其传递给另一个玩家。由于逻辑不知道客户端或服务器指定,因此该结构可以扩展到任意数量的玩家,前提是您知道轮到谁了。

现在您已准备好设置蓝牙通信。客户端线程通过获取本地设备的 DiscoveryAgent 类并发出 startInquiry() 广播来查找其他蓝牙设备,从而响应“新游戏”请求。请注意,所有 DiscoveryAgent 查询都是异步的,框架通过回调函数进行通信。例如,调用 startInquiry() 的线程等待执行环境调用回调方法 inquiryCompleted()。(如果没什么,为抽搐无线电设备编写异步代码是锻炼您的 Java 线程技能的好方法)。一旦发现其他设备,就会在 RemoteDevice 上调用第二个查询:searchServices()。同样,这是一个异步调用,当等待线程收到 serviceSearchCompleted() 的通知时结束。

如果服务搜索成功,您现在拥有来自其他设备的一个或多个服务记录。您可以向其他设备发送邀请(前面提到的 GameTurn 对象的特例)。这就是 Java 蓝牙实现的闪光点。您可以使用从 ServiceRecord 对象中提取的 URL 获取与其他设备的连接

Connector.open( record.getConnectionURL() )

此时,您有一个标准的 Java StreamConnection 对象。您可以继续编写应用程序代码,而无需担心底层协议。通信协议的抽象是一件好事,也是 Java 连接框架的一个特性。

你说这很简洁,但是应用程序如何首先将服务记录放入 SDD 中呢?您刚刚看到客户端线程使用 Connector.open() 方法使用服务记录 URL 建立与远程设备的连接。服务器线程使用类似的技巧在本地 SDD 中建立服务记录。当应用程序启动时,服务器线程使用以下形式的 URL 打开本地连接

Connector.open(“btspp://127.0.0.1:<UUID>;name=<btName>;authorize=false”);

UUID 是您服务的通用标识符。客户端线程使用它来调用 searchServices() 方法。btName 参数是与服务关联的友好名称。连接器足够智能,知道您没有尝试建立远程连接,因此不会像以前那样返回 StreamConnection。在这种情况下,您将获得一个 StreamConnectionNotifier 对象,该对象链接到该特定服务。此时,服务记录已创建。您可以通过向 LocalDevice 请求 ServiceRecord 并传递 StreamConnectionNotifier 来添加属性

localDevice.getRecord(notifier);

最后,您可以通过调用 acceptAndOpen() 将服务记录添加到 SDD 并侦听对此服务的任何连接

notifier.acceptAndOpen();

此调用返回到请求设备的 StreamConnection。与以前一样,您现在可以将此连接视为普通的 Java StreamConnection。连接关闭后,服务记录将从 SDD 中删除。

在像“剪纸”这样的对称网络应用程序中,大部分挑战在于正确管理两部手机上的多个线程。与其他 Java GUI 应用程序一样,您不希望挂起 GUI(客户端)线程。您也不希望允许用户做他们不应该做的事情。您不希望让用户感觉他们没有控制权,但有时您也不想给他们控制权。幸运的是,这些问题在仿真中很容易解决。当然,您现在拥有的只是一个在假手机上运行的应用程序。当您将代码加载到设备上时,真正的乐趣就开始了。

构建和测试

现在您已准备好构建应用程序,将其加载到设备上(称为配置的过程),然后运行它。准备用于部署的 MIDlet 涉及以下任务

您可能想知道预验证是什么意思。如前所述,CLDC VM 未实现字节码验证器。验证传入字节码的计算开销被认为对于 CLDC 类设备来说过于昂贵,因此被省略了。这意味着字节码验证需要在 VM 外部完成,在运行时加载类之前完成。这提出了一个安全问题,因为 VM 类加载器(在运行时)进行的验证保证了正在处理的代码在被使用之前立即通过验证。将运行时 VM 与验证过程分离为恶意应用程序留下了更大的安全漏洞。MIDP 2.0 规范尝试使用代码签名、证书和基于域的安全模型来缓解此风险。此过程不在本文的讨论范围之内,但您可以在 MIDP 2.0 规范中阅读有关它的信息。

应用程序描述符包含您的 MIDlet 的元数据和属性。与其他 Java 执行环境中的描述符不同,JAD(Java 应用程序描述符)在应用程序 (MIDlet) jar 文件外部。这样做是为了协助 OTA(空中下载)配置。MIDP 2.0 规范正式确定了这种通过无线 (HTTP) 网络分发 MIDP 应用程序(捆绑在套件中)的方法。最简单的 OTA 案例的工作原理如下

  1. 用户通过浏览 JAD 发现 MIDlet 套件。
  2. 设备检查 JAD 的安全设置、内存要求、配置和平台版本。
  3. 如果 MIDlet 套件兼容,则设备使用 JAD 中的 URL 下载套件 *.jar 文件。
  4. 设备在用户批准后安装 MIDlet 套件。

从开发的角度来看,OTA 不是将您的代码放到手机上最有效的方法。它需要一部具有有效帐户、互联网服务和开发人员访问公共 Web 服务器的手机。Web 服务器必须理解 JAD 和 JAR mime 类型,但大多数服务器都不理解。如果您为多部手机开发,则可能会非常昂贵。

许多手机允许您通过 USB 电缆上传数据,但并非所有手机都会自动加载 MIDlet 套件 JAR。像西门子这样的较新型号的手机允许通过蓝牙进行文件传输,并且足够智能以识别 JAR 作为 Java 应用程序并将其安装在手机 UI 的应用程序文件夹中。

一旦加载到手机上,游戏可能需要一些工作才能使其正常运行。例如,发现代理的 startInquiry() 可能看起来不是异步的——也就是说,客户端线程被阻塞,这会冻结应用程序 GUI——但是当您将代码加载到另一部 JSR 82 手机上时,应用程序的行为与在模拟器上非常相似。此类错误非常难以发现,尤其是在没有硬件调试功能的情况下。对于任何从事 Java 企业版开发的人来说,这种类型的问题(供应商对 Java 规范的不同实现)应该很熟悉。鉴于竞争激烈的 Java 供应商的数量以及编写专注于外部行为(而不指定实现)的规范的难度,这些问题比我们希望的更频繁地发生。

结论

本文试图提供足够的信息,使您熟悉 J2ME。通过带您完成开发周期并最终在手机上运行,我们希望分享了为移动设备开发的一些兴奋(和痛苦)。如果您将大量时间用于为大型系统开发软件,那么 J2ME 提供了一个不同且令人愉悦的挑战。

STEPHEN JOHNSON 是泰雷兹-雷神系统公司(位于加利福尼亚州富勒顿)Command View II 产品线的主要软件工程师。他的兴趣包括软件架构和以网络为中心的系统。他目前正在追求通过面向服务的架构改进指挥和控制系统的互操作性。Johnson 拥有乔治梅森大学系统工程理学硕士学位。

acmqueue

最初发表于 Queue 第 4 卷,第 3 期
数字图书馆 中评论本文





更多相关文章

Andre Charland, Brian LeRoux - 移动应用开发:Web 与原生
几年前,大多数移动设备用一个更好的词来说,都是“笨拙的”。当然,有一些早期的智能手机,但它们要么完全以电子邮件为中心,要么缺乏可以在没有手写笔的情况下使用的复杂触摸屏。更少有配备能够显示文本、链接,甚至可能是一张图片的体面移动浏览器的设备。这意味着如果您拥有其中一种设备,那么您要么是沉迷于电子邮件的商务人士,要么是希望今年将成为智能手机之年的 Alpha 极客。


- 流媒体和标准:交付移动视频
不相信我?请继续关注…… 手机无处不在。每个人都有一部。想想您上次乘坐飞机并且航班在地面上延误的时候。在可怕的公告之后,您立即听到每个人都拿起手机并开始拨号。


Fred Kitson - 移动媒体:使其成为现实
许多未来的移动应用程序都基于丰富、交互式媒体服务的存在。此类服务的承诺和挑战是在最恶劣的条件下以低成本为具有高期望的用户社区提供应用程序。情境感知服务需要有关用户是谁、在哪里、何时以及正在做什么的信息,并且必须及时且以最小的延迟交付。本文揭示了一些当前最先进的“魔法”和研究挑战。


Bruce Zenel - 企业级无线
我们在无线领域工作了超过 10 年,并参与了其成熟过程的每个阶段。我们看到无线从互联网泡沫之前的玩具技术发展到互联网泡沫期间真正有前途的技术,但在泡沫破灭后却令人失望,当时发现该技术尚未为黄金时段做好准备。幸运的是,我们似乎终于达到了技术和企业的期望最终融合的地步。





© 保留所有权利。

© . All rights reserved.