>蓝牙类别与简介
BLE设备分单模和双模两种,双模简称BR,商标为Bluetooth Smart Ready,单模简称BLE或者LE,商标为Bluetooth Smart。低功耗蓝牙是不能兼容经典蓝牙的,需要兼容,只能选择双模蓝牙。一个蓝牙主端设备,可同时与7个蓝牙从端设备进行通讯。
低功耗蓝牙(BLE):字如其名,第一特点就是低功耗,蓝牙4.0以上的;一个纽扣电池可以支持其运行数月至数年,至于怎么实现低功耗,看下文。它应用场景广,可以想想,现在的智能家居,智能音箱,智能手表等等物联网设备,大多数通过BLE进行配网和数据交互。(每次最大传输20bit字节)
经典蓝牙(BT):经典蓝牙,泛指蓝牙4.0以下的都是经典蓝牙,你还怀念通过蓝牙让音箱播放手机的音乐么?经典蓝牙常用在语音、音乐等较高数据量传输的应用场景上。 经典蓝牙模块可再细分为:传统蓝牙模块和高速蓝牙模块。 传统蓝牙模块在2004年推出,主要代表是支持蓝牙2.1协议的模块,在智能手机爆发的时期得到广泛支持。 高速蓝牙模块在2009年推出,速率提高到约24Mbps,是传统蓝牙模块的八倍。 传统蓝牙有3个功率级别,Class1,Class2,Class3,分别支持100m,10m,1m的传输距离
双模蓝牙:即在蓝牙模块中兼容BLE和BT
在Android 4.3及更高版本,Android 蓝牙堆栈可提供实现蓝牙低功耗 (BLE) 的功能,在 Android 8.0 中,原生蓝牙堆栈完全符合蓝牙 5.0 的要求。也就是说在Android 4.3以上,我们可以通过Android 原生API和蓝牙设备交互。
一、低功耗蓝牙介绍
开发步骤如下:
获取BluetoothAdapter,然后扫描,获取蓝牙驱动Device,然后连接蓝牙驱动,监听连接回调,获取一个驱动Device下的所有不同功能的service数组,通过service的uuid获取需要的service,拿到service后通过特征的uuid获取所要的特征Characteristic,每个特征都含有一个value和多个对value的描述Descriptor。通过操作特征可以读取和写入数据。
//1. Android 4.3以上,Android 5.0以下
mBluetoothAdapter.startLeScan(BluetoothAdapter.LeScanCallback LeScanCallback)
//2. Android 5.0以上,扫描的结果在mScanCallback中进行处理
mBluetoothLeScanner=mBluetoothAdapter.getBluetoothLeScanner();
mBluetoothLeScanner.startScan(ScanCallback mScanCallback);
GATT协议:
1.一个蓝牙设备有多个Service->每个Service内部有多个characteristic属性->每个characteristic属性内有多个特征和携带的value值;蓝牙的读写都是通过characteristic属性来进行的,通过Gatt进行扫描蓝牙和连接。service和characteristic,都有一个唯一的uuid来标识。GATT协议
2.profile(数据配置文件):一个profile文件可以包含一个或者多个Service,一个profile文件包含需要的服务的信息或者为对等设备如何交互的配置文件的选项信息。ProfileProfile 并不是实际存在于 BLE 外设上的,它只是一个被 Bluetooth SIG 或者外设设计者预先定义的 Service 的集合。
BLE技术是基于GATT进行连接与通信的,GATT是一种属性传输协议,简单的讲可以认为是一种属性传输的应用层协议。结构图如下
image
3.UUID:“GATT层”中定义的所有属性都有一个UUID值,UUID是全球唯一的128bit的号码数字,它用来识别不同的特性。作用类似Soccket通信的端口。蓝牙核心规范制定了两种不同的UUID,一种是基本的UUID,一种是代替基本UUID的16位UUID。所有的蓝牙技术联盟定义UUID共用了一个基本的UUID:
0x0000xxxx-0000-1000-8000-00805F9B34FB
为了进一步简化基本UUID,每一个蓝牙技术联盟定义的属性有一个唯一的16位UUID,以代替上面的基本UUID的‘x’部分。例如,心率测量特性使用0X2A37作为它的16位UUID,因此它完整的128位UUID为:
0x00002A37-0000-1000-8000-00805F9B34FB
虽然蓝牙技术联盟使用相同的基本UUID,但是16位的UUID足够唯一地识别蓝牙技术联盟所定义的各种属性。蓝牙技术联盟所用的基本UUID不能用于任何定制的属性、服务和特性。对于定制的属性,必须使用另外完整的128位UUID。
每一个Service、属性特征characteristic、属性描述Descriptor都有一个专属的UUID做为标示。
4.主从设备
Center(中心设备,主动连接的一方)
Center主要可以分为 扫描->连接->通讯 三块内容. 通讯主要包含read,write,notify/indicate。read就是读取设备上的数据(如读取外设电量),write就是发送数据(如发送关闭命令关闭蓝牙灯),notify/indicate 字面意思就是通知/指示, 是用来接收设备主动上报的数据的(如手环可以每隔1秒就告诉APP心率值, 然后APP展现一个心率谱图),这样就达成了双向通讯。
Peripheral(外设设备,被动连接的一方)
Peripheral主要理解为硬件外设,提供数据用的。在开发APP时很少关心这个,因为大家都是直接拿着硬件来调试的。在android5.0时,增加了Peripheral相关的API, 意味着可以让android设备模拟成外设,作为Peripheral来提供数据。这样,当我们没有硬件设备的时候,可以拿2台手机进行BLE开发,很方便。还可以扩展很多其他功能,比如使用BLE实现蓝牙聊天(google sample里面有经典蓝牙的聊天demo),还可以把手机模拟成iBeacon等等。
ble读和写:
超过20bit写入需要分包发送
private void writeData(){
BluetoothGattService service=mBluetoothGatt.getService(write_UUID_service);
BluetoothGattCharacteristic charaWrite=service.getCharacteristic(write_UUID_chara);
byte[] data=HexUtil.hexStringToBytes(hex);
if (data.length>20){//数据大于个字节 分批次写入
Log.e(TAG, "writeData: length="+data.length);
int num=0;
if (data.length%20!=0){
num=data.length/20+1;
}else{
num=data.length/20;
}
//分包发送
for (int i=0;i<num;i++){
byte[] tempArr;
if (i==num-1){
tempArr=new byte[data.length-i*20];
System.arraycopy(data,i*20,tempArr,0,data.length-i*20);
}else{
tempArr=new byte[20];
System.arraycopy(data,i*20,tempArr,0,20);
}
charaWrite.setValue(tempArr);
mBluetoothGatt.writeCharacteristic(charaWrite);
}
}else{
charaWrite.setValue(data);
mBluetoothGatt.writeCharacteristic(charaWrite);
}
}
开启订阅
//订阅通知
mBluetoothGatt.setCharacteristicNotification(mBluetoothGatt
.getService(notify_UUID_service).getCharacteristic(notify_UUID_chara),true);
注意在写入之前要先开启订阅,要不然就收不到写入的数据,我一般都是在发现服务之后就订阅。关于订阅收不到这里,需要注意一下,首先你写入的和订阅的Characteristic对象一定要属于同一个Service对象,另外就是保证你写入的数据没问题,否则就可能收不到订阅回调。
二、经典蓝牙开发 Android-经典蓝牙(BT)-建立长连接传输短消息和文件 1、经典蓝牙的开发类似一个Socket连接。Clinet端需要创建一个BluetoothSocket,服务端需要创建一个BluetoothServerSocket监听待连接的uuid的clinet,这个监听uuid类似Socket的端口监听。数据操作采用输入流与输出流写入和读取。
SPP_UUID是同一个UUID,也就是类似Scoket的端口 ——Clinet端——
//BluetoothSocket socketC = dev.createRfcommSocketToServiceRecord(SPP_UUID); //加密传输,Android系统强制配对,弹窗显示配对码
BluetoothSocket socketC = dev.createInsecureRfcommSocketToServiceRecord(SPP_UUID); //明文传输(不安全),无需配对
——Service端——
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
//BluetoothServerSocket mSSocket = adapter.listenUsingRfcommWithServiceRecord(TAG, SPP_UUID); //加密传输,Android强制执行配对,弹窗显示配对码
BluetoothServerSocket mSSocket = adapter.listenUsingInsecureRfcommWithServiceRecord(TAG, SPP_UUID); //明文传输(不安全),无需配对
BluetoothSocket socketC = mSSocket.accept(); // 监听连接
mSSocket.close(); // 关闭监听,只连接一个设备
服务端和客户端都可获取输入流与输出流,然后读取数据与发送数据信息
//发送信息用输出流
DataOutputStream mOut = new DataOutputStream(socketC.getOutputStream());
//读取信息用输入流
DataInputStream mIn= new DataInputStream(socketC.getInputStream());