蓝牙4.0是 蓝牙3.0+HS规范的补充,专门面向对成本和功耗都有较高要求的无线方案,可广泛用于卫生保健、 体育健身、家庭娱乐、安全保障等诸多领域。
技术细节:
速度:支持1Mbps数据传输率下的超短数据包,最少8个八组位,最多27个。所有连接都使用 蓝牙2.1加入的减速呼吸模式(sniff subrating)来达到超低工作循环。
跳频:使用所有蓝牙规范版本通用的自适应跳频,最大程度地减少和其他2.4GHz ISM频段无线技术的串扰。
主控制:更加智能,可以休眠更长时间,只在需要执行动作的时候才唤醒。
延迟:最短可在3毫秒内完成连接设置并开始传输数据。
范围:提高调制指数,最大范围可超过100米(根据不同应用领域, 距离不同)。
健壮性:所有数据包都使用24-bit CRC校验,确保最大程度抵御干扰。
安全:使用AES-128 CCM加密算法进行数据包加密和认证。
拓扑:每个数据包的每次接收都使用32位寻址,理论上可连接数十亿设备;针对一对一连接优化,并支持星形拓扑的一对多连接;使用快速连接和断开,数据可以再网状拓扑内转移而无需维持复杂的 网状网络。
应用:
健康医疗、智能家居、物品防丢、蓝牙立体声耳机、蓝牙免提电话、蓝牙音响、HID人机交换、蓝牙游戏手柄、蓝牙3D眼镜
传统蓝牙-技术相关:
1、打开蓝牙:BluetoothAdapter.getDefaultAdapter().enable();
或:
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, 1);
2、关闭蓝牙:BluetoothAdapter.getDefaultAdapter().disable();
3、开始扫描外围设备:BluetoothAdapter.getDefaultAdapter().startDiscovery();
停止扫描:BluetoothAdapter.getDefaultAdapter().cancelDiscovery();
4、获取已经配对的设备数组:BluetoothAdapter.getDefaultAdapter().getBondedDevices();
5、蓝牙通信:
服务端:
String SPP_UUID = "00001101-0000-1000-8000-00805F9B34FB";
UUID uuid = UUID.fromString(SPP_UUID);
BluetoothServerSocket serverSocket
= null;
serverSocket =BluetoothAdapter.getDefaultAdapter()
.listenUsingRfcommWithServiceRecord("now", uuid);
客户端:
String SPP_UUID = "00001101-0000-1000-8000-00805F9B34FB";
UUID uuid = UUID.fromString(SPP_UUID);
BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(MainActivity.MAC);
BluetoothSocket socket = device.createRfcommSocketToServiceRecord(uuid);
BLE4.0-技术相关:
1、得到BluetoothAdapter对象:
BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
BluetoothAdapter
mBluetoothAdapter = bluetoothManager.getAdapter();
2、开始扫描外围设备:
mBluetoothAdapter
.
startLeScan
(BluetoothAdapter.
LeScanCallback
);在回调中得到BluetoothDevice
device
;
附:若知道设备的mac可通过mBluetoothAdapter.
getRemoteDevice
(mac)得到设备的BluetoothDevice
device
;
停止扫描:mBluetoothAdapter.
stopLeScan
(
BluetoothAdapter.LeScanCallback
);
3、连接设备:device.connectGatt(Context,boolean,BluetoothGattCallback);得到
Blue
toothGattgatt对象,可以与设备通信
4、通过修改gatt里Service、Characteristic、Descriptor的值,并结合
BluetoothGattCallback的回调方法与设备通信;
一个设备可以有多个Service,一个Service可以有多个Characteristic,一个Characteristic可以
有一个Value和多个Descriptor,
一个Descriptor有一个Value。
具体:
BluetoothGattService service = gatt.getService(UUID);
BluetoothGattCharacteristic characteristic = service.
getCharacteristic
(UUID);
BluetoothGattDescriptor descriptor = characteristic.
getDescriptor
(UUID);
descriptor.
setValue
(byte[] byte);
gatt.
writeDescriptor
(descriptor);
gatt.
writeCharacteristic
(characteristic);
BluetoothGattCallback的回调方法:
gatt.setCharacteristicNotification(characteristic, true)
------>
BluetoothGattCallback.onCharacteristicChanged
gatt.readCharacteristic(characteristic)
------------------------>
BluetoothGattCallback.onCharacteristicRead
gatt.writeCharacteristic(mCurrentcharacteristic)
------------>
BluetoothGattCallback.onCharacteristicWrite
连接蓝牙或者断开蓝牙
-------------------------------------------->
BluetoothGattCallback.onConnectionStateChange
gatt.readDescriptor(descriptor)
--------------------------------->
BluetoothGattCallback.onDescriptorRead
gatt.writeDescriptor(descriptor)
--------------------------------->
BluetoothGattCallback.onDescriptorWrite
gatt.readRemoteRssi()
------------------------------------------->
BluetoothGattCallback.onReadRemoteRssi
gatt.executeReliableWrite()
-------------------------------------->
BluetoothGattCallback.onReliableWriteCompleted
gatt.discoverServices()
------------------------------------------->
BluetoothGattCallback.onServicesDiscovered
经验:
1、
通过使用if(gatt==null)来判断gatt是否被创建过,如果创建过就使用gatt.connect();重新建立连接。
但是在这种情况下测试的结果是重新连接需要花费很长的时间。
解决办法是通过gatt = device.connectGatt(this, false, gattCallback);建立一个新的连接对象,很明显这样的速度要比上一种方法快很多
然而,多次创建gatt连接对象的直接结果是创建过6个以上gatt后就会再也连接不上任何设备,原因应该是android中对BLE限制了同时连接的数量为6个
解决办法是在每一次重新连接时都执行一次gatt.close();关闭上一个连接。
有人说为什么不在gatt.disconnect();后加一条gatt.close();呢,原因是如果立即执行gatt.close();会导致gattCallback无法收到STATE_DISCONNECTED的状态。
当然,最好的办法是在gattCallback收到STATE_DISCONNECTED后再执行gatt.close();,这样逻辑上会更清析一些。
2、这样的解决方法(在每次connect前,检查是否已经有了Gatt对象,有了的话,就close,然后建立连接重新分配-这个方法)是没错的。真实的原因是每一次连接都会生成一个Gatt对象,每一个Gatt对象都需要断开连接,不然的话,一旦其中有一个Gatt对象没有断开连接,系统就会认为你是在连接的,让你连扫描都扫描不到这个设备,就别说继续连接了。。。。你的方法是正好保证了系统中只有一个Gatt对象,且把真实的(也就是最后的那个)给保存了起来,用于实际操作。而disconnect本身在这个算法里面就可以代替close。close和disconnect的区别在于,close除了断开连接外,还会释放掉所有资源,导致不可以直接在后面的操作中用gatt对象的connect直接连接,而disconnect并不释放资源,所以,所有的资源还保存着,就可以用Gatt的connect进行简单恢复连接,而不是在device那一层进行操作。至于为啥允许可以对一个外设连接多次,这个事情我也很纳闷,不知道什么场景需要这样的操作。。。