在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
看过一些蓝牙App的事例,大体上对蓝牙的连接过程进行了了解。但是开始真正自己写一个小的BLE程序的时候就举步维艰了。那些模棱两可的概念在头脑中瞬间就蒸发了,所以还是决定从最基本的蓝牙连接过程进行。这里所说的蓝牙是针对 bluetooth 4.0的。 第一步就是去看官方的关于蓝牙框架的文档,即Core Bluetooth Programming Guide,在苹果的官方网站上可以轻松找到,不管你对蓝牙的基本概念是否有了解,这个文件可以使你更好的对蓝牙的连接过程有个了解。这个文档的前面几张介绍了关于bluetooth 4.0开发过程中必要的概念(这些概念必不可少,一定要搞懂,否则后面会搞得很乱),真正开始将连接过程是从Performing Common Central Role Tasks 这一章开始,这里很清晰的将过程分成了以下这么几步,每一步对有对应的接口函数,只需要按着这一步一步写下去就可以。
针对每一步我将我的Swift所对应的代码列出来: Starting Up a Central Manager 将CBCenteralManager实例化,如下: 1 //start up a central manager object 2 func startCentralManager(){ 3 myCentralManager = CBCentralManager(delegate: self, queue: nil) 4 } 当实例化成功后,对调用如下函数: 1 func centralManagerDidUpdateState(central: CBCentralManager!){ 2 println("CentralManager is initialized") 3 4 switch central.state{ 5 case CBCentralManagerState.Unauthorized: 6 println("The app is not authorized to use Bluetooth low energy.") 7 case CBCentralManagerState.PoweredOff: 8 println("Bluetooth is currently powered off.") 9 case CBCentralManagerState.PoweredOn: 10 println("Bluetooth is currently powered on and available to use.") 11 default:break 12 } 13 } 此时CBCenteralManager实例化完毕,就可以开始进行扫描外设了。 2、Discovering Peripheral Devices That Are Advertising OC中扫描函数是: 1 [myCentralManager scanForPeripheralsWithServices:nil options:nil];
在swift中对应的是: 1 myCentralManager!.scanForPeripheralsWithServices(nil , options: nil)
当发现设备后,会调用如下的函数,这样我们就可以对设备进行一定的操作,当发现设备后接下来应该是连接设备。 1 func centralManager(central: CBCentralManager!, didDiscoverPeripheral peripheral: CBPeripheral!, advertisementData: [NSObject : AnyObject]!, RSSI: NSNumber!) { 2 println("CenCentalManagerDelegate didDiscoverPeripheral") 3 println("Discovered \(peripheral.name)") 4 println("Rssi: \(RSSI)") 5 6 println("Stop scan the Ble Devices") 7 myCentralManager!.stopScan() 8 cbPeripheral = peripheral 9 10 }
3、Connecting to a Peripheral Device After You’ve Discovered It OC中连接设备的代码是: 1 [myCentralManager connectPeripheral:peripheral options:nil];
Swift中的代码是: 1 myCentralManager!.connectPeripheral(cbPeripheral!, options: nil)
连接的结果会调用下面三个回调函数 1 func centralManager(central: CBCentralManager!, didConnectPeripheral peripheral: CBPeripheral!) { 2 println("CenCentalManagerDelegate didConnectPeripheral") 3 println("Connected with \(peripheral.name)") 4 peripheral.delegate = self 5 6 peripheral.discoverServices(nil) 7 } 8 9 func centralManager(central: CBCentralManager!, didFailToConnectPeripheral peripheral: CBPeripheral!, error: NSError!) { 10 println("CenCentalManagerDelegate didFailToConnectPeripheral") 11 } 12 13 func centralManager(central: CBCentralManager!, didDisconnectPeripheral peripheral: CBPeripheral!, error: NSError!) { 14 println("CenCentalManagerDelegate didDisconnectPeripheral") 15 } 具体含义可以查询官方文档。 注意:连接设备的函数不能在didDiscoverPeripheral回调函数中直接调用,这样是无法连接的,这个问题也困扰了我一会,后面歪打正着就成了, 要么设一个延迟再去connect,要么加个按钮触发事件再去连接。
4、Discovering the Services of a Peripheral That You’re Connected To 当连接完毕后,就是扫描这个外设(Peripheral)所支持服务。然后可以保存下来,下次可以直接调用 OC中扫描Services的代码如下: 1 [peripheral discoverServices:nil];
Swift中如下: 1 peripheral.discoverServices(nil)
当扫描到Service后对调用下面的回调函数: 1 func peripheral(peripheral: CBPeripheral!, didDiscoverServices error: NSError!) { 2 println("CBPeripheralDelegate didDiscoverServices") 3 for service in peripheral.services { 4 println("Discover service \(service)") 5 println("UUID \(service.UUID)") 6 if(service.UUID == CBUUID.UUIDWithString("1802")){ 7 println("Immediate_Alert_Service") 8 immediateAlertService = (service as CBService) 9 peripheral.discoverCharacteristics(nil , forService: immediateAlertService) 10 }else if(service.UUID == CBUUID.UUIDWithString("1803")){ 11 println("Link_Loss_Service") 12 linkLossAlertService = (service as CBService) 13 peripheral.discoverCharacteristics(nil , forService: linkLossAlertService) 14 } 15 } 16 } 扫描到Service后,要遍历这个Service所包含的Characteristics。 5、Discovering the Characteristics of a Service 扫描Characteristics 1 peripheral.discoverCharacteristics(nil , forService: linkLossAlertService)
和扫描Services一样,会有回调函数 1 func peripheral(peripheral: CBPeripheral!, didDiscoverCharacteristicsForService service: CBService!, error: NSError!) { 2 for characteristic in service.characteristics{ 3 4 if(service == immediateAlertService && characteristic.UUID == CBUUID.UUIDWithString("2A06")){ 5 println("immediateAlertService Discover characteristic \(characteristic)") 6 alertLevelCharacteristic = (characteristic as CBCharacteristic) 7 //immediateAlertCharacter 写入是有问题的 8 // cbPeripheral!.writeValue(NSData(bytes: &alertLevel, length: 1), forCharacteristic: characteristic as CBCharacteristic, type: CBCharacteristicWriteType.WithResponse) 9 }else if(service == linkLossAlertService && characteristic.UUID == CBUUID.UUIDWithString("2A06")){ 10 println("linkLossAlertService Discover characteristic \(characteristic)") 11 linkLossAlertCharacteristic = (characteristic as CBCharacteristic) 12 //linkLossAlertCharacteristic 写入没有问题,所以通过这个写入来进行绑定 13 cbPeripheral!.writeValue(NSData(bytes: &alertLevel, length: 1), forCharacteristic: characteristic as CBCharacteristic, type: CBCharacteristicWriteType.WithResponse) 14 } 15 } 16 } 这样就把每个Service所对应的Characteristics给读取出来了。 6、Retrieving the Value of a Characteristic
1 cbPeripheral!.readValueForCharacteristic(alertLevelCharacteristic!)
值在回调函数中获取,在read之前,要注意这个Characteristic是否可读。 1 func peripheral(peripheral: CBPeripheral!, didUpdateValueForCharacteristic characteristic: CBCharacteristic!, error: NSError!) { 2 if(error != nil){ 3 println("Error Reading characteristic value: \(error.localizedDescription)") 4 }else{ 5 var data = characteristic.value 6 println("Update value is \(data)") 7 } 8 9 }
1 var alertLevel:Byte = 0x02 2 cbPeripheral!.writeValue(NSData(bytes: &alertLevel, length: 1), forCharacteristic: alertLevelCharacteristic!, type: CBCharacteristicWriteType.WithoutResponse) 写是否成功会根据CBCharacteristicWriteType来决定是否调用下面的回调函数: 1 func peripheral(peripheral: CBPeripheral!, didWriteValueForCharacteristic characteristic: CBCharacteristic!, error: NSError!) { 2 if(error != nil){ 3 println("Error writing characteristic value: \(error.localizedDescription)") 4 }else{ 5 println("Write value success!") 6 } 7 8 } 关于write我这里还有些注意的地方要强调!!!! 并不是每一个Characteristic都可以通过回调函数来查看它写入状态的。就比如针对 immediateAlertService(1802) 的 alertLevelCharacteristic(2A06),就是一个不能有response的Characteristic。刚开始我就一直用CBCharacteristicWriteType.WithResponse来进行写入始终不成功,郁闷坏了,最后看到每个Characteristic还有个属性值是指示这个的,我将每个Characteristic打印出来有如下信息: immediateAlertService Discover characteristic <CBCharacteristic: 0x15574d00, UUID = 2A06, properties = 0x4, value = (null), notifying = NO> linkLossAlertService Discover characteristic <CBCharacteristic: 0x15671d00, UUID = 2A06, properties = 0xA, value = (null), notifying = NO> 这个的properties是什么刚开始不知道,觉得他没意义,后面才注意到properties是Characteristic的一个参数,具体解释如下: Declaration SWIFT struct CBCharacteristicProperties : RawOptionSetType { init(_ value: UInt) var value: UInt static var Broadcast: CBCharacteristicProperties { get } static var Read: CBCharacteristicProperties { get } static var WriteWithoutResponse: CBCharacteristicProperties { get } static var Write: CBCharacteristicProperties { get } static var Notify: CBCharacteristicProperties { get } static var Indicate: CBCharacteristicProperties { get } static var AuthenticatedSignedWrites: CBCharacteristicProperties { get } static var ExtendedProperties: CBCharacteristicProperties { get } static var NotifyEncryptionRequired: CBCharacteristicProperties { get } static var IndicateEncryptionRequired: CBCharacteristicProperties { get } } OBJECTIVE-C typedef enum { CBCharacteristicPropertyBroadcast = 0x01, CBCharacteristicPropertyRead = 0x02, CBCharacteristicPropertyWriteWithoutResponse = 0x04, CBCharacteristicPropertyWrite = 0x08, CBCharacteristicPropertyNotify = 0x10, CBCharacteristicPropertyIndicate = 0x20, CBCharacteristicPropertyAuthenticatedSignedWrites = 0x40, CBCharacteristicPropertyExtendedProperties = 0x80, CBCharacteristicPropertyNotifyEncryptionRequired = 0x100, CBCharacteristicPropertyIndicateEncryptionRequired = 0x200, } CBCharacteristicProperties;
可以看到0x04对应的是CBCharacteristicPropertyWriteWithoutResponse 0x0A对应的是CBCharacteristicPropertyNotify 所以 immediateAlertService(1802) 的 alertLevelCharacteristic(2A06)是不能用CBCharacteristicWriteType.WithRespons进行写入,只能用CBCharacteristicWriteType.WithOutRespons。这样在以后的开发中可以对每个Characteristic的这个参数进行检查再进行设置。
最后讲一下关于蓝牙绑定的过程,在iOS中,没有讲当绑定的过程,直接就是扫描、连接、交互。从而很多人会认为,连接就是绑定了,其实不然。在iOS开发中,连接并没有完成绑定,在网上找到了个很好的解释:
就是当发生读写交互时,系统在会和外设进行绑定操作!!!
|
请发表评论