两个demo在下面的博客中查看:
iOS swift 蓝牙详解(蓝牙中心demo,蓝牙外设demo(可替代mac蓝牙串口调试工具),蓝牙中心框架,gif演示)
文章目录
- 1.CBCentral CBPeripheral程序员不能自己创建,只能由系统创建,然后程序员在代理方法中获取
- 1.2 maximumUpdateValueLength(CBCentral)蓝牙中心最多一包能收多少个字节,苹果APP作为蓝牙中心是182
- 2.iphone手机app作为蓝牙外设,不发数据,60~70s后会自动和蓝牙中心断开,需要发心跳包才不会断开
- 3.writeValue.withResponse和writeValue.withoutResponse
- 3.1 writeValue.withResponse
- 3.2 writeValue.withoutResponse
- 4.必须执行read和notify的方法,代理方法被调用后,characteristic.value才有数据,否则为nil
- 5.最多一包可以给外设发(写)多少个字节peripheral.maximumWriteValueLength.
- 5.1 苹果app作为蓝牙外设 .withResponse: 512, .withoutResponse: 182
- 5.2 我这的一个蓝牙串口作为蓝牙外设 .withResponse: 512, .withoutResponse: 20
- 5.2 1 .withResponse分包发大量数据时打印截图如下:
- 5.3 maximumWriteValueLength,canSendWriteWithoutResponse,peripheralIsReady
- 5.3.1 用我这的蓝牙串口meek实测的发现(我的蓝牙串口应该是有点问题)
- 发现1
- 发现2
- 发现3
- 5.3.2 用写无回复writeWithoutResponse分包发大量数据时,打印结果如下截图
- 6.从5中得到的启示:.withResponse类似TCP,可靠传输,速度慢,每包写完都有回应,每包传的数据大。.withoutResponse类似UDP,不可靠传输,每包传完没有回应,传输速度快,每包传的数据小
- 7. 蓝牙外设特征属性为.read
- 7.1 给read特征赋一个固定的值
- 7.2 动态赋值
1.CBCentral CBPeripheral程序员不能自己创建,只能由系统创建,然后程序员在代理方法中获取
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary<NSString *, id> *)advertisementData RSSI:(NSNumber *)RSSI;
- (void)peripheralManager:(CBPeripheralManager *)peripheral central:(CBCentral *)central didSubscribeToCharacteristic:(CBCharacteristic *)characteristic;
1.2 maximumUpdateValueLength(CBCentral)蓝牙中心最多一包能收多少个字节,苹果APP作为蓝牙中心是182
亲测:
外设发:
蓝牙中心收:只能收182个,应该是发的时候就被截断了
2.iphone手机app作为蓝牙外设,不发数据,60~70s后会自动和蓝牙中心断开,需要发心跳包才不会断开
3.writeValue.withResponse和writeValue.withoutResponse
3.1 writeValue.withResponse
print(backStr)
printXY("写", obj: self, line: #line)
self.peripheral?.writeValue(data, for: self.characteristic!, type: .withResponse)
func peripheral(_ peripheral: CBPeripheral, didWriteValueFor characteristic: CBCharacteristic, error: Error?) {
print(#function)
print(error)
}
打印(外设那边没有回复):
23
19:44:49.887 XYCharacteristicVC 29 写
peripheral(_:didWriteValueFor:error:)
Optional(Error Domain=CBATTErrorDomain Code=241 “Unknown ATT error.” UserInfo={NSLocalizedDescription=Unknown ATT error.})如果外设那边回了success, print(error)的结果为nil
3.2 writeValue.withoutResponse
print(backStr) printXY(self.peripheral?.canSendWriteWithoutResponse, obj: self, line: #line)
printXY("写无回复", obj: self, line: #line)
self.peripheral?.writeValue(data, for: self.characteristic!, type: .withoutResponse)
func peripheralIsReady(toSendWriteWithoutResponse peripheral: CBPeripheral) {
print(peripheral.canSendWriteWithoutResponse)
print(#function)
}
打印:
67
19:45:11.491 XYCharacteristicVC 48 Optional(true)
19:45:11.492 XYCharacteristicVC 49 写无回复
true
peripheralIsReady(toSendWriteWithoutResponse:)
peripheralIsReady(toSendWriteWithoutResponse:)方法始终会被调用
参考:
iOS蓝牙的使用
4.必须执行read和notify的方法,代理方法被调用后,characteristic.value才有数据,否则为nil
read和notify方法:
open func readValue(for characteristic: CBCharacteristic)
open func setNotifyValue(_ enabled: Bool, for characteristic: CBCharacteristic)
CBPeripheralDelegate代理方法:
- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(nullable NSError *)error;
5.最多一包可以给外设发(写)多少个字节peripheral.maximumWriteValueLength.
CBPeripheral
open func maximumWriteValueLength(for type: CBCharacteristicWriteType) -> Int
5.1 苹果app作为蓝牙外设 .withResponse: 512, .withoutResponse: 182
当用苹果app作为蓝牙外设时,写可以发512个字节,写无回复可以发182个字节,如下图:
5.2 我这的一个蓝牙串口作为蓝牙外设 .withResponse: 512, .withoutResponse: 20
5.2 1 .withResponse分包发大量数据时打印截图如下:
5.3 maximumWriteValueLength,canSendWriteWithoutResponse,peripheralIsReady
5.3.1 用我这的蓝牙串口meek实测的发现(我的蓝牙串口应该是有点问题)
发现1
如下图,写无回复前,canSendWriteWithoutResponse的值为true,之后为false,之后peripheralIsReady代理方法被调用canSendWriteWithoutResponse的值又变为true.
如果,写的data的数据长度超过了maximumWriteValueLength:20,则peripheralIsReady代理方法不会被调用。发下一包数据前canSendWriteWithoutResponse的值还是为false. 发一包小于20的数据后会恢复正常
发现2
下面两张蓝牙串口收到数据的图,结合5.3.1的两张截图。当发的数据是120时虽然远远超过了maximumWriteValueLength:20,但还是可以收到,而且是分包接收,每包最大长度为32。
当长度为180时,串口这边就收不到了。但再发一包小于20的数据,通讯可以恢复正常:发数据前canSendWriteWithoutResponse的值为true,发完后peripheralIsReady代理方法会被调用。
长度为480个的时候,蓝牙串口直接失效。和app断开,而且搜不到了。要拔了重插。如下面的图3
图1
图2
图3
发现3
这个蓝牙串口peripheral.maximumWriteValueLength(for: .withResponse)为512. 但是我一包发480个数据,串口还是直接会挂掉。这应该是蓝牙串口的问题
5.3.2 用写无回复writeWithoutResponse分包发大量数据时,打印结果如下截图
6.从5中得到的启示:.withResponse类似TCP,可靠传输,速度慢,每包写完都有回应,每包传的数据大。.withoutResponse类似UDP,不可靠传输,每包传完没有回应,传输速度快,每包传的数据小
7. 蓝牙外设特征属性为.read
7.1 给read特征赋一个固定的值
1.permissions只能为.readable. 不能为[.readable, .writable]
//'Characteristics with cached values must be read-only'
let read = CBMutableCharacteristic(type: characteristicReadUUID, properties: .read, value: Data(bytes: [9, 10, 11]), permissions: .readable)
2.赋值后就不能改变,蓝牙中心read时,下面的代理方法不会被调用
func peripheralManager(_ peripheral: CBPeripheralManager, didReceiveRead request: CBATTRequest) {
print(#function)
}
7.2 动态赋值
1.value参数赋值为nil,permissions参数可以赋值为[.readable, .writable]
let read = CBMutableCharacteristic(type: characteristicReadUUID, properties: [.read,.write, value: nil, permissions: [.readable, .writable])
2.当蓝牙中心读数据时下面的代理方法会被调用,request.value就是蓝牙中的读到的值
func peripheralManager(_ peripheral: CBPeripheralManager, didReceiveRead request: CBATTRequest) {
print(#function)
print(request)
request.value = Data([2,3,4]) //蓝牙中心read到的值
peripheral.respond(to: request, withResult: .success)
}
参考博客:
蓝牙BLE: ATT和GATT的概念RxSwift 封装 CoreBluetooth(三) 连接RxSwift 封装 CoreBluetooth(四) 外设接口设计及实现