越来越多的移动手机开始支持java应用,但是你知道吗? 很多其它设备也可以运行java 2微型版(J2EE)的应用。

    应用于无线蓝牙技术标准的java APIs(JABWT),由JSR 82 规范定义,支持快速开发便捷、安全及用途广泛的蓝牙应用。无线设备生产商已对JABWT规范做出反应,他们宣布移动手机和其它产品将支持JABWT应用。

    本文我们首先介绍在移动设备上进行java开发的基本原理,然后描述如何为蓝牙通讯编写java应用。

    Java 蓝牙 API

    Java蓝牙 API依赖java通用连接框架,一直一来这成为java 蓝牙API应用的一个局限。但是,人们建议将GCF加入到J2SE中。Java蓝牙API使得访问更多的系统成为可能。

    Java蓝牙API定义了两个包:一个是Java蓝牙API的核心javax.bluetooth,另一个是用于对象交换协议的javax.obex(OBEX)。

    根据JSR 82 规范,所有潜在蓝牙系统都必须支持蓝牙控制中心(BCC),该控制中心是一个控制面板,它的作用类似于可以让用户或OEM给堆栈中的某些配置参数定义具体值得应用程序,特别是,它将应用于堆栈初始化中。

    任何蓝牙应用都有以下这些组件:堆栈初始化组件,设备管理组件,设备发现组件,服务发现组件和通讯组件。

    堆栈初始化

    在开始无线通讯之前,你需要以销售商预订的方式初始化蓝牙设备。(具体的堆栈初始化步骤超出了蓝牙API规范的范围。)

    在一篇关于java与蓝牙技术起步的java.net文章中,Bruce Hopkins(java与蓝牙技术的作者)向我们介绍了在Atinav java蓝牙开发平台上是如何通过一系列设置完成初始化工作的。(见列表A),在JSR 82规范不包含这些调用,这一点很重要,因为其它的JSR82实现可能包括其它的初始化堆栈的方式。

    设备管理

    JSR82规范介绍了用于设备管理的两个类:LocalDevice 和 RemoteDevice.

    LocalDevice 允许你请求获得蓝牙设备的静态信息。它依靠javax.bluetooth.DeviceClass类来获得设备类型和它所提供的服务类型。

    RemoteDevice可用来获得蓝牙邻近区的设备信息(例如,某个远程蓝牙设备的地址)。它可以代表一台远程设备(例如,一台在可到达范围内的设备),并提供相应的方法来获得关于这台设备的有关信息,包括它的蓝牙地址和名称。

    每个蓝牙设备有一个唯一的硬件地址,像计算机的MAC地址一样。你可以设定设备发现的级别,通过调用LocalDevice 对象中的setDiscoverable()方法可以使得其它蓝牙设备发现当前设备。(见列表B

    设备发现

    无线设备需要一种机制来允许它们发现其它的设备并访问它们的功能。核心蓝牙API的DiscoveryAgent 类和DiscoveryListener接口提供了需要的发现服务。有三种方式获得可访问设备列表。DiscoveryAgent.startInquiry()方法可将设备设置为查询模式,为了充分利用这种模式,应用必须要指定一个事件监听器来对与查询相关的事件作出反应。当查询完成或取消时,会调用DiscoveryListener.inquiryCompleted()方法。

    如果一台设备不想等待发现其它的设备,可以使用DiscoveryAgent.retrieveDevices()方法来获得一个已经存在的列表。该方法或者返回一个在前面的查询中发现的设备列表,或者返回一个预知的设备列表,这些设备是由本地设备提前告诉蓝牙控制中心的它经常联系的设备。返回那种列表取决于传递的参数。列表C演示了最简单的一种方式,当检测到一台新的蓝牙设备时,对象需要使用DiscoveryAgent通过DiscoveryListener接口通知你。

    服务发现

    服务发现允许你发现附近的服务,而不管哪一台设备提供的该服务。DiscoveryAgent提供的方法可以用来发现蓝牙服务设备上的服务,并初始化服务发现事务。在服务可以被发现以前,必须首先在蓝牙服务设备上注册或广播该服务。服务设备负责完成很多任务,包括创建描述所提供的服务的服务记录,接受来自客户端的连接,向服务设备的服务发现数据库(SDDB)添加新的服务记录。总之,它的工作类似于web服务器。列表D是服务注册的一个例子。

    通讯

    两台设备必须共享通用的通讯协议才能通讯。为了应用能够访问更多的蓝牙服务,蓝牙java API提供了这样一个机制,它允许连接到使用RFCOMM, L2CAP, 或 OBEX协议的任何服务。如果服务使用了位于上面协议之上其它的协议(例如TCP/IP),只有在应用中利用CLDC通用连接框架实现额外的协议,才可以访问该服务。

    用于服务记录的URL包括数字和符号,大体是这样的结构:

    btspp://508031205080110F1B1B1D1C100:8.它的意思是客户应该使用蓝牙串口框架来建立到地址为508031205080110F1B1B1D1C100的设备的8号服务。设备地址和计算机的物理地址相似,列表E显示了简单的RFCOMM连接。

    Peter V. Mikhalenko是sun公司认证的专业IT人员,是Deutsche银行的业务顾问。

列表A


import javax.bluetooth.*;
import javax.microedition.io.*;
import com.atinav.bcc.*;

. . .
  BCC.setPortName("COM1");
  BCC.setBaudRate(57600);
  BCC.setConnectable(true);
  BCC.setDiscoverable(DiscoveryAgent.GIAC);
. . . 

列表B

. . . 
// retrieve the local Bluetooth device object
LocalDevice local = LocalDevice.getLocalDevice();
// retrieve the name of the local Bluetooth device
String name = local.getFriendlyName();
. . . 

列表C

. . .
LocalDevicelocaldevice = LocalDevice.getLocalDevice();
DiscoveryAgentdiscoveryAgent = localdevice.getDiscoveryAgent();
discoveryAgent.startInquiry(DiscoveryAgent.GIAC, this);
. . . 

列表D

...
// Service registration

// invoke Connector.open with a server connection URL argument
StreamConnectionNotifier service =
    (StreamConnectionNotifier) Connector.open("someURL");

// Obtain the service record created by the server device
ServiceRecordsr = local.getRecord(service);

// Indicate that the service is ready to accept a client connection.
//acceptAndOpen() blocks
//   until a client connects.
StreamConnection connection =
    (StreamConnection) service.acceptAndOpen();

// DO SOME EXCHANGE HERE

service.close(); 

列表E

...
String url =
    serviceRecord.getConnectionURL(
        record.NOAUTHENTICATE_NOENCRYPT, false);
// open a connection to the server
StreamConnection connection =
    (StreamConnection) Connector.open(url);
// Send/receive data
try {
    byte buf[] = new byte[200];
    String msg = "Test message";
    InputStream is = connection.openInputStream();
    OutputStreamos = connection.openOutputStream();
    // send data to the server
    os.write(msg.getBytes);
    // read data from the server
    is.read(buf);
    connection.close();
} catch(IOException e) {
    e.printStackTrace();
}
...