从零开始写一个蓝牙SPP通讯

流程思考

这边有几个需求点,

1.一个统一的蓝牙管理类,BtManger,针对蓝牙连接和各种数据回调处理。

TIM截图20180330145900.png

变量说明一下,
(1)BluetoothAdapter 是一个本地蓝牙适配器,可以用来查询设备,获取已配对设备列表,通过MAC连接蓝牙设备,做蓝牙接入监听,还有蓝牙开关状态等等。可以通过获取系统的BluetoothManager来获取,也可以直接通过BluetoothAdapter获取一个默认的BluetoothAdapter,

1
2
3
BluetoothManager btManager = (BluetoothManager) context
.getSystemService(Context.BLUETOOTH_SERVICE);
BluetoothAdapter bluetoothAdapter = btManager.getAdapter;
1
2
BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();

两种方式的区别在于,第一种方式可以通过btManager来获取蓝牙的一些状态信息,包括已连接的设备列表等…

(2)Context上下文,如果有全局的蓝牙处理需求,建议在Application创建的时候传入应用上下文,这个上下文需要注册广播还有一些其他的功能,如果不是声明周期长的Activiy会导致内存泄露。
(3)BluetoothTransferService 传输服务类,提供设备连接,还有蓝牙Socket数据传输。后面会详细讲到。
(4)BluetoothStatusReceiver 广播接收器,用来接收蓝牙状态的广播,蓝牙开启/关闭。
(5)BluetoothScanRecevier 广播接收器,用来接收蓝牙设备扫描的广播
(6)BtManager 蓝牙管理类的单实例,因为蓝牙SPP对接整个周期只做一个,没必要每次都创建新的连接。
(7)DeviceHandler 这个类用来做跨线程的诸多状态的通信。(整个连接,监听,和传输过程都放在线程中)

2.蓝牙搜索,需要有一个能搜索附近的蓝牙的回调
TIM图片20180328151248.png
整个设计大致如下,BluetoothDevice为蓝牙设备信息,rssi为信号强度,提供单设备扫描,扫描超时,和全部扫描结束列表回调

3.蓝牙对接,需要有一个能让用户知道蓝牙连接状态的回调 成功,失败,中断等..

TIM图片20180328152721.png
四个方法分别 是连接中,已连接,断开连接,等待接入,连接到设备

4.蓝牙数据传输(发送),这个是重点,分析一下这一块需要的功能,(1)发送消息的功能,称之为sendMessage。(2)消息可能是一个文件,可能是一长串字节流,可能是一个int数组,也可能是一串字符串,好了这边这边提供一个抽象。提供一个基础的RequestMessage,和getRequestBody根据不同的文件类型做策略包装。甚至可以提供静态工厂来包装一个这样的对象;

5.蓝牙数据传输(接收),这个也是重点,分析一下这一块需要的功能,(1)接收消息的功能,当消息接收完毕后告诉用户。(2)消息可能是一个文件,可能是一长串字节流,可能是一个int数组等等。提供一个扩展的接口用来做消息处理,针对不同的消息做不同的处理。提供一个基础的 ResponseMessage,getResponseBody也做策略封装。

6.分包传输,分包接收这类的机制。降低仪器数据量大小限制

7.最后针对以上的功能提供一些静态的方法做数据处理,ByteUtil,FileUtil等。

协议定制

需求如下既要考虑到不同文件的传输,又要考虑到文件传输的大小限制。

协议可以这么做

  1. 包头,当接收到头部的时候代表一次请求开始,
  2. 文件名称,如果当前传输为文件的话填入文件名称否则为00 00;
  3. 总包数 针对数据太大的问题采用分包发送,AllPack总包
  4. 分包 当前传出分包
  5. 数据区长度 传输的数据区长度,用来确认接下来需要读取的字节数
  6. 数据 待传输数据,可以为空
  7. 校验和 针对前面传输数据的累加和,取低位

具体内容如下

包头 0x7e 0x7e 两个十六进制数 占两字节

文件名称 00 00 … 占50字节大致能传16个UTF-8中文字符和1个英文字符,或者50个英文字符,扩展名算进去。

总包数 00 01 占两个字节
分包 00 01 占两个字节
数据区域长度 00 01 占两个字节
数据 01 占1-n个字节
校验和 00 占一个字节,取低位 假设文件名为空数据为01 校验和为 7e+7e+01+01+01+01=01 00 取低位得00

一个完整的包如下

7e 7e 00 00… 00(50个00) 00 01 00 01 00 01 00 01 00

完美!!

编码阶段

demo地址:https://github.com/guoxiaolongonly/AndroidBluetooth

实现简单的聊天功能。文件名称也采用跟文件内容一样长度(2字节)加名称(长度字节)。