BLE中心模式流程-coding
BLE中心模式流程
- 1.建立中心角色
- 2.扫描外设(Discover Peripheral)
- 3.连接外设(Connect Peripheral)
- 4.扫描外设中的服务和特征(Discover Services And Characteristics)
* 4.1 获取外设的services
* 4.2 获取外设的Characteristics,获取characteristics的值,,获取Characteristics的Descriptor和Descriptor的值
- 5.利用特征与外设做数据交互(Explore And Interact)
- 6.订阅Characteristic的通知
- 7.断开连接(Disconnect)
## 准备环境
- 1.Xcode7.0
- 2.手机
- 3.外设(手机+LightBlue)
#import "CentralViewController.h" // BLE 框架 #import <CoreBluetooth/CoreBluetooth.h> @interface CentralViewController ()<CBCentralManagerDelegate, CBPeripheralDelegate> /** 中心管理者 */ PROPERTYSTRONG(CBCentralManager, cMgr) /** 连接到的外设 */ PROPERTYSTRONG(CBPeripheral, cPeriphery) @end @implementation CentralViewController /** * 懒加载 * * @ 需要调用完成对象初始化 */ - (CBCentralManager *)cMgr { if (!_cMgr) { _cMgr = [[CBCentralManager alloc] initWithDelegate:self queue:dispatch_get_main_queue() options:nil]; } return _cMgr; } - (void)viewDidLoad { [super viewDidLoad]; self.title = @"CentralViewController"; // 在ios5之前, 再通过以下方法设置背景时, 有闪屏bug // self.view.backgroundColor = [UIColor colorWithPatternImage:<#(nonnull UIImage *)#>]; // // 解决方案 // self.view.layer.contents = (id)[UIColor colorWithPatternImage:[UIImage imageNamed:xxx]]; // 0. 创建管理者对象 #pragma mark - #pragma mark - - 1.建立中心角色 [self cMgr]; } // 通常在此需要 断开连接外设 - (void)viewWillDisappear:(BOOL)animated { [super viewWillDisappear:animated]; // 此处断开连接外设 [self yf_dismissConnectedWithPeripheral:self.cPeriphery]; } #pragma mark - CBCentralManagerDelegate /** * @1 只要中心管理者初始化, 就会触发此方法 */ - (void)centralManagerDidUpdateState:(CBCentralManager *)central { switch (central.state) { // 开启 case CBCentralManagerStateUnknown: { // 未知 LogRed(@"CBCentralManagerState--- Unknown"); break; } case CBCentralManagerStateResetting: { // 重置 LogRed(@"CBCentralManagerState--- Resetting"); break; } case CBCentralManagerStateUnsupported: { // 不支持 LogRed(@"CBCentralManagerState--- Unsupported"); break; } case CBCentralManagerStateUnauthorized: { // 未授权 LogRed(@"CBCentralManagerState--- Unauthorized"); break; } case CBCentralManagerStatePoweredOff: { // 关闭 LogRed(@"CBCentralManagerState---- PoweredOff"); break; } case CBCentralManagerStatePoweredOn: { // 开启 LogRed(@"CBCentralManagerState--- PoweredOn"); #pragma mark - #pragma mark - - 2.扫描外设(Discover Peripheral) // 1. 搜索外设 [self.cMgr scanForPeripheralsWithServices:nil // 通过某些服务, 筛选外设 options:nil]; break; } } } /*! * @method centralManager:willRestoreState: **/ - (void)centralManager:(CBCentralManager *)central willRestoreState:(NSDictionary<NSString *, id> *)dict{ } /*! *****@2 常用方法 - 发现外设触发此方法 * @method centralManager:didDiscoverPeripheral:advertisementData:RSSI: * */ - (void)centralManager:(CBCentralManager *)central // 中心管理者 didDiscoverPeripheral:(CBPeripheral *)peripheral // 外设 advertisementData:(NSDictionary<NSString *, id> *)advertisementData // 外设携带的数据 RSSI:(NSNumber *)RSSI // 外设信号强度 { /** peripheral - <CBPeripheral: 0x1666faa0, identifier = E57942BE-7941-DC11-1CD9-CEA1725456DF, name = (null), state = disconnected> advertisementData - { kCBAdvDataIsConnectable = 0; kCBAdvDataManufacturerData = <75004204 018020fc 8f90a492 9bfe8f90 a4929a01 00000000 0000>; } */ LogYellow(@"%@\n -- %@\n --%@\n --%@\n", central, peripheral, advertisementData, RSSI); // 需要对连接到的设备进行过滤 // 1. 信号强度(大于35) // 2. 设备名(前缀 "0") [peripheral.name hasPrefix:@"0"] && if((ABS(RSSI.integerValue) > 35)){ // 在此处对我们的 advertisementData, 进行处理 // 此处应该讲得到的外设存储到可变数组中 // 以下对一个外设处理: // 让外设的生命周期 == VC self.cPeriphery = peripheral; #pragma mark - #pragma mark - - 3.连接外设(Connect Peripheral) // 发现外设之后进行连接 [self.cMgr connectPeripheral:self.cPeriphery options:nil]; } } /*! *****@3 中心管理者成功连接外设后, 会触发此方法 * @method centralManager:didConnectPeripheral: * */ - (void)centralManager:(CBCentralManager *)central // 中心管理者 didConnectPeripheral:(CBPeripheral *)peripheral // 外设 { LogBlue(@"%@\n --- %@", central, peripheral); // 连接成功后可以进行数据交互 // 3.1 获取外设的服务 self.cPeriphery.delegate = self; #pragma mark - #pragma mark - - 4.扫描外设中的服务和特征(Discover Services And Characteristics) // 3.2 外设发现所有服务, nil代表不过滤 // 触发: - (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error [self.cPeriphery discoverServices:nil]; } /*! *** 外设连接失败 * @method centralManager:didFailToConnectPeripheral:error: */ - (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(nullable NSError *)error{ LogGreen(@"error - %@ ", error); } /*! *** 断开连接 * @method centralManager:didDisconnectPeripheral:error: * */ - (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(nullable NSError *)error{ LogGreen(@"error - %@ ", error); } #pragma mark - CBPeripheryDelegate /** * 外设发现服务 触发此代理方法 */ #warning 以下方法中只要error, 都要容错处理 - (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error { // 容错处理 [self dealError:error]; #pragma mark - - * 4.1 获取外设的services // 遍历外设的所有服务 for (CBService *service in peripheral.services) { // 发现服务后, 让外设发现服务内部 特征 // 触发: - (void)peripheral: didDiscoverCharacteristicsForService: error: [peripheral discoverCharacteristics:nil forService:service]; } LogGreen(@"%@", peripheral); } /** * 发现外设服务里面特征后 触发此代理方法 * * @param peripheral 外设 * @param service 服务 * @param error 错误 */ - (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error { [self dealError:error]; #pragma mark - - * 4.2 获取外设的Characteristics和Descriptor for (CBCharacteristic *character in service.characteristics) { // 获取特征对应的描述 // 触发: - didUpdateValueForDescriptor [peripheral discoverDescriptorsForCharacteristic:character]; // 获取特征的值 // 触发: - didUpdateValueForCharacteristic: [peripheral readValueForCharacteristic:character]; #warning 在此处调用写入数据方法 // [self yf_peripheral:peripheral didWriteData:<#(NSData *)#> forCharacteristic:character]; } } /** * 更新特征的时候就会 触发此方法 * * @param peripheral 外设 * @param characteristic 对应的服务的特征 * @param error 错误 */ - (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error { LogRed(@"%s", __FUNCTION__); [self dealError:error]; for (CBDescriptor *descriptor in characteristic.descriptors) { // 获取特征描述值 // 触发: - didDiscoverDescriptorsForCharacteristic [peripheral readValueForDescriptor:descriptor]; } } /** * 更新特征的描述的值时, 触发此方法 * * @param peripheral 外设 * @param descriptor 外设对应服务的特征的描述 * @param error 错误 */ - (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForDescriptor:(CBDescriptor *)descriptor error:(NSError *)error { LogRed(@"%s", __FUNCTION__); [self dealError:error]; // 当前描述更新时, 直接调用此方法 [peripheral readValueForDescriptor:descriptor]; } /** * 发现外设服务特征中的描述, 触发此方法 * * @param peripheral 外设 * @param characteristic 服务对应的特征 * @param error 错误 */ - (void)peripheral:(CBPeripheral *)peripheral didDiscoverDescriptorsForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error { LogRed(@"%s", __FUNCTION__); [self dealError:error]; // 此处读取描述即可 for (CBDescriptor *descriptor in characteristic.descriptors) { [peripheral readValueForDescriptor:descriptor]; } } // 容错处理 - (void)dealError:(NSError *)error { if (error) { LogRed(@"error - %@", error.localizedDescription); return; } } #pragma mark 自定义方法 #pragma mark - #pragma mark - - 5.利用特征与外设做数据交互(Explore And Interact) /** * 外设 写数据到特征中 * [注意]: 需要判断, 特征的属性是否支持写入 */ - (void)yf_peripheral:(CBPeripheral *)peripheral didWriteData:(NSData *)data forCharacteristic:(nonnull CBCharacteristic *)charcteristic { /** typedef NS_OPTIONS(NSUInteger, CBCharacteristicProperties) { CBCharacteristicPropertyBroadcast = 0x01, CBCharacteristicPropertyRead = 0x02, CBCharacteristicPropertyWriteWithoutResponse = 0x04, CBCharacteristicPropertyWrite = 0x08, CBCharacteristicPropertyNotify = 0x10, CBCharacteristicPropertyIndicate = 0x20, CBCharacteristicPropertyAuthenticatedSignedWrites = 0x40, CBCharacteristicPropertyExtendedProperties = 0x80, CBCharacteristicPropertyNotifyEncryptionRequired NS_ENUM_AVAILABLE(NA, 6_0) = 0x100, CBCharacteristicPropertyIndicateEncryptionRequired NS_ENUM_AVAILABLE(NA, 6_0) = 0x200 }; */ LogYellow(@"char.pro = %d", charcteristic.properties); // 由于枚举属性是 NS_OPTIONS类型, 所有一个枚举可能对应多个类型, 判断不能用 = , 应该用&(包含) if (charcteristic.properties & CBCharacteristicPropertyWrite) { // 核心代码 --- [peripheral writeValue:data // 写入的数据 forCharacteristic:charcteristic // 特征 type:CBCharacteristicWriteWithResponse]; // 通过此响应记录是否成功写入 } } #pragma mark - #pragma mark - - 6.订阅Characteristic的通知 // 订阅通知和取消订阅 // [注意]: 一般根据项目的具体需求确定, 以下方法在哪调用 - (void)yf_peripheral:(CBPeripheral *)peripheral regNotifyWithCharacteristic:(nonnull CBCharacteristic *)charcteristic { // 外设为特征 订阅通知 // 触发: - didUpdateValueForCharacteristic:方法 [peripheral setNotifyValue:YES forCharacteristic:charcteristic]; } - (void)yf_peripheral:(CBPeripheral *)peripheral cancelNotifyWithCharacteristic:(nonnull CBCharacteristic *)charcteristic { // 外设为特征 取消订阅通知 // 触发: - didUpdateValueForCharacteristic:方法 [peripheral setNotifyValue:NO forCharacteristic:charcteristic]; } #pragma mark - #pragma mark - - 7.断开连接(Disconnect) - (void)yf_dismissConnectedWithPeripheral:(CBPeripheral *)peripheral { // 停止扫描 [self.cMgr stopScan]; // 断开连接 [self.cMgr cancelPeripheralConnection:peripheral]; } @end
demo时刻 我的github