前段时间一直在忙手上的一个智能物流配送的项目,最近项目赶的不太紧,领导让我协助做一下同事项目上的蓝牙相关功能。我上一次接触蓝牙开发还是在16年,当时的领导说会做一个手环相关的项目,最后因为种种原因不了了之,所以从知识储备的维度上讲,这次蓝牙开发也算是从零开始吧。
先大致了解一下iOS端蓝牙的开发历史,在蓝牙2.0时代,那个时候iOS的版本为3.0,苹果为蓝牙开发推出GameKit.framework框架,顾名思义,这个框架大多用于游戏开发并且仅限于iOS设备之间连接。之后又推出了一个MultipeerConnectivity.framework的框架,用于iOS设备相互传输文件。再后来又推出一个ExternalAccessory.framework框架,这个可以使iOS设备与第三方蓝牙连接使用,不过需要通过苹果MFI认证,可以直接弃用这个框架。现在用的是CoreBluetooth.framework框架,只需硬件设备的蓝牙版本大于4.0即可。为什么大家都又称蓝牙开发为BLE开发呢?因为蓝牙4.0又称为Bluetooth Low Energy,耗能很少。现在很火的智能家居、手环、耳机等等除了很少部分使用WiFi连接开发,其余绝大部分都是用这个开发的。
对于我们移动端开发者而言,苹果其实对iOS和OSX做了很好的封装。蓝牙开发的难点在于理解其工作模式和清理一些关键的概念,比如:Central(中心设备)、Peripheral(外围设备)、Services(服务)、Characteristic(特征))......iOS端蓝牙开发的大致流程如下:
1.新建Central Manager实例进行蓝牙管理;
2.搜索外围设备;
3.连接外围设备;
4.获取外围设备的服务;
5.获取服务的特征;
6.给外围设备发送数据;
7.读取外围设备的数据;
如下图所示:
这里要着重理解一下服务和特性这两个关键概念。通常情况下一个外部硬件设备包含多个服务,每个服务又包含多个特征,特征里包含特征值和特征描述。并不是每个服务都具有读写的功能,当我们硬件相关文档缺失的时候(例如我,几乎没拿到什么文档),我们可以下载一个LightBlue软件,这里使用该软件连接我的笔记本做一下演示:
当我们找到可读可写的服务和属性之后就可以放心的去写代码了。注意我第三张图标记的Without Response,有的设备是With Response,这样就导致在写入数据的时候选择哪种类型进行写入,后面也会再次提及。
下面开始按照步骤来写代码:
注意:硬件设备中可读可写的服务值和特征值可以自己去查找,也可以找硬件的同事提供。
注意:在扫描设备和连接设备之前应该先判断手机蓝牙状态,只有扫到设备后才会进入相应的扫描和连接设备的代理方法。
注意:扫描到服务后,我们要筛选到可以读写的那个服务,只有这样后期才可以使用蓝牙对硬件进行发指令操作,之后再调用扫描该服务的特征方法。
注意:这一步其实很关键,我和负责调试蓝牙同事都卡在了这里,究其原因是数据源形式和方法不对,导致无法将数据写入蓝牙。蓝牙那边只支持16进制,所以我们要把信息流转成双方可识别的16进制。拿我们项目来说,我需要把传输的指令字符串,先转成byte,再转成16进制的字符串,最后再转成data类型写入蓝牙。上图我标注了一个类型,这个类型有两种,分别是CBCharacteristicWriteWithoutResponse和CBCharacteristicWriteWithResponse,其中使用CBCharacteristicWriteWithResponse这个类型是有回调的方法来告诉我们是写入了还是没写入,使用CBCharacteristicWriteWithoutResponse是没有直接回调的方法,我们只能根据订阅的通知来看是否写入成功。根据LightBlue的显示,我司的硬件需要使用CBCharacteristicWriteWithoutResponse才符合要求。调用了写入的方法,还需手动订阅通知。如果不手动订阅通知的话,该特征值的通知则无法激活。
就这样,我们利用蓝牙与硬件完成了一次简单的写读交互操作。
iOS蓝牙开发中还有一些代理方法,例如连接失败、断开连接等等,在此就不一一叙述了。总之,在我看来,电子元件和代码结合起来,才能演绎更多的精彩。