Android BLE 获取设备信息
最近需要做一个基于蓝牙设备的开发,在磕磕碰碰下基本完成任务要求,主要实现从蓝牙设备上获取需要的信息。下面是我对于蓝牙4.0 BLE 的一些浅白认识。
BLE 简单说明
BLE,低功耗蓝牙,主要由三部分组成,分别是Service、Characteristic以及Descriptor;其中三者是层级递减的包含关系,一个蓝牙4.0的设备可以包含n个Service,一个Service下可以包含n个Characteristic,一个Characteristic下可以包含n个Descriptor。每一个组成都有其唯一的UUID所标识。
开发实例
- 权限声明
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
Android 6.0及以上还需要位置权限,记得动态获取,没有位置权限将扫描不到BLE设备。
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
-
获取 BluetoothAdapter
通过BluetoothManager获取蓝牙适配器,或者可以通过BluetoothAdapter.getDefaultAdapter()获取默认的。通过bleAdapter 的值还可以判断是否支持蓝牙设备。
val bluetoothManager = getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
val bleAdapter = bluetoothManager.adapter
-
扫描BLE设备
1.bleAdapter.startDiscovery()扫描所有的蓝牙设备
2.bleAdapter.startLeScan()扫描所有的BLE设备(已过时)
3.通过BluetoothLeScanner对象调用startScan()方法进行扫描;而且startScan()和startLeScan()都需要自己实现扫描结果的回调。 -
连接BLE设备
在连接蓝牙设备前最好先停止蓝牙扫描,建立连接后会返回一个BluetoothGatt对象,这很重要,后面的读写和连接状态都需要它。
/**
* 连接蓝牙设备
*
* @param address 待连接设备的Mac地址
*/
fun connect(address: String) {
if (bleAdapter == null && address == null) {
return
}
var localBluetoothDevice = bleAdapter!!.getRemoteDevice(address)
// 如果连接存在先断开
if (bleGatt != null) {
bleGatt!!.disconnect()
bleGatt!!.close()
bleGatt = null
}
bleGatt = localBluetoothDevice.connectGatt(App.instance, false, bleGattCallback)
Log.d(TAG, "开始Ble连接")
}
代码中的bleGattCallback是蓝牙连接的回调,连接状态的监听、信号强度监听、收取数据监听、数据读写监听都可以在这里实现。本文只对连接蓝牙设备、通知蓝牙设备可以发送数据、获取蓝牙设备发送的数据这一过程进行说明。实现代码如下:
/**
* 与蓝牙通信回调
*/
private var bleGattCallback: BluetoothGattCallback = object : BluetoothGattCallback() {
/**
* 收到消息
*/
override fun onCharacteristicChanged(bluetoothGatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic) {
val arrayOfByte = characteristic.value
Log.d(TAG, "收到消息--- " + Arrays.toString(arrayOfByte))
}
/**
* 连接状态改变
*/
override fun onConnectionStateChange(bluetoothGatt: BluetoothGatt, oldStatus: Int, newStatus: Int) {
// 已连接状态,表明连接成功
if (newStatus == BluetoothProfile.STATE_CONNECTED) {
// 连接到蓝牙后查找可以读写的服务
bluetoothGatt.discoverServices()
return
}
// 断开连接或未连接成功
if (newStatus == BluetoothProfile.STATE_DISCONNECTED) {
return
}
// 避免其他情况出现,不满足条件的都断开连接
bluetoothGatt.disconnect()
bluetoothGatt.close()
return
}
// 找到Service
override fun onServicesDiscovered(gatt: BluetoothGatt?, status: Int) {
findService(gatt!!.services)
}
}
/**
* 搜索服务
*
* @param paramList
*/
fun findService(paramList: List<BluetoothGattService>) {
val serviceIterator = paramList.iterator()
while (serviceIterator.hasNext()) {
val localBluetoothGattService = serviceIterator.next()
if (localBluetoothGattService.uuid.toString().equals(Constant.JDY_TAG_SERVICE_UUID)) {
Log.d(TAG, "找到对应的蓝牙服务")
// 获取对应服务下所有的特征
val localList = localBluetoothGattService.characteristics
val charIterator = localList.iterator()
while (charIterator.hasNext()) {
val localBluetoothGattCharacteristic = charIterator.next() as BluetoothGattCharacteristic
if (localBluetoothGattCharacteristic.uuid.toString().equals(Constant.JDY_TAG_CHAR_DATA_UUID)) {
Log.d(TAG, "找到对应可读写特征")
bleGattCharacteristic = localBluetoothGattCharacteristic
// 获取对应特征下的Descriptor
val localDesList = localBluetoothGattCharacteristic.descriptors
val desIterator = localDesList.iterator()
while (desIterator.hasNext()) {
val localBluetoothGattDescriptor = desIterator.next() as BluetoothGattDescriptor
if (localBluetoothGattDescriptor.uuid.toString().equals(Constant.JDY_TAG_CHAR_DATA_DESP_UUID)) {
Log.d(TAG, "找到对应的descriptor")
bleGattDescriptor = localBluetoothGattDescriptor
break
}
}
break
}
}
break
}
}
// 启动本地通知
if (bleGatt!!.setCharacteristicNotification(bleGattCharacteristic, true)) {
Log.d(TAG, "Notification通知启动成功")
}
bleGattDescriptor?.value = BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE
if (bleGatt!!.writeDescriptor(bleGattDescriptor)) {
Log.d(TAG, "enable写入成功")
}
}
这里查找的Service、Characteristic以及Descriptor都是通过固定的UUID所获取的,具体的UUID可以向硬件部询问。