作者博客
http://www.jianshu.com/u/f2a928cacb8d
源码地址
https://github.com/Alex-Jerry/BleDemo
文章目录
1
前言
随着物联网时代的到来,越来越多的智能硬件设备开始流行起来,比如智能手环、心率检测仪、以及各式各样的智能家具和玩具类产品。安卓4.3(API 18)为BLE的核心功能提供平台支持和API,App可以利用它来发现设备、查询服务和读写特性。相比传统的蓝牙,BLE更显著的特点是低功耗。本文主要讲解Android低功耗蓝牙的api使用以及蓝牙扫描、连接、发送数据、接收数据等一系列操作,并主要介绍本人封装的BleLib蓝牙库,非常适合蓝牙初学者使用,只需要一行代码注入就OK了,而且用法也极其简单,下面会专门讲解BleLib库的使用。
2
原生API的详细讲解
在BLE协议中,有两个角色,周边(Periphery)和中央(Central);周边是数据提供者,中央是数据使用/处理者,一个中央可以同时连接多个周边,但是一个周边某一时刻只能连接一个中央。
首先使用蓝牙就不得不说BluetoothGatt和BluetoothGattCallback这两个类,该类继承自BluetoothProfile,BluetoothGatt作为中央来使用和处理数据,通过BluetoothGatt可以连接设备(connect),发现服务(discoverServices),并把相应地属性返回到BluetoothGattCallback,BluetoothGattCallback返回中央的状态和周边提供的数据。
1. 蓝牙开发流程:
我们蓝牙操作的主要目的就是为了拿到中央BluetoothGatt这个对象,进而进行接下来的所有一系列操作,如下:
这时总算拿到中央BluetoothGatt了,它有很多的方法,调用这些方法,你就可以通过BluetoothGattCallback和周边BluetoothGattServer交互了。
2. 主要类的大致理解:
BluetoothProfile: 一个通用的规范,按照这个规范来收发数据。
BluetoothManager:通过BluetoothManager来获取BluetoothAdapter
如:BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
BluetoothAdapter:一个Android系统只有一个BluetoothAdapter ,通过BluetoothManager 获取
BluetoothAdapter mBluetoothAdapter = bluetoothManager.getAdapter();
BluetoothGattDescriptor:可以看成是描述符,对Characteristic的描述,包括范围、计量单位等。
BluetoothGattService:服务,Characteristic的集合。
BluetoothGattCallback:已经连接上设备,对设备的某些操作后返回的结果。这里必须提醒下,已经连接上设备后的才可以返回,没有返回的认真看看有没有连接上设备。
3. 上面所说的9个要实现的方法,所对应蓝牙交互的主要对应关系:
(1) notification对应onCharacteristicChanged;
gatt.setCharacteristicNotification(characteristic, true);
该方法一般是在发现服务后,进行设置的,设置该方法的目的是让硬件在数据改变的时候,发送数据给app,app则通过onCharacteristicChanged方法回调给用户,从参数中可获取到回调回来的数据。
(2) readCharacteristic对应onCharacteristicRead;
gatt.readCharacteristic(characteristic);
(3) writeCharacteristic对应onCharacteristicWrite;
gatt.wirteCharacteristic(mCurrentcharacteristic);
(4) 连接蓝牙或者断开蓝牙 对应 onConnectionStateChange;
(5) readDescriptor对应onDescriptorRead;
(6) writeDescriptor对应onDescriptorWrite;
gatt.writeDescriptor(descriptor);
(7) readRemoteRssi对应onReadRemoteRssi;
gatt.readRemoteRssi()
(8) executeReliableWrite对应onReliableWriteCompleted;
(9) discoverServices对应onServicesDiscovered
gatt.discoverServices()
开启蓝牙所具备的权限:
如果 android.hardware.bluetooth_le设置为false,可以安装在不支持的设备上使用,判断是否支持蓝牙4.0用以下代码就可以了,如:
对蓝牙的启动关闭操作:
1、利用系统默认开启蓝牙对话框
2、后台打开蓝牙,不做任何提示,这个也可以用来自定义打开蓝牙对话框啦
mBluetoothAdapter.enable();
3、后台关闭蓝牙
mBluetoothAdapter.disable();
3
BleLib库的优点
最简洁的植入(近乎一行代码)
哦!不好意思,说错话了,好像是两行代码哈
最大程度简化了代码量
有对比才有伤害,那就来看下原生api调用蓝牙流程和该库之间的对比:
例如扫描设备(原生写法 vs BleLib写法)
原生API写法:
BleLib写法
提供了独一无二的OTA升级接口(即蓝牙硬件进行更新升级的接口)
这绝对是其他蓝牙库所没有的
易懂的回调方法
可随意实现自己需要的回调方法
也就是说上面的那些回调方法可以根据自己项目中的需求选择性实现
4
如何使用该库?
1. 初始化蓝牙(包含了动态授权蓝牙操作权限、打开蓝牙、判断设备是否支持蓝牙)
如果没有打开蓝牙,当点击打开蓝牙的提示框后,会在
该方法中收到回调信息,打开后则开启扫描,否则则根据你自己的需要进行操作。
2. 通过注册监听的方式,这里我们可以看到我们把lisenter的实例传进去,那么我们就会在这里得到蓝牙的所有回调监听,从而在此处进行各种操作。如下图(注:下面回调方法大多数都可以根据你的需要选择性实现,不需要可以不用实现):
当收到onChanged()回调时,则说明蓝牙设备的数据发生改变了,通知程序作出改变。
3. 发送数据到蓝牙设备
这里可以通过调用BleManager中的sendData()方法即可,只需要传入指定的蓝牙设备地址以及需要发送的字节数组即可,返回值是发送成功或者失败的布尔值。
5
BleLib库封装的详细分析
分析之前先来张BleLib库API的结构图供大家参考:
1、我们先来看一下该库的结构,以及每个类的作用。如下图:
这里先不讲解iQppCallback和QppApi两个类,这两个类暂时并未用到,后期维护时会详细讲解。
BleDevice:
该类的主要是来描述并记录蓝牙的属性和状态,如记录蓝牙名称、蓝牙MAC地址、蓝牙别名(即修改之后的名称)、蓝牙连接状态等。
BleConfig:
该类是蓝牙配置类,里面包含了蓝牙服务的UUID、蓝牙特征的UUID、描述的UUID、以及蓝牙状态的静态常量值的标记等等,其中蓝牙相关的UUID的设置是对外提供了接口的,用的时候可以自行传入特定的UUID即可。
BleLisenter:
该类提供了蓝牙各个状态的接口,此处做成了抽象类,目的是为了可以让用户有条件的去实现想要实现的方法,比如说客户想要在蓝牙扫描开始的时候添加一些动画效果,那么你就可以实现onStart()方法,然后在其中做你想做的事情,默认是不需要实现的,如果你想要在蓝牙设备返回数据时做出反应,那就去实现onRead()方法,如果你想在蓝牙连接失败或者超时的情况下去做特殊的处理,你就去实现onError()或者onConnectTimeOut()方法等等。
BleManager:
该类提供了几乎所有你需要用到的方法,包括蓝牙扫描、连接、断开、蓝牙当前连接状态等等,管理了蓝牙操作的所有接口和方法。
BluetoothLeService:
该类是最重要的一个类,主要是蓝牙操作中用到的各个方法的实现类,是整个蓝牙的核心功能实现,BleManager是对外提供所有蓝牙操作接口的管理类,当BluetoothLeService处理之后要把结果返回到BleManager中,然后再由BleManager对外提供接口,他们之间通过handler进行连接起来,如下:
当BluetoothLeService中处理之后就会通知BleManager去处理状态改变,如下:
在此要注意一些细节,比如大多数设备扫描的时候会重复扫描到相同蓝牙设备,必须要进行过滤,开发应用时,必须还要进行产品过滤,比如通过设备的广播包过滤,或者通过设备名过滤都是可以的,如下(注意:要根据自己产品提供的广播包进行过滤,下图是我们自己产品的):
还有更重要的一个细节就是,在设备添加、移除或者连接状态发生改变时怎么样判断当前蓝牙对象是否是同一个对象(有点拗口),看下图:
可以看到mBleFactory.create(BleManager.this,(BluetoothDevice) msg.obj)返回了一个蓝牙对象,该方法最基本的实现如下:
这里就是判断当前已连接的蓝牙设备的集合中是否存在该设备,如果有直接返回该对象,如果没有则新创建一个蓝牙对象。
当设备连接成功之后并不代表就可以在此时发送数据,因为此时只是连接成功,并没有获取到蓝牙服务。必须要先通过gatt对象去获取服务discoverServices()在可以。如果想让APP内能够实时监听到蓝牙设备发来的数据,则还需要设置一个通知(可以理解成注册监听吧)如下:
这里对几个重要的回调做解读,当我们收到onLeScan()回调时,则说明已经扫描到设备,只需要加入到你的设备列表中即可,当收到onConnectionChanged()方法时,说明蓝牙连接状态已经改变,则只需要判断BleDevice的状态即可,当收到onServicesDiscovered()回调时,说明已经搜索到蓝牙服务,这时可以根据自己的需求去设置通知Notify,如下图:
根据服务的UUID来进行过滤,然后根据服务获取到特征的UUID,然后在进行过滤,然后再从特征中取出通知的UUID,这时设置通知为true就可以了。
新更新的OTA升级模块的接口还没有介绍,大家感兴趣可以去下载源码自己去查看,OK,要注意的细节问题已经介绍的差不多了,如果感兴趣的朋友可以大胆的去应用该库到自己的项目中。