Android BLE开发 —— Jetpack Bluetooth

5,089 阅读2分钟

1、简介

JetPack 出了 Bluetooth的 新库, 包含了对 经典蓝牙和 低功耗蓝牙的支持。

pk0HleP.png

目前最新的版本为 1.0.0-alpha02。

1.0简介.png

这个库主要是使用了Kotlin 和 协程,封装了对蓝牙的操作,简化开发者对蓝牙的使用。

地址:developer.android.com/jetpack/and…

2、集成

dependencies {
    
    implementation "androidx.bluetooth:bluetooth:1.0.0-alpha02"
}

申请需要的权限:

    <!--建立蓝牙连接和传输权限-->
    <uses-permission android:name="android.permission.BLUETOOTH"/>
    <!--扫描蓝牙设备或修改蓝牙设置权限-->
    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
    <!--Android 6.0及后续版本扫描蓝牙,需要定位权限(进入GPS设置,可以看到蓝牙定位)-->
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
    <uses-permission android:name="android.permission.BLUETOOTH_CONNECT"/>

Android6.0 以上需要动态定位权限。

包结构:

pk0H9MR.png

可以看出大部分由Kotlin进行了重写。

3、扫描

首先开始扫描操作:

        // 初始化 BluetoothLe
        val bluetoothLe = BluetoothLe(context)

        // 根据serviceUuid和deviceName 过滤条件进行扫描
        val scanFlow = bluetoothLe.scan(listOf(ScanFilter(
            serviceDataUuid = UUID.fromString("XXX"),
            deviceName = "XXX"
        )))

        // 扫描到的结果
        scanFlow.collect {
            Log.d("MainActivity", "scan result: $it ${it.device.name} ${it.rssi}")
      
        }

可以看出通过调用 bluetoothLe.scan 返回了 一个Kotlin协程的 Flow<ScanResult> 对象。

和之前的 BLE API 一样, 支持对设备扫描的条件进行配置, 可以配置 serviceId, deviceName, MAC地址等信息。

ScanFilter.png

然后 通过扫描的 ScanResult结果可以拿到设备信息, 如支持的服务 serviceUuids, 信号强度 rssi等信息

ScanResult.png

扫描到结果后, 不需要我们手动去关闭扫描。会自动关闭扫描 .png

可以看出新出的这个蓝牙库, 比之前的扫描操作代码少了很多, 也简洁了很多。

4、连接

扫描到设备后, 对设备进行发起连接操作

        val bluetoothLe = BluetoothLe(context)
        // 连接设备, device是刚才扫描到的设备
        bluetoothLe.connectGatt(device) {
            // 获取服务
            getService(UUID.fromString("XXX"))



            // 订阅
            getService(UUID.fromString("XXX"))?.getCharacteristic(UUID.fromString("XXX"))?.let {
                subscribeToCharacteristic(it).collect {
                    // 收到数据
                    Log.d("MainActivity", "subscribe result: $it")
                }
            }

            // 读取数据
            getService(UUID.fromString("XXX"))?.getCharacteristic(UUID.fromString("XXX"))?.let {
                readCharacteristic(it)
            }

            // 写入数据
            getService(UUID.fromString("XXX"))?.getCharacteristic(UUID.fromString("XXX"))?.let {
                writeCharacteristic(it, "XXX".toByteArray())
            }
            
        }

调用 BluetoothLeconnectGatt方法,发起连接。在连接的回调中, 可以进行获取服务, 订阅, 读取数据, 写入数据等操作。

可以看出相比之前 在 BluetoothGattCallback回调中进行操作, 简洁了很多。

5、增大MTU

在这个库中, 在连接成功时,自动帮我们增大了MTU为,512 + 3

MTU.png

没有发现提供给开发者增大MTU的API, 也没有返回 GATT 对象的接口, 需要动态改变合适的MTU还是需要使用之前的API, 这个库要支持的话,估计要等官方后续更新完善了。

6、源码探索

6.1 BluetoothLe

BluetoothLe是操作的核心类, 主要提供了扫描和连接的API接口。

1.png 可以看到 scan方法调用了ScanImpl 的scan方法, connectGatt方法调用了GattClient的 connect方法。

6.2 ScanImplBase 的scan

2.png

底层还是使用 BluetoothLeScanner 进行扫描操作,将过滤条件放进 BluetoothLeScanner中, 扫描到设备后发送数据, collect处理之后 关闭扫描。

6.3 GattClient的 的connect

last.png

本质上还是调用了之前的API,BluetoothDevice 的 connectGatt, 并结合携程 和 flow 包装返回一个 GattClientScope的作用域, 在这个作用域中可以进行 writeCharacteristic、readCharacteristic等操作。

本质是并没有引入新的底层BLE API操作,还是使用了之前的那一套 BLE API操作, 在此基础上,使用了Kotlin, 协程,Flow等 对其进行了封装, 是开发者用起来更加简洁, 关注于业务。