iOS - 蓝牙库CoreBluetooth核心内容之central

来源:互联网 发布:mysql 连接数查看 编辑:程序博客网 时间:2024/05/21 08:38

IOS蓝牙中心模式(central)简单来讲就是以你的手机为中心,连接其他的外设设备(Peripheral),每个设备可能会有一些服务,这个服务里面又会有一些特征,而特征的属性又分为读,写,通知几种方式。

我们先看下初始化API

 *  @method initWithDelegate:queue: * *  @param delegate The delegate that will receive central role events. *  @param queue    The dispatch queue on which the events will be dispatched. * *  @discussion     The initialization call. The events of the central role will be dispatched on the provided queue. *                  If <i>nil</i>, the main queue will be used. * */- (instancetype)initWithDelegate:(nullable id<CBCentralManagerDelegate>)delegate   queue:(nullable dispatch_queue_t)queue;
接着我们创建对象
CBCentralManager *manager;

然后初始化,遵循CBCentralManagerDelegate协议,线程参数我们可以写成nil,上面API已经明确说明,默认主线程

manager = [[CBCentralManager alloc]initWithDelegate:self queue:nil];

同样我们先看下CBCentralManagerDelegate协议API,这里只看需要用到的协议方法,其他自己去看

 *  @method centralManagerDidUpdateState: * *  @param central  The central manager whose state has changed. * *  @discussion     Invoked whenever the central manager's state has been updated. Commands should only be issued when the state is *                  <code>CBCentralManagerStatePoweredOn</code>. A state below <code>CBCentralManagerStatePoweredOn</code> *                  implies that scanning has stopped and any connected peripherals have been disconnected. If the state moves below *                  <code>CBCentralManagerStatePoweredOff</code>, all <code>CBPeripheral</code> objects obtained from this central *                  manager become invalid and must be retrieved or discovered again. * *  @see            state * */- (void)centralManagerDidUpdateState:(CBCentralManager *)central;

从API可看出,这个方法是检测蓝牙状态的,有好多种状态,当确认蓝牙已打开开始扫描外设

