以下是我研究的蓝牙代码,因为时间紧没怎么好好的测试,目前在wtk2.2上运行通过,真机还有些问题。等我调试后再放更新版本,不过对初学者来说,这些应该足够了。也欢迎学过蓝牙的朋友一起讨论该项技术,指出错误。谢谢。代码分为3个类,一个主类,一个服务器端,一个客户端。以下是代码:
package myblue;
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;public class BlueMIDlet extends MIDlet implements CommandListener
{
static BlueMIDlet instance;
BlueClientBox blueClientBox = null; //客户端实例
BlueServerBox blueServerBox = null; //服务端实例
List list = null; //列表实例
public static boolean isClose = false; //是否关闭连接
public static Object lock = new Object();
public BlueMIDlet()
{
instance = this;
} public void startApp()
{
list = new List("蓝牙聊天软件", List.IMPLICIT);
list.append("客户端", null);
list.append("服务端", null);
list.setCommandListener(this);
Display.getDisplay(this).setCurrent(list);
} public void pauseApp()
{
} public void destroyApp(boolean unconditional)
{
} public static void quitApp()
{
instance.destroyApp(true);
instance.notifyDestroyed();
instance = null;
} public void commandAction(Command command, Displayable displayable)
{
if (command == list.SELECT_COMMAND)
{
if (list.getSelectedIndex() == 0)
{ //运行客户端
blueClientBox = new BlueClientBox();
Display.getDisplay(this).setCurrent(blueClientBox);
}
else if (list.getSelectedIndex() == 1)
{ //运行服务端
blueServerBox = new BlueServerBox();
Display.getDisplay(this).setCurrent(blueServerBox);
}
}
}
}package myblue;
import javax.microedition.lcdui.*;
import javax.bluetooth.DiscoveryAgent;
import javax.bluetooth.LocalDevice;
import javax.bluetooth.*;
import java.util.Vector;
import javax.microedition.io.*;
import java.io.*;public class BlueClientBox extends Form implements Runnable, CommandListener,DiscoveryListener
{
//消息框
private TextField textField = null;
//反馈框
private StringItem stringItem = null;
//发送按钮
private Command comOk = null;
//返回按钮
private Command comBack = null;
/**
设备发现:
使用DiscoveryAgent类的"设备发现"方法来开始和取消设备发现:
.retrieveDevices()重新获得已经发现或者附近的已知设备
.startInquiry() 启动发现附近设备,也叫inquiry
.cancelInquiry()取消当前进行的任何请求
蓝牙发现代理在请求阶段的不同时候会分别调用DiscoveryListener(发现监听器)不同的回调方法:
.deviceDiscovered() 指出是否有设备被发现。
.inquiryCompleted() 指出是否请求已经成功、触发一个错误或已被取消。
设备发现以调用startInquiry()函数开始。
在请求进行时,蓝牙发现代理会在适当的时候调用回调方法DeviceDiscovered()和inquiryCompleted()。
服务发现:
可以使用发现代理的服务发现方法来开始或取消服务发现:
.selectService()启动服务发现搜索。(原文有误,根据API手册应为尝试定位一个服务)
.searchServices()启动服务发现搜索。
.cancelServiceSearch()取消在正在进行中的任何的服务发现搜索操作。
蓝牙发现代理在服务发现阶段的不同时候会分别调用DiscoveryListener的服务发现回调方法:
.servicesDiscovered() 表示是否服务已被发现。
.serviceSearchCompleted()表示服务发现是否已经完成。
服务发现的状态改变结束于DiscoveryListener的回调方法的返回。
服务发现开始于对searchServices()的调用。当服务搜索进行时,
蓝牙发现代理会在适当的时候回调servicesDiscovered()和 serviceSearchCompleted()方法。
*/
//设备发现代理
private DiscoveryAgent discoverAgent = null; /**
LocalDevice类标识了本地蓝牙设备。蓝牙应用程序和LocalDevice之间的关系是典型的一对一关系:
本地设备提供了方法来返回关于本地设备的信息,并且能够进入Bluetooth manager:
.getBluetoothAddress()返回蓝牙设备地址。
.getDeviceClass()返回设备类。
.getFriendlyName()返回设备友好名称,蓝牙设备名通常是用户在蓝牙控制中心为其设置的。
.getRecord()返回一个指定蓝牙连接的服务记录。
.updateRecord()方法用来为指定的ServiceRecord更新SDDB服务记录。
.getDiscoverable()返回设备的可发现状态。
.setDiscoverable()设置设备的可发现状态。
.getDiscoveryAgent()返回一个参考给发现代理。
.getProperty()返回一个设备的蓝牙属性
通过调用getProperty()方法你可以得到的属性包括:
.bluetooth.api.version,蓝牙API版本
.bluetooth.sd.attr.retrievable.max,一次性能够被获得的服务记录属性的最大值
.bluetooth.connected.devices.max,支持的连接设备的最大值
.bluetooth.sd.trans.max,同时发生的服务发现处理的最大值
.bluetooth.l2cap.receiveMTU.max,L2CAP最大发射单元
*/
//本地蓝牙设备实例
private LocalDevice localDevice = null; /**
一个RemoteDevice的实例代表了一个远端蓝牙设备。
在一个蓝牙客户端应用程序可以进行服务,消费之前,它必须发送一个设备请求来发现远端设备。
典型的蓝牙应用程序和远端设备之间的关系是一对多:
远端设备(RemoteDevice)提供的方法中,有些很类似于本地设备(LocalDevice)里提供的方法:
.getBluetoothAddress()返回蓝牙地址。
.getFriendlyName()返回蓝牙设备名。
.getRemoteDevice()返回相应的被指定蓝牙连接的远端设备。
.authenticate()尝试识别验证远端设备。
.authorize()为指定的蓝牙连接去尝试批准远端设备访问本地设备。
.encrypt()尝试为指定的蓝牙连接开启或关闭加密。
.isAuthenticated()测试是否远端设备可以被验证。
.isAuthorized()测试是否远端设备已经被蓝牙控制中心授权访问本地设备以进行蓝牙连接。
.isEncrypted()测试是否本地设备和远端设备之间的通信被加密。
.isTrustedDevice()测试是否远端设备被蓝牙控制中心指定为可信任的。
*/
//远端设备实例
private RemoteDevice remoteDevice = null; /**
在蓝牙中,每个服务和服务属性都唯一地由"全球唯一标识符" (UUID)来校验。
正如它的名字所暗示的,每一个这样的标识符都要在时空上保证唯一。
UUID类可表现为短整形(16或32位)和长整形(128位)UUID。
他提供了分别利用String和16位或32位数值来创建类的构造函数,
提供了一个可以比较两个UUID(如果两个都是128位)的方法,
还有一个可以转换一个UUID为一个字符串的方法。UUID实例是不可改变的(immutable),
只有被UUID标示的服务可以被发现。
在Linux下你用一个命令uuidgen -t可以生成一个UUID值;
在Windows下则执行命令uuidgen 。
UUID看起来就像如下的这个形式:2d266186-01fb-47c2-8d9f-10b8ec891363。
当使用生成的UUID去创建一个UUID对象,你可以去掉连字符。
*/
//全球唯一标识符
private UUID[] uuid = null; /**
.authenticate验证一个连接设备的身份。
.authorize授权一个连接中的设备(已被识别)是否被允许进入。
.encrypt指定连接需被加密。
你已经看到了想要连接到一个服务的客户端可以通过调用
ServiceRecord.getConnectionURL()方法以获得服务连接的URL。该方法中的一个参数requiredSecurity,
指定了返回的这个连接URL是否应该包含可选的authenticate和encrypt等安全参数。关于requiredSecurity的有效值为:
.ServiceRecord.NOAUTHENTICATE_NOENCRYPT意为authenticate=false; encrypt=false。
.ServiceRecord.AUTHENTICATE_NOENCRYPT意为authenticate=true; encrypt=false。
.ServiceRecord.AUTHENTICATE_ENCRYPT意为authenticate=true; encrypt=true。
*/
//
ServiceRecord serviceRecord = null;
//设备容器
private Vector device = null;
//服务容器
public Vector service = null;
//连接实例
StreamConnection streamConnection = null;
//实例化输出流
DataOutputStream dataOutputStream = null;
//实例化输入流
DataInputStream dataInputStream = null;
//用于蓝牙连接的url
String url = null;
//接收阻塞标记
private boolean blSend = false; public BlueClientBox()
{
super("客户端");
this.textField = new TextField("", "", 50, TextField.ANY);
this.stringItem = new StringItem("反馈:", "");
this.comOk = new Command("发送", Command.OK, 1);
this.comBack = new Command("退出", Command.EXIT, 2);
this.append(textField);
this.append(stringItem);
this.addCommand(comOk);
this.addCommand(comBack);
this.setCommandListener(this);
this.device = new Vector();
this.service = new Vector();
new Thread(this).start();
} public void commandAction(Command command, Displayable displayable)
{
if (command.getCommandType() == Command.EXIT)
{
BlueMIDlet.isClose = true;
this.clear();
BlueMIDlet.quitApp();
}
else if(command.getCommandType() == Command.OK)
{
this.blSend = true;
Thread fetchThread = new Thread()
{
public void run()
{
//发送消息
sendMessage();
}
};
fetchThread.start();
}
} public void run()
{
//midp2.0进度条(持续动画状态)
Gauge gauge = new Gauge(null,false,Gauge.INDEFINITE,Gauge.CONTINUOUS_RUNNING);
this.append(gauge); //开始搜索服务端蓝牙设备
this.stringItem.setText("开始搜索蓝牙设备...");
startSearchDevices();
try
{
synchronized(this)
{
wait();
}
}
catch (InterruptedException ex)
{
ex.printStackTrace();
}
this.stringItem.setText("共找到:"+device.size()+"个蓝牙设备开始搜索服务..."); //开始搜索远端设备提供的服务
startSearchServices();
try
{
synchronized(this)
{
wait();
}
}
catch (InterruptedException ex)
{
ex.printStackTrace();
}
this.stringItem.setText("共找到:"+service.size()+"个服务开始发送信息。");
url = serviceRecord.getConnectionURL(ServiceRecord.NOAUTHENTICATE_NOENCRYPT,false);
try
{
streamConnection = (StreamConnection)Connector.open(url);
dataOutputStream = streamConnection.openDataOutputStream();
dataInputStream = streamConnection.openDataInputStream();
}
catch (IOException ex1)
{
}
//删除进度条
this.delete(2);
while(true)
{
if(this.blSend)
{
try
{
synchronized(this)
{
wait();
}
}
catch (InterruptedException ex)
{
ex.printStackTrace();
}
}
this.receiveMessage();
}
} /**
* 蓝牙设备发现
*/
private void startSearchDevices()
{
try
{
//获得本地设备
localDevice = LocalDevice.getLocalDevice();
//获得发现代理
discoverAgent = localDevice.getDiscoveryAgent();
discoverAgent.startInquiry(DiscoveryAgent.GIAC,this);
}
catch (BluetoothStateException ex)
{
ex.printStackTrace();
}
} /**
* 发送消息
* @param serviceRecord 服务记录
*/
public boolean sendMessage()
{
//获得一个连接远端设备的url
try
{
//发送数据
dataOutputStream.writeUTF(textField.getString());
}
catch (IOException ex)
{
ex.printStackTrace();
return false;
}
synchronized(this)
{
notify();
}
this.blSend = false;
return true;
} /**
* 接收消息
* @param serviceRecord ServiceRecord 服务记录
*/
public boolean receiveMessage()
{
try
{
//接收数据
if (dataInputStream != null)
{
String text = dataInputStream.readUTF();
stringItem.setText(text); //dataInputStream This method blocks until input data is available
}
}
catch (IOException ex)
{
ex.printStackTrace();
return false;
}
return true;
}
/**
* 远端设备服务发现
*/
private void startSearchServices()
{
uuid = new UUID[2];
uuid[0] = new UUID(0x1101);
uuid[1] = new UUID("F0E0D0C0B0A000908070605040302010",false); for(int i = 0; i<device.size(); i++)
{//取出已经搜到的远端设备
remoteDevice = (RemoteDevice)device.elementAt(i);
try
{//搜索该设备上的服务
discoverAgent.searchServices(null, uuid, remoteDevice, this);
}
catch (BluetoothStateException ex)
{
}
}
}
/**
* 设备发现过程中的回调(用来查找每一个可用的设备)
* @param remoteDevice RemoteDevice
* @param deviceClass DeviceClass
*/
public void deviceDiscovered(RemoteDevice remoteDevice,DeviceClass deviceClass)
{
if(device.indexOf(remoteDevice) == -1)
{
device.addElement(remoteDevice);
}
}
/**
* 设备发现完成回调(用来标识设备查找是否完成)
* @param _int int
*/
public void inquiryCompleted(int _int)
{
synchronized (this)
{
notify();
}
}
/**
* 服务发现回调(用来发现远端设备上的可用服务)
* @param _int int
* @param serviceRecordArray ServiceRecord[]
*/
public void servicesDiscovered(int _int, ServiceRecord[] serviceRecordArray)
{
for (int i = 0; i < serviceRecordArray.length; i++)
{
service.addElement(serviceRecordArray[i]);
serviceRecord = serviceRecordArray[i];
}
}
/**
* 服务发现回调(用来标识服务搜索是否完成)
* @param _int int
* @param _int1 int
*/
public void serviceSearchCompleted(int _int, int _int1)
{
synchronized (this)
{
notify();
}
}
/**
* 断开连接
*/
private void clear()
{
try
{
dataInputStream.close();
dataOutputStream.close();
discoverAgent.cancelInquiry(this);
discoverAgent.cancelServiceSearch(0);
streamConnection.close();
}
catch (IOException ex)
{
}
}}
package myblue;
import javax.microedition.lcdui.*;
import javax.bluetooth.LocalDevice;
import javax.bluetooth.ServiceRecord;
import javax.microedition.io.StreamConnectionNotifier;
import javax.bluetooth.*;
import javax.microedition.io.Connector;
import java.io.*;
import javax.microedition.io.StreamConnection;
import java.util.Vector;/**
*
* <p>Title: </p>
*
* <p>设置一个蓝牙服务器 </p>
* <p> 要设置一个能提供消费服务的蓝牙服务器,将有四个主要步骤:</p>
* <p> 1.创建一个你想要提供的可消费服务的服务记录, </p>
* <p> 2.增加一个新的服务记录到服务发现数据库, </p>
* <p> 3.注册服务。 </p>
* <p> 4.等候客户端的引入连接。 </p>
* <p> 两个有重要意义的相关操作: </p>
* <p> 1.修改服务记录,如果服务属性能使客户端可视需要改变; </p>
* <p> 2.当所有的都做了,从SDDB移除服务记录。 </p>
* <p>Copyright: Copyright (c) 2007</p>
*
* <p>Company: </p>
*
* @author sld
* @version 1.0
*/
public class BlueServerBox extends Form implements Runnable, CommandListener
{
//消息发送框
private TextField textField = null;
//消息反馈框
private StringItem stringItem = null;
//发送按钮
private Command cmdOk = null;
//退出按钮
private Command cmdExit = null;
//本地设备类实例
private LocalDevice localDevice = null;
//服务记录实例
private ServiceRecord serviceRecord = null;
//服务通告实例
private StreamConnectionNotifier notifier = null;
//蓝牙服务url
private String url = "btspp://localhost:F0E0D0C0B0A000908070605040302010;name=BTServer;authorize=false";
//连接实例
private StreamConnection streamConnection = null;
//输出数据流
private DataOutputStream dataOutputStream = null;
//输入数据流
private DataInputStream dataInputStream = null;
//连接容器
public Vector connect = null;
//接收阻塞标记
private boolean blSend = false; public BlueServerBox()
{
super("Displayable Title");
textField = new TextField("服务器端","",50,TextField.ANY);
stringItem = new StringItem("反馈:","");
cmdOk = new Command("发送",Command.OK,1);
cmdExit = new Command("退出",Command.EXIT,2);
this.addCommand(cmdOk);
this.addCommand(cmdExit);
this.append(textField);
this.append(stringItem);
this.setCommandListener(this);
connect = new Vector();
new Thread(this).start();
} public void commandAction(Command command, Displayable displayable)
{
if(command.getCommandType() == Command.EXIT)
{
BlueMIDlet.isClose = true;
this.clear();
BlueMIDlet.quitApp();
}
else if(command.getCommandType() == Command.OK)
{
this.blSend = true;
Thread fetchThread = new Thread()
{
StreamConnection streamConnection = null;
public void run()
{
sendMessage();
}
};
fetchThread.start();
}
} public void run()
{
try
{
//得到本地设备
this.localDevice = LocalDevice.getLocalDevice();
this.localDevice.setDiscoverable(DiscoveryAgent.GIAC);
}
catch (BluetoothStateException ex)
{
ex.printStackTrace();
} try
{
//获得客户端连接通告
notifier = (StreamConnectionNotifier)Connector.open(this.url);
}
catch (IOException ex1)
{
ex1.printStackTrace();
}
//获得服务记录
serviceRecord = localDevice.getRecord(notifier); StreamConnection conn = null;
try
{
//从通告获得远端蓝牙设备的连接
conn = notifier.acceptAndOpen();
dataOutputStream = conn.openDataOutputStream();
dataInputStream = conn.openDataInputStream();
}
catch (IOException ex2)
{
}
while(true)
{
if(this.blSend)
{
try
{
synchronized(this)
{
wait();
}
}
catch (InterruptedException ex)
{
ex.printStackTrace();
}
}
this.receiveMessage();
}
} /**
* 发送消息
*/
public void sendMessage()
{
try
{
dataOutputStream.writeUTF(textField.getString());
}
catch (IOException ex)
{
ex.printStackTrace();
}
this.blSend = false;
synchronized(this)
{
notify();
}
}
/**
* 接收消息
*/
public void receiveMessage()
{
try
{
if (dataInputStream != null)
{
String text = dataInputStream.readUTF();
this.stringItem.setText(text); //This method blocks until input data is available
}
}
catch (IOException ex)
{
ex.printStackTrace();
}
}
/**
* 断开连接
*/
private void clear()
{
try
{
dataOutputStream.close();
dataInputStream.close();
}
catch (IOException ex)
{
} }
}