《低功耗蓝牙工具APP开发实战》
什么是 LightBLE?
一个功能比较全面的蓝牙调试工具。支持所有使用蓝牙4.0低功耗的设备接入调试,提供蓝牙设备搜索、读取服务、浏览特征等操作。
当前支持iPhone、安卓及微信小程序,后续将陆续支持Mac、Windows、Linux、网页端Chrome及其他可能使用的系统。
本文亮点
- BLE入门知识,图表形式简洁易懂
- 大量实战代码,由浅入深讲解
- 代码开源分享,涵盖陆续扩展版本
- 资源永久分享,导图、设计图都有
你能收获什么?
- 快速掌握BLE基础知识
- 学会uni开发并上架市场
- 获得 LightBLE 思维导图、原型图、设计原稿
- 获得一套完整的、可运行的LightBLE代码
适合人群
- 想快速掌握BLE的小伙伴
- 需要开发BLE的程序员
- 想要获得快速BLE调试框架的爱好者
工具与语言
- 需求规整:XMind
- 原型设计:Mockplus
- UI设计:Sketch
- 硬件:智能手机(安卓4.3以上 或 iOS6.0以上)
- 开发工具:hbuilderx
- 开发框架:Uni-App
- 协议:蓝牙4.0
- 开发语言:Vue 、HTML、CSS3
本文结构
- 第一章:初识BLE
尽可能用简短的语句、图片及表格来阐述BLE的入门知识。 - 第二章:Uni-app快速入门
对标官网,通过另外一种方式快速掌握基本使用方法。 - 第三章:需求分析
用思维导图讲解需求迭代,用原型和UI图展示效果。 - 第四章:项目实战
统一基础工程讲解BLE开发,减少不必要的学习成本。
第一章 初识BLE
BLE简介
BLE全称是BlueTooth Low Energy,即低功耗蓝牙,目前主要广泛应用于IoT产品领域。
低功耗蓝牙与经典蓝牙使用相同的2.4GHz无线电频率,因此双模设备可以共享同一个天线。但值得注意的是,低功耗蓝牙不能向后兼容原有的蓝牙协议(也就是经典蓝牙)。
本文开发使用的是蓝牙4.0,包括传统蓝牙模块部分和低功耗蓝牙模块部分,是一个双模标准,BLE是蓝牙4.0中的单模模式(注:在2016年由蓝牙技术联盟提出蓝牙5.0技术标准)。
设备状态[重点]
状态名 | 中文名 | 说明 |
---|---|---|
tandby | 待机状态 | 设备没有传输和发送数据,并且没有连接到任何设备 |
advertiser | 广播状态 | 周期性广播状态 |
Scanner | 扫描状态 | 主动寻找正在广播的设备 |
Initiator | 发起连接状态 | 主动向扫描设备发起连接 |
Master | 主设备 | 作为主设备连接到其他设备 |
Slave | 从设备 | 作为从设备连接到其他设备 |
工作状态[重点]
状态名 | 中文名 |
---|---|
standby | 准备 |
dvertising | 广播 |
Scanning | 监听扫描 |
Initiating | 发起连接 |
Connected | 已连接 |
状态切换图
设备类型
类型 | 中文名 | 说明 |
---|---|---|
Cnetral | 主机 | 常作为client端,如手机、PC |
Peripheral | 从机 | 常作为Service端,如鼠标、血压计 |
Observer | 观察者 | |
Broadcast | 广播者 |
中心设备和外设交互[重点]
从上图可以看出,手机或者MAC可以做为中心设备,鼠标和血压计作为外设。外设(有数据)发起发起广播,中心设备(类似APP向服务端索取数据)收到广播会去扫描外设和监听收到的信息。
协议栈
蓝牙协议规定了两个层次的协议,分别为蓝牙核心协议(Bluetooth Core)和蓝牙应用层协议(Bluetooth Application)。蓝牙核心协议关注对蓝牙核心技术的描述和规范,它只提供基础的机制,并不关心如何使用这些机制;蓝牙应用层协议,是在蓝牙核心协议的基础上,根据具体的应用需求,百花齐放,定义出各种各样的策略,如FTP、文件传输、局域网等等。
而蓝牙核心协议(Bluetooth Core)又包含BLE Controller和BLE Host两部分。这两部分在不同的蓝牙技术中(BR/EDR、AMP、LE),承担角色略有不同,但大致的功能是相同的。Controller负责定义RF、Baseband等偏硬件的规范,并在这之上抽象出用于通信的逻辑链路(Logical Link);Host负责在逻辑链路的基础上,进行更为友好的封装,这样就可以屏蔽掉蓝牙技术的细节,让Bluetooth Application更为方便的使用。
名称 | 英文 | 说明 |
---|---|---|
物理层 | Physical Layer | PHY层用来指定BLE所用的无线频段,调制解调方式和方法等。 |
链路层 | Link Layer | LL层是整个BLE协议栈的核心。 |
主机控制接口层 | Host Controller Interface | HCI主要用于2颗芯片实现BLE协议栈的场合,用来规范两者之间的通信协议和通信命令等。是可选的。 |
通用访问配置文件层 | Generic access profile | GAP是对LL层payload(有效数据包)如何进行解析的两种方式中的一种,而且是最简单的那一种。目前主要用来进行广播,扫描和发起连接等。 |
逻辑链路控制及自适应协议层 | Logical Link Control and Adaptation Protocol | L2CAP对LL进行了一次简单封装,LL只关心传输的数据本身,L2CAP就要区分是加密通道还是普通通道,同时还要对连接间隔进行管理。 |
安全管理层 | Security Manager | SMP用来管理BLE连接的加密和安全的,如何保证连接的安全性,同时不影响用户的体验,这些都是SMP要考虑的工作。 |
属性协议层 | Attribute protocol | 简单来说,ATT层用来定义用户命令及命令操作的数据,比如读取某个数据或者写某个数据。 |
通用属性配置文件层 | Generic Attribute profile | GATT用来规范attribute中的数据内容,并运用group(分组)的概念对attribute进行分类管理。 |
服务与特征[重点]
一个外设可以包含一个或多个服务(Service),服务是用于实现装置的功能或特征数据相关联的行为集合。而每个服务又对应多个特征(CBCharacteristic),特征提供外设服务进一步的细节。
数据包
BLE 发送数据时最多允许20个字节,但仍可以通过分包方式,使发送内容长度的扩充。
第二章 Uni-app快速入门
简介
uni-app
是一个使用 Vue.js 开发所有前端应用的框架,开发者编写一套代码,可发布到iOS、Android、Web(响应式)、以及各种小程序(微信/支付宝/百度/头条/飞书/QQ/快手/钉钉/淘宝)、快应用等多个平台。
需要更详细的介绍,请进入到uni-app官网查看,官网地址:https://uniapp.dcloud.io/ 。
本章节是官网的个人提炼,便于快速进入后期项目开发做准备。
快速入门
创建工程
下载开发工具:HBuilderX ,选择App开发版,下载地址:https://www.dcloud.io/hbuilderx.html 。
在点击工具栏里的文件 -> 新建 -> 项目:
选择 uni-app ,填入项目名称[此处取名demo
],模板选择 默认模板
后,点击创建。
项目运行
使用HBuilderX打开demo项目,双击 App.vue 后,点击工具栏的运行 -> 内置浏览器运行,即可在浏览器里面体验uni-app 的 H5 版【首次运行会提示需要安装,安装后再次点击即可】。
了解其他运行效果,可以官网查看,也可以自行操作,此处就不再累赘。
目录结构说明
如果您看到的目录与下面不一致,试着创建新项目,模板选择Hello uni-app
。
┌─ components uni-app组件目录
│ └─ comp-a.vue 可复用的a组件
├─ hybrid 存放本地网页的目录
├─ platforms 存放各平台专用页面的目录
├─ pages 业务页面文件存放的目录
│ ├─ index
│ │ └─ index.vue index页面
│ └─ list
│ └─ list.vue list页面
├─ static 存放应用引用静态资源(如图片、视频等)的目录,注意:静态资源只能存放于此
├─ wxcomponents 存放小程序组件的目录
├─ main.js Vue初始化入口文件
├─ App.vue 应用配置,用来配置App全局样式以及监听 应用生命周期
├─ manifest.json 配置应用名称、appid、logo、版本等打包信息
└─ pages.json 配置页面路由、导航条、选项卡等页面类信息
项目配置
使用HBuilderX打开demo项目,双击 manifest.json
。
配置 AppID 和 Vue 版本:
添加 BLE 模块支持:
添加BLE权限:
如不配置自动添加权限,则找下以下几个选项,勾选:
" ",
" ",
" ",
" "
其他配置
- 使用HBuilderX打开demo项目,双击
manifest.json
选择 微信小程序配置
添加微信小程序AppID 。
选择 App图标配置
添加图标,使用自动生成即可。
- 选择HBuilderX
配好设置
,选择运行配置
选择 微信开发者工具路径
,添加对应路径。
- 配置证书(需要发布在进行操作)
使用HBuilderX打开demo项目,双击 App.vue 后,点击工具栏的发行 -> 原生APP-云打包。
会弹出App打包需要配置的内容,区分 Android 和 iOS ,根据内容自行配置即可。
-
账户申请(安卓市场只列举部分)
平台 地址 说明 微信小程序 https://mp.weixin.qq.com LightBLE 开发及发布,公司或个人均可 iOS开发者 https://developer.apple.com 需要 99美元/年 的开发者账户,公司或个人均可 小米 https://dev.mi.com Android端发布使用,发布需要软著 oppo https://open.oppomobile.com Android端发布使用,发布需要软著 华为 https://developer.huawei.com Android端发布使用,发布需要软著 应用宝 https://open.qq.com/app_plus Android端发布使用,发布需要软著
第三章 需求分析
需求分解
LightBLE定位为一个轻量级BLE调试助手,具体功能通过思维导图示如下:
经过上图规整,再对比uni-app
提供的BLE接口,能一套代码完成以上功能。这也是本文选择使用 uni-app
进行开发并讲解的原因。
低功耗蓝牙 API 平台差异说明(刚好满足App和微信小程序)
App | H5 | 微信小程序 | 支付宝小程序 | 百度小程序 | 字节跳动小程序 | 飞书小程序 | QQ小程序 | 快手小程序 |
---|---|---|---|---|---|---|---|---|
√ | × | √ | √ | × | × | √ | × | × |
[蓝牙API](https://uniapp.dcloud.io/api/system/bluetooth)(接口地址:https://uniapp.dcloud.io/api/system/bluetooth)
API | 说明 |
---|---|
uni.openBluetoothAdapter(OBJECT) | 初始化蓝牙模块 |
uni.startBluetoothDevicesDiscovery(OBJECT) | 开始搜寻附近的蓝牙外围设备。 此操作比较耗费系统资源,请在搜索并连接到设备后调用 uni.stopBluetoothDevicesDiscovery 方法停止搜索。 |
uni.onBluetoothDeviceFound(CALLBACK) | 监听寻找到新设备的事件 |
uni.stopBluetoothDevicesDiscovery(OBJECT) | 停止搜寻附近的蓝牙外围设备。 若已经找到需要的蓝牙设备并不需要继续搜索时,建议调用该接口停止蓝牙搜索。 |
uni.onBluetoothAdapterStateChange(CALLBACK) | 监听蓝牙适配器状态变化事件。 |
uni.getConnectedBluetoothDevices(OBJECT) | 根据 uuid 获取处于已连接状态的设备。 |
uni.getBluetoothDevices(OBJECT) | 获取在蓝牙模块生效期间所有已发现的蓝牙设备。 包括已经和本机处于连接状态的设备。 |
uni.getBluetoothAdapterState(OBJECT) | 获取本机蓝牙适配器状态。 |
uni.closeBluetoothAdapter(OBJECT) | 关闭蓝牙模块。 调用该方法将断开所有已建立的连接并释放系统资源。建议在使用蓝牙流程后,与 uni.openBluetoothAdapter 成对调用。 |
[低功耗蓝牙 API](https://uniapp.dcloud.io/api/system/ble) (接口地址:https://uniapp.dcloud.io/api/system/ble )
API | 说明 |
---|---|
uni.setBLEMTU(OBJECT) | 设置蓝牙最大传输单元。 需在 uni.createBLEConnection调用成功后调用,mtu 设置范围 (22,512)。安卓5.1以上有效。 |
uni.writeBLECharacteristicValue(OBJECT) | 向低功耗蓝牙设备特征值中写入二进制数据。 注意:必须设备的特征值支持 write 才可以成功调用。 |
uni.readBLECharacteristicValue(OBJECT) | 读取低功耗蓝牙设备的特征值的二进制数据值。 注意:必须设备的特征值支持 read 才可以成功调用。 |
uni.onBLEConnectionStateChange(CALLBACK) | 监听低功耗蓝牙连接状态的改变事件。 包括开发者主动连接或断开连接,设备丢失,连接异常断开等等。 |
uni.onBLECharacteristicValueChange(CALLBACK) | 监听低功耗蓝牙设备的特征值变化事件。 必须先启用 notifyBLECharacteristicValueChange 接口才能接收到设备推送的 notification。 |
uni.notifyBLECharacteristicValueChange(OBJECT) | 启用低功耗蓝牙设备特征值变化时的 notify 功能,订阅特征值。 注意:必须设备的特征值支持 notify 或者 indicate 才可以成功调用。 另外,必须先启用 notifyBLECharacteristicValueChange 才能监听到设备 characteristicValueChange 事件 |
uni.getBLEDeviceServices(OBJECT) | 获取蓝牙设备所有服务(service)。 |
uni.getBLEDeviceRSSI(OBJECT) | 获取蓝牙设备的信号强度。 |
uni.getBLEDeviceCharacteristics(OBJECT) | 获取蓝牙设备某个服务中所有特征值(characteristic)。 |
uni.createBLEConnection(OBJECT) | 连接低功耗蓝牙设备。 若APP在之前已有搜索过某个蓝牙设备,并成功建立连接,可直接传入之前搜索获取的 deviceId 直接尝试连接该设备,无需进行搜索操作。 |
uni.closeBLEConnection(OBJECT) | 断开与低功耗蓝牙设备的连接。 |
通过上述分析,再次针对APP/小程序进行需求梳理,梳理如下:
原型设计
通过上诉需求梳理后,进行原型图设计和UI图设计。
原型图
- 设计工具:Mockplus
- 原型地址:https://run.mockplus.cn/dua7ZgYiBOPE5Wsw/index.html
- 说明:原型不要太考虑美化,因为那是UI设计师、视觉设计师、动效设计师等的事情。原型只要把功能和基本页面交互规划准确就可以。
-
交互图展示:
UI图
- 设计工具:Sketch
- 在线设计图:蓝湖 (建议使用,会在项目开发中提及)
- 说明:Sketch 当前只能使用Mac进行设计,所以无法打开Sketch的读者,请双击资源[在下节
前置准备
提及]中的LightBLE-HTML/index.html
跳转到浏览器,便可以看到 LightBLE 的UI设计图。 - UI设计图展示:
前置准备
- LightBLE :最新版,便于理解及测试 。下载着陆页:https://i2kai.com 。
- 安卓手机 :Android 4.3 及以上,开启手机调试模式。
- iOS手机 :iOS 6.0 及以上,上架或分发需配置开发证书,开发不用。
- 微信小程序 :申请账号获取APPID 或 使用测试号,测试号申请地址:https://developers.weixin.qq.com/miniprogram/dev/devtools/sandbox.html 。
- ESP32 :Peripheral 真实体验,可不要(替代方案:多找一部手机安装 LightBLE 来模拟Peripheral;电脑版推荐 lightblue 来模拟Peripheral ,将来有机会把桌面端也写上)。[将来会写ESP32的教程]
- 资源(思维导图、原型图、设计稿和基础工程):https://www.aliyundrive.com/s/sEE5xycpMpG 提取码: 60dm
- 源码:https://gitee.com/luoyaosheng/smart-ble
第四章 项目实战
基础框架
从资源目录中打开 LightBLE 项目,可以看到以下结构
┌─ common 通用配置
│ ├─ animate.css 动画[当前版本还未使用]
│ ├─ common.css 业务全局css
│ ├─ config.js 业务全局配置
│ ├─ free.css 通用css
│ ├─ iconfont.css 图标
│ ├─ mock.js 模拟数据
│ └─ tool.js 工具函数集合
┌─ components uni-app组件目录
│ ├─ divider.vue 分割线
│ ├─ logItem.vue 日志列表item
│ ├─ scannerItem.vue 扫描列表item
│ ├─ sk-switch.vue 自定义Switch
│ └─ spread.vue 水波纹动效[搜索/广播中无数据时展示]
├─ pages 业务页面文件存放的目录
│ ├─ advertiser 广播相关页面
│ │ └─ ...
│ ├─ scanner 扫描相关页面
│ │ └─ ...
│ ├─ setting 设置相关页面
│ │ └─ ...
│ └─ tabbar tabbar相关页面
│ └─ ...
├─ static 存放应用引用静态资源(如图片、视频等)的目录,注意:静态资源只能存放于此
│ ├─ imgs 图片
│ │ └─ ...
│ ├─ tabbar tabbar专属图片
│ │ └─ ...
│ ├─ iconfont.ttf iconfont资源文件
│ └─ logo.png logo
├─ main.js Vue初始化入口文件
├─ App.vue 应用配置,用来配置App全局样式以及监听 应用生命周期
├─ manifest.json 配置应用名称、appid、logo、版本等打包信息
└─ pages.json 配置页面路由、导航条、选项卡等页面类信息
工程内容说明
文件名 | 说明 |
---|---|
config.js | 填写 常量 和 枚举 |
free.css | 通用css ,即使没有UI设计情况下,仍能做出好产品 |
common.css | 业务全局css,通常包括 全局背景色、业务色、字体、圆角、边距及自定义全局使用css等 |
mock.js | 此处只是模拟假数据,没有真正使用 mock |
tool.js | 工具函数集合。例如项目中使用到的 秒转化格式、ArrayBuffer转换、hex和ascii转换及uuid 获取等方法 |
main.js | 添加 全局组件、toos.js、config.js 和 mock.js ,方便全局使用 |
App.vue | 添加 全局css |
组件使用
基本介绍
组件有两种方式引用:全局组件 和 局部组件。
# 全局组件 通过 main.js 进行配置
# 本项目引入 分割线 divider.vue
// 全局注册
import divider from './components/divider.vue'
// 全局注册
Vue.component('divider', divider)
# 局部组件 通过 vue 进行设置
# 下面用 scannerItem.vue 做说明
...
属性赋值
组件的使用中包含 属性赋值 怎么通过组件对外开放。
// 使用 scannerItem.vue 做介绍
...
// 子组件
我是子组件。
# 通过prop实现通信
// 父组件
我是父组件。
// 子组件
{{message}}
# 通过$ref 实现通信
// 父组件
我是父组件。
// 子组件
{{message}}
# 通过$emit 实现通信
// 父组件
{{title}}
// 子组件
我是子组件。
注意事项
本项目重点在于蓝牙的基本开发操作,所以在基础工程中已配置好不同平台的兼容处理。
由于 uni-app 暂时没有作为 外设设备 的接口,所以当前只有程序小程序版本支付外设模式,并不支持自定义。
项目中包含两种图片引入方式:本地图片 和 iconfont 。
考虑总体时间,动画先引入,后期会同步提交到 GitHub 或 Gitee。
Cnetral
初始化蓝牙
主要目的是为了检测蓝牙是否打开。
// 方便调用,定义方法 bleOpenBluetoothAdapter(){}
搜索蓝牙设备
搜索蓝牙设备需要两步:
- startBluetoothDevicesDiscovery 调用成功;
- onBluetoothDeviceFound 监听寻找到新设备。
// 方便调用,定义方法 bleOpenBluetoothAdapter(){}
综合考虑,将开始搜寻附近的蓝牙外围设备的搜索条件,放到数据整理函数dataRegularization中,从而避免多次操作 startBluetoothDevicesDiscovery 。
条件筛选
通过上面代码知道,搜索到设备信息均为未赛选过滤数据。所以我们增加了两个方法来优化数据。
连接设备
通过上节获取的设备信息,选择一个设备并传递 deviceId 连接。
连接上设备后,就可以进行设备的读、写、通知等操作。代码中的注意字段请仔细阅读。
Peripheral
查看 uni-app 蓝牙相关文档,并没有作为外设的API。转而查看微信小程序蓝牙相关文档,发现是有外设API(尽管不全),再结合uni可以直接调用微信小程序API,所以下面代码使用微信小程序代码来展示。(APP需要自己做组件或使用原生,后期处理后会更新到代码库中。)
通用
日志存储
日志格式
全局变量
本次项目选择使用数据缓存到本地,全局key对存储内容管理从而实现全局变量的方式。