- (void)centralManagerDidUpdateState:(CBCentralManager *)central{    switch (central.state) {        case CBCentralManagerStateUnknown:            NSLog(@"CBCentralManagerStateUnknown---》未知");            break;        case CBCentralManagerStateResetting:            NSLog(@"CBCentralManagerStateResetting---》正在重置");            break;        case CBCentralManagerStateUnsupported:            NSLog(@"CBCentralManagerStateUnsupported---》不支持");            break;        case CBCentralManagerStateUnauthorized:            NSLog(@"CBCentralManagerStateUnauthorized---》设备未授权");            break;        case CBCentralManagerStatePoweredOff:            NSLog(@"CBCentralManagerStatePoweredOff---》关闭");            break;        case CBCentralManagerStatePoweredOn:            NSLog(@"CBCentralManagerStatePoweredOn---》打开");            // 这里已确认蓝牙已打开才开始扫描周围的外设。第一个参数nil就是扫描周围所有的外设。            [central scanForPeripheralsWithServices:nil options:nil];            break;        default:            break;    }}

这里要注意是只有确认蓝牙已经打开才能开始扫描外设,不然可能会出错。补充下扫描外设方法的API

/*! *  @method scanForPeripheralsWithServices:options: * *  @param serviceUUIDs A list of <code>CBUUID</code> objects representing the service(s) to scan for. *  @param options      An optional dictionary specifying options for the scan. * *  @discussion         Starts scanning for peripherals that are advertising any of the services listed in <i>serviceUUIDs</i>. Although strongly discouraged, *                      if <i>serviceUUIDs</i> is <i>nil</i> all discovered peripherals will be returned. If the central is already scanning with different *                      <i>serviceUUIDs</i> or <i>options</i>, the provided parameters will replace them. *                      Applications that have specified the <code>bluetooth-central</code> background mode are allowed to scan while backgrounded, with two *                      caveats: the scan must specify one or more service types in <i>serviceUUIDs</i>, and the <code>CBCentralManagerScanOptionAllowDuplicatesKey</code> *                      scan option will be ignored. * *  @see                centralManager:didDiscoverPeripheral:advertisementData:RSSI: *  @seealso            CBCentralManagerScanOptionAllowDuplicatesKey *@seealsoCBCentralManagerScanOptionSolicitedServiceUUIDsKey * */- (void)scanForPeripheralsWithServices:(nullable NSArray<CBUUID *> *)serviceUUIDs options:(nullable NSDictionary<NSString *, id> *)options;
从API可以看出,第一个参数为nil意味着扫描所有的外设,当扫描到外设会进入下面的协议方法

/*! *  @method centralManager:didDiscoverPeripheral:advertisementData:RSSI: * *  @param central              The central manager providing this update. *  @param peripheral           A <code>CBPeripheral</code> object. *  @param advertisementData    A dictionary containing any advertisement and scan response data. *  @param RSSI                 The current RSSI of <i>peripheral</i>, in dBm. A value of <code>127</code> is reserved and indicates the RSSI *was not available. * *  @discussion                 This method is invoked while scanning, upon the discovery of <i>peripheral</i> by <i>central</i>. A discovered peripheral must *                              be retained in order to use it; otherwise, it is assumed to not be of interest and will be cleaned up by the central manager. For *                              a list of <i>advertisementData</i> keys, see {@link CBAdvertisementDataLocalNameKey} and other similar constants. * *  @seealso                    CBAdvertisementData.h * */- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary<NSString *, id> *)advertisementData RSSI:(NSNumber *)RSSI;
这里值得提一下的是可以根据RSSI的值大概估计出外设设备离我们的中心设备有多远,下面实现这个协议方法
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral     advertisementData:(NSDictionary *)advertisementData                  RSSI:(NSNumber *)RSSI{    if ([peripheral.name isEqualToString:@"BLE-Bridge"]) {        // 开始连接外设        [manager connectPeripheral:peripheral options:nil];        NSLog(@"扫描的外设名称:%@",peripheral.name);        NSLog(@"扫描的外设广播名:%@",[advertisementData valueForKeyPath:CBAdvertisementDataLocalNameKey]);    }}
注意这里我做了限制,只有扫描到名为"BLE-Bridge"的外设才开始进行连接,连接的过程中,会有断开,失败,成功几种情况,这几种情况分别会进入不同的协议方法,下面先依次附上这几种情况的API

断开:

/*! *  @method centralManager:didDisconnectPeripheral:error: * *  @param central      The central manager providing this information. *  @param peripheral   The <code>CBPeripheral</code> that has disconnected. *  @param error        If an error occurred, the cause of the failure. * *  @discussion         This method is invoked upon the disconnection of a peripheral that was connected by {@link connectPeripheral:options:}. If the disconnection *                      was not initiated by {@link cancelPeripheralConnection}, the cause will be detailed in the <i>error</i> parameter. Once this method has been *                      called, no more methods will be invoked on <i>peripheral</i>'s <code>CBPeripheralDelegate</code>. * */- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(nullable NSError *)error;
失败:

/*! *  @method centralManager:didFailToConnectPeripheral:error: * *  @param central      The central manager providing this information. *  @param peripheral   The <code>CBPeripheral</code> that has failed to connect. *  @param error        The cause of the failure. * *  @discussion         This method is invoked when a connection initiated by {@link connectPeripheral:options:} has failed to complete. As connection attempts do not *                      timeout, the failure of a connection is atypical and usually indicative of a transient issue. * */- (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(nullable NSError *)error;
成功:

/*! *  @method centralManager:didConnectPeripheral: * *  @param central      The central manager providing this information. *  @param peripheral   The <code>CBPeripheral</code> that has connected. * *  @discussion         This method is invoked when a connection initiated by {@link connectPeripheral:options:} has succeeded. * */- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral;
假如断开或者失败了你可以分别打印相应的信息看什么原因再做处理,这里我们实现成功的协议方法
- (void)centralManager:(CBCentralManager *)central  didConnectPeripheral:(CBPeripheral *)peripheral{    [peripheral setDelegate:self];    [peripheral discoverServices:nil];}
可以看到,当我们连接外设成功后,实现外设的代理CBPeripheralDelegate,并开始扫描服务,这里的参数为nil代表扫描外设所有的服务,详情看下面API
/*! *  @method discoverServices: * *  @param serviceUUIDs A list of <code>CBUUID</code> objects representing the service types to be discovered. If <i>nil</i>, *all services will be discovered, which is considerably slower and not recommended. * *  @discussionDiscovers available service(s) on the peripheral. * *  @seeperipheral:didDiscoverServices: */- (void)discoverServices:(nullable NSArray<CBUUID *> *)serviceUUIDs;
当我们扫描到服务会进入下面协议方法,先附上API

/*! *  @method peripheral:didDiscoverServices: * *  @param peripheralThe peripheral providing this information. *@param errorIf an error occurred, the cause of the failure. * *  @discussionThis method returns the result of a @link discoverServices: @/link call. If the service(s) were read successfully, they can be retrieved via *<i>peripheral</i>'s @link services @/link property. * */- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(nullable NSError *)error;
从这个代理方法里面你也可以打印扫描服务失败的错误原因,下面实现这个代理
- (void)peripheral:(CBPeripheral *)peripheraldidDiscoverServices:(NSError *)error{    if (error) {        NSLog(@"扫描服务失败,原因:%@",[error localizedDescription]);        return;    }    for (CBService *service in peripheral.services) {        if ([service.UUID.UUIDString isEqualToString:@"FFF0"]) {            // 扫描每个service的Characteristics            [peripheral discoverCharacteristics:nil forService:service];        }    }}
解释下,首先判断扫描服务是否成功,否则return。如果扫描服务成功,因为每个外设可能不止一个服务,所以这里用了for循环,而根据和硬件的协议,这里只取UUID为"FFF0"的服务,接着开始扫描这个服务的特征,下面附上扫描特征的API

/*! *  @method discoverCharacteristics:forService: * *  @param characteristicUUIDsA list of <code>CBUUID</code> objects representing the characteristic types to be discovered. If <i>nil</i>, *all characteristics of <i>service</i> will be discovered, which is considerably slower and not recommended. *  @param serviceA GATT service. * *  @discussionDiscovers the specified characteristic(s) of <i>service</i>. * *  @seeperipheral:didDiscoverCharacteristicsForService:error: */- (void)discoverCharacteristics:(nullable NSArray<CBUUID *> *)characteristicUUIDs forService:(CBService *)service;
参数nil从API可以看出是扫描这个服务下面的所有特征,当扫描到特征后,进入下面的协议方法,同样先附上API

/*! *  @method peripheral:didDiscoverCharacteristicsForService:error: * *  @param peripheralThe peripheral providing this information. *  @param serviceThe <code>CBService</code> object containing the characteristic(s). *@param errorIf an error occurred, the cause of the failure. * *  @discussionThis method returns the result of a @link discoverCharacteristics:forService: @/link call. If the characteristic(s) were read successfully,  *they can be retrieved via <i>service</i>'s <code>characteristics</code> property. */- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(nullable NSError *)error;
下面实现这个方法

- (void)peripheral:(CBPeripheral *)peripheraldidDiscoverCharacteristicsForService:(CBService *)service             error:(NSError *)error{    if (error) {        NSLog(@"扫描特征失败,原因: %@", [error localizedDescription]);        return;    }    for (CBCharacteristic *characteristic in service.characteristics) {        if ([characteristic.UUID.UUIDString isEqualToString:@"FF0A"]) {            [peripheral setNotifyValue:YES forCharacteristic:characteristic];        }        if ([characteristic.UUID.UUIDString isEqualToString:@"FF0B"]) { //写入            {                Byte dataArr[2];                dataArr[0]=0x55; dataArr[1]=0x01;                NSData *myData = [NSData dataWithBytes:dataArr length:2];                [peripheral writeValue:myData forCharacteristic:characteristic type:CBCharacteristicWriteWithResponse];            }        }    }}
解释下,同样如果扫描特征失败,直接return。每个服务下面可能有很多特征,这里我取了UUID为"FF0A" 和 UUID为"FF0B"的特征,从代码中可以看出,对前者的操作是启用通知,对后者的操作是写入数据,这些操作的前提必须是这个特征具备这个权限,假如这个特征能写,能读,那你可以进行读写操作,否则不行。先附上启用通知和写入数据API

启用通知:

/*! *  @method setNotifyValue:forCharacteristic: * *  @param enabledWhether or not notifications/indications should be enabled. *  @param characteristicThe characteristic containing the client characteristic configuration descriptor. * *  @discussionEnables or disables notifications/indications for the characteristic value of <i>characteristic</i>. If <i>characteristic</i> *allows both, notifications will be used. *                          When notifications/indications are enabled, updates to the characteristic value will be received via delegate method  *                          @link peripheral:didUpdateValueForCharacteristic:error: @/link. Since it is the peripheral that chooses when to send an update, *                          the application should be prepared to handle them as long as notifications/indications remain enabled. * *  @seeperipheral:didUpdateNotificationStateForCharacteristic:error: *  @seealso                CBConnectPeripheralOptionNotifyOnNotificationKey */- (void)setNotifyValue:(BOOL)enabled forCharacteristic:(CBCharacteristic *)characteristic;
写入数据:

/*! *  @method writeValue:forCharacteristic:type: * *  @param dataThe value to write. *  @param characteristicThe characteristic whose characteristic value will be written. *  @param typeThe type of write to be executed. * *  @discussionWrites <i>value</i> to <i>characteristic</i>'s characteristic value. *If the <code>CBCharacteristicWriteWithResponse</code> type is specified, {@link peripheral:didWriteValueForCharacteristic:error:} *is called with the result of the write request. *If the <code>CBCharacteristicWriteWithoutResponse</code> type is specified, the delivery of the data is best-effort and not *guaranteed. * *  @seeperipheral:didWriteValueForCharacteristic:error: *@seeCBCharacteristicWriteType */- (void)writeValue:(NSData *)data forCharacteristic:(CBCharacteristic *)characteristic type:(CBCharacteristicWriteType)type;
当对一个特征启用通知操作后,这个特征值有变化时会调用下面方法,附上API

/*! *  @method peripheral:didUpdateValueForCharacteristic:error: * *  @param peripheralThe peripheral providing this information. *  @param characteristicA <code>CBCharacteristic</code> object. *@param errorIf an error occurred, the cause of the failure. * *  @discussionThis method is invoked after a @link readValueForCharacteristic: @/link call, or upon receipt of a notification/indication. */- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(nullable NSError *)error;
当对一个特征进行写入操作后,写入成功或者失败会调用下面方法,附上API
/*! *  @method peripheral:didWriteValueForCharacteristic:error: * *  @param peripheralThe peripheral providing this information. *  @param characteristicA <code>CBCharacteristic</code> object. *@param errorIf an error occurred, the cause of the failure. * *  @discussionThis method returns the result of a {@link writeValue:forCharacteristic:type:} call, when the <code>CBCharacteristicWriteWithResponse</code> type is used. */ - (void)peripheral:(CBPeripheral *)peripheral didWriteValueForCharacteristic:(CBCharacteristic *)characteristic error:(nullable NSError *)error;


以上,整体上就是这个流程!
0 0
原创粉丝点击