蓝牙通信是我们日常生活中比较方便的一种通信技术,Android从2.0版本的SDK就开始支持蓝牙。对开发人员来说,应用程序中蓝牙还是一种用来创建点对点连接通信的简单而高效的方式。
之前讨论过蓝牙设备搜索的解决方案,今天在这个基础上进行蓝牙设备搜索之后创建连接的学习。
Android模拟器还不支持蓝牙,因此要测试使用蓝牙功能,必须使用至少两台Android设备。
(1)关于UUID
要创建蓝牙连接,首先要确保客户端程序的UUID和服务器端的UUID相同才能进行连接。但是UUID并不是蓝牙技术的特有标准,UUID含义是通用唯一识别码 (Universally Unique Identifier),这是一个软件建构的标准。以下给出常用的蓝牙服务对应的UUID码:
- 蓝牙串口服务 00001101-0000-1000-8000-00805F9B34FB
- 拨号网络服务 00001103-0000-1000-8000-00805F9B34FB
- 信息同步服务 00001104-0000-1000-8000-00805F9B34FB
- 文件传输服务 00001106-0000-1000-8000-00805F9B34FB
- 个人局域网服务 00001115-0000-1000-8000-00805F9B34FB
用于测试或个人使用的蓝牙服务,可到Online UUID Generator进行申请,直接打开网页即可获得一个UUID码。
(2)建立连接
确保服务器端和客户端所指定的UUID码相同之后,即可开始建立连接。Android创建蓝牙连接是通过BluetoothSocket来进行,这个过程要使用的类有两个,BluetoothServerSocket和BluetoothSocket。
BluetoothServerSocket
蓝牙通信服务器端类,蓝牙通信过程类似于Socket,当两台蓝牙设备连接配对之后,服务器端通过accept()方法来建立BluetoothSocket。
BluetoothSocket
这是服务器和客户端通信的通道,常用的方法有:
close() 关闭
connect() 连接
getInptuStream() 获取输入流
getOutputStream() 获取输出流
getRemoteDevice() 获取远程设备,这里指的是获取bluetoothSocket指定连接的那个远程蓝牙设备
需要注意的是,服务器端进行监听客户端连接(BluetoothServerSocket.accept())和客户端进行对服务器的连接(BluetoothSocket.connect())都会阻塞线程,因此都应使用新的线程进行。
服务器端蓝牙连接步骤:
- 启动服务器
private static final UUID UUID_SERVER = UUID.fromString("2b21619a-e2d4-4108-aab5-b64c48906552");
BluetoothAdapter bAdapter = BluetoothAdapter.getDefaultAdapter();
BluetoothServerSocket serverSocket = bAdapter.listenUsingRfcommWithServiceRecord("Server", UUID_SERVER);
- 服务器监听客户端连接
serverSocket.accept();
因为线程阻塞,所以要使用新线程进行蓝牙连接。
private static final UUID UUID_SERVER = UUID.fromString("2b21619a-e2d4-4108-aab5-b64c48906552");
private BluetoothAdapter bAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
//...
new ServerStart().start(); //开启蓝牙服务器
}
class ServerStart extends Thread {
@Override
public void run() {
try {
BluetoothServerSocket serverSocket = bAdapter.listenUsingRfcommWithServiceRecord("Server", UUID_SERVER);
//服务器打开成功
//...
while (true) {
serverSocket.accept(); //服务器等待客户端访问,线程阻塞
//客户端接入访问成功
//...
}
} catch (Exception e) {
}
}
}
客户端蓝牙连接步骤:
获取服务器端蓝牙设备的BluetoothDevice
客户端进行对服务器的连接
private static final UUID UUID_CLIENT = UUID.fromString("2b21619a-e2d4-4108-aab5-b64c48906552");
BluetoothSocket socket = device.createRfcommSocketToServiceRecord(UUID_CLIENT);
socket.connect();
因为线程阻塞,所以要使用新线程进行蓝牙连接。
private static final UUID UUID_CLIENT = UUID.fromString("2b21619a-e2d4-4108-aab5-b64c48906552");
List<BluetoothDevice> devices = new ArrayList<>();
private BroadcastReceiver searchReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
//搜索到设备
if(BluetoothDevice.ACTION_FOUND.equals(action)) {
BluetoothDevice dev = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); //获取蓝牙设备信息
devices.add(dev);
}
//搜索完成
else if(BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) {
//搜索结果列表,对话框呈现
AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
builder.setTitle("搜索到的蓝牙设备列表");
final String[] item = new String[devices.size()];
int n = item.length;
//遍历搜索结果
for(int i = 0; i < n; i ++) {
item[i] = devices.get(i).getName()+"\t:\t"+devices.get(i).getAddress();
}
builder.setItems(item, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
new ClientConnect(devices.get(which)).start(); //启动蓝牙连接线程
}
});
builder.create().show();
}
}
};
class ClientConnect extends Thread {
BluetoothDevice device;
public ClientConnect(BluetoothDevice dev) {
device = dev;
}
@Override
public void run() {
try {
BluetoothSocket socket = device.createRfcommSocketToServiceRecord(UUID_CLIENT);
socket.connect(); //线程阻塞
//连接成功
//...
} catch (Exception e) {
//连接失败
//...
}
}
}
(3)运行结果
服务器启动:
客户端搜索服务器:
客户端发起蓝牙连接:
客户端连接到服务器&服务器接收到服务器请求: