蓝牙串口模块是嵌入式设备上的常用模块,它可以方便地和手机建立连接,实时传输数据。本文介绍Android设备与蓝牙串口通信的具体实现。
一、流程图
本文以Android蓝牙客户端为例介绍从打开蓝牙到收发数据的完整流程,对蓝牙服务端程序不作介绍,请读者举一反三。下图为Android蓝牙客户端的流程图。
下面分步详细介绍。文中只给出每一步的关键代码,整个例程的完整代码将在文末给出。
二、打开蓝牙
通过启动指定的Action来请求系统打开蓝牙。这几行代码的效果相当于点击手机顶部下拉框中的蓝牙按钮。
// 获取蓝牙适配器
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
//请求开启蓝牙
if (!mBluetoothAdapter.isEnabled()) {
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
}
三、搜索设备
首先找出已匹配的蓝牙设备列表。
// 将已配对的设备添加到列表中
Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices();
if (pairedDevices.size() > 0) {
for (BluetoothDevice device : pairedDevices) {
mDevicesArray.add(device.getName() + "\n" + device.getAddress());
deviceList.add(device);
}
}
再开始搜索附近的蓝牙设备,创建一个广播接收器以获取搜索结果。
// 注册广播接收器,以获取蓝牙设备搜索结果
IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
registerReceiver(mReceiver, filter); // Don't forget to unregister during onDestroy
// 搜索蓝牙设备
mBluetoothAdapter.startDiscovery();
这里用到的广播接收器定义如下。注意最后需要调用notifyDataSetChanged
方法,否则新搜索到的设备不会更新到ListView中。
// Create a BroadcastReceiver for ACTION_FOUND
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
// When discovery finds a device
if (BluetoothDevice.ACTION_FOUND.equals(action)) {
// Get the BluetoothDevice object from the Intent
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
deviceList.add(device);
// Add the name and address to an array adapter to show in a ListView
mDevicesArray.add(device.getName() + "\n" + device.getAddress());
// Notify ListView to update
devicesListAdapter.notifyDataSetChanged();
}
}
};
四、匹配并建立连接
通过调用BluetoothDevice对象的createRfcommSocketToServiceRecord
方法可以获取一个socket。该方法需要传入蓝牙设备的UUID。通常,对于不同的服务需要设置不同的UUID,本文设置为针对蓝牙串口服务的UUID,其它常用的UUID可见文末的参考资料。成功获得socket对象之后,调用其上的connet
方法即可匹配并建立连接。在Android系统中,不需要执行单独的匹配操作,建立连接时,系统会自动对未匹配的设备尝试匹配,必要时会要求用户输入Pin码。
BluetoothSocket socket = null;
try {
// 蓝牙串口服务对应的UUID。如使用的是其它蓝牙服务,需更改下面的字符串
UUID MY_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
socket = device.createRfcommSocketToServiceRecord(MY_UUID);
} catch (Exception e) {
Log.d("log", "获取Socket失败");
return;
}
try {
// Connect the device through the socket. This will block
// until it succeeds or throws an exception
socket.connect();
Log.d("log", "连接成功");
} catch (IOException connectException) {
// Unable to connect; close the socket and get out
Log.d("log", "连接失败");
try {
socket.close();
} catch (IOException closeException) { }
return;
}
五、收发数据
只需要从socket中获取输入输出流,再调用read和write方法就可以实现数据的发送与接收。原理很简单,不过具体使用时需要考虑如何循环读取数据。一般是创建一个新线程专门用于读取数据,否则read方法将会阻塞主线程。下面的代码只说明了数据收发的基本用法。
mmInStream = socket.getInputStream();
mmOutStream = socket.getOutputStream();
//接收数据
byte[] buffer = new byte[1024];
try {
bytes = mmInStream.read(buffer);
} catch (IOException e) {
break;
}
//发送数据
try {
mmOutStream.write(bytes);
} catch (IOException e) { }
六、总结
本文把Android与蓝牙串口通信的整个流程做了最大程度上的简化,只突出核心功能代码。而具体应用时则需要考虑更多的实际情况,包括界面的布局等等。关于Android系统针对蓝牙设备提供的API的总体介绍,建议阅读参考资料中的第一篇。
完整代码下载地址:https://github.com/jingedawang/BluetoothDemo
下图是在华为手机上的运行效果。
七、参考资料
Android经典蓝牙开发简介 Chuckiefan
关于蓝牙服务对应的UUID码 ZF_Chen