本文较长,阅读需要十分钟
鉴于星球的很多同学比较期望此类文章,本文我们好好的来聊聊低功耗蓝牙,相信有小部分同学正在从事的就是此行业了,这篇文章算是从零开始吧,带领你从新认识BLE,所以前面会有一些长篇大论,耐心读写去,收获满满。
一.蓝牙的工作原理
蓝牙的设备关系处于C/S架构,也就是说,一个是Client,一个是Server,两端连接成功之后将建立数据链,建立成功之后就能进行双向的数据或语音通讯,并且两端都是可以发起断链操作,也就是说只有在设备连接的时候才会有身份关系,之后双向的可操作性都是一样的,而搜索配对这个过程,我们可以理解为呼叫:主端发起呼叫首先是查找,然后根据蓝牙地址进行配对,配对成功后进行建链,蓝牙在手机上的应用,一般都是无线传输,但是应用最广泛的,还是基于蓝牙模块的串口通信。
二.蓝牙的基本概念
先来了解一下UUID,UUID被用于唯一标识的一个服务,主设备通过UUID访问从设备提供相同UUID的服务,从而建立C/S模式,再来了解一下基础的概念知识,一般我们使用的无外乎蓝牙3.0(传统蓝牙) 和 蓝牙4.0(低功耗蓝牙),他们之前的使用有一些共性也有一些区别的,所以我们虽然是以BLE为主,但是我们还是要先从传统蓝牙了解,这样也能更好的平移过去,我们先来了解传统蓝牙
三.蓝牙3.0的实践
我们就来基础的使用一下传统蓝牙,先了解传统蓝牙的两个关键类
BluetoothAdapter
BluetoothDevice
BluetoothAdapter位于源码中frameworks/base/core/java/android/bluetooth/目录下,作为本地适配器的存在,他有一系列的可操作本地功能的方法,我们再来看下BluetoothDevice,本地蓝牙设备,记录了机身相关蓝牙信息和同步蓝牙状态信息的一个类,通过实例,我们就可以使用了。
1.初始化
首先是添加权限,在传统蓝牙中,我们的权限需要添加如下两个:
<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
然后就可以操作我们的蓝牙设备获取本地适配器来打开蓝牙了:
这里我们可以看到,我通过getDefaultAdapter获取到BluetoothAdapter对象,这里要判断是否为空,因为模拟器是获取不到对象的,我们看下他的实现就知道了:
这是一个单例的写法,我们通过ServiceManager.getService去获取与framework通讯的IBinder,如果能获取到,说明系统蓝牙层是运行状态的,我们就可以初始化BluetoothAdapter并且返回了,否则会打印:Bluetooth binder is null
这里还要看下,我们可以通过两种方式来打开蓝牙,实际上是一种方式,另外一种知识Setting对外的接口而已,我们可以调用enable来打开,也可以通过disable来关闭蓝牙,这些方法包括适配器中的方法无外乎都是外包装了一层,最终的实现还是BluetoothManager通过IBluetoothManager接口实现的,这里还可以看到我们的第二种方法就是Intent跳转,这里可以传入一个requestCode来接收返回结果是否开启蓝牙。
2.已配对列表
到这里蓝牙是打开了,我们紧接着就可以实现搜索等功能并且展示蓝牙列表了,首先我们可以通过适配器去获取已配对的列表:
这里通过getBondedDevices获得一个Set集合,只要遍历就能得到已配对的列表,我们来看下这个方法的实现:
他首先判断了当前的状态是否是开启的,如果不是则返回一个空的集合,然后再判断mService是否为空,我们在getDefaultAdapter的源码中看到,mService实际上就是绑BluetoothManager的服务,所以如果调用getDefaultAdapter或者设备不支持蓝牙,则调用getBondedDevices获取为空。
这里用到了一个mServiceLock,也就是ReentrantReadWriteLock,这是一个线程锁,同一时间只能允许一个线程访问,确保binder的通信,后面会有很多地方用到这个锁的。