iOS--Core Bluetooth
2016-02-26 16:41
429 查看
Demo下载
在iOS中进行蓝牙传输应用开发常用的框架有如下几种:
GameKit.framework:iOS7之前的蓝牙通讯框架,从iOS7开始过期,但是目前多数应用还是基于此框架。
MultipeerConnectivity.framework:iOS7开始引入的新的蓝牙通讯开发框架,用于取代GameKit。
CoreBluetooth.framework:功能强大的蓝牙开发框架,要求设备必须支持蓝牙4.0。
现在CoreBluetooth越来越受欢迎,准备研究一下。
CoreBluetooth设计是类似于客户端-服务器端的设计,作为服务器端的设备称为外围设备(Peripheral),作为客户端的设备叫做中央设备(Central),CoreBlueTooth整个框架就是基于这两个概念来设计的。
外围设备和中央设备在CoreBluetooth中使用CBPeripheralManager和CBCentralManager表示。
CBPeripheralManager:外围设备通常用于发布服务、生成数据、保存数据。外围设备发布并广播服务,告诉周围的中央设备它的可用服务和特征。
CBCentralManager:中央设备使用外围设备的数据。中央设备扫描到外围设备后会就会试图建立连接,一旦连接成功就可以使用这些服务和特征。
外围设备和中央设备之间交互的桥梁是服务(CBService)和特征(CBCharacteristic),二者都有一个唯一的标识UUID(CBUUID类型)来唯一确定一个服务或者特征,每个服务可以拥有多个特征,下面是他们之间的关系:
图片来源于网络
1、创建一个外围设备通常分为以下几个步骤:
创建外围设备CBPeripheralManager对象并指定代理。
创建特征CBCharacteristic、服务CBSerivce并添加到外围设备
外围设备开始广播服务(startAdvertisting:)。
和中央设备CBCentral进行交互。
2、中央设备的创建一般可以分为如下几个步骤:
创建中央设备管理对象CBCentralManager并指定代理。
扫描外围设备,一般发现可用外围设备则连接并保存外围设备。
查找外围设备服务和特征,查找到可用特征则读取特征数据。
外围设备,代码如下
代码其实并没有很复杂,中心设备和外围设备的相互交流大概流程是这样的
外围设备管理器设置服务,特征 -->
外围设备管理器发出广播 -->
中心设备管理器发现外围设备 -->
找到需要的外围设备 -->
建立连接 --> 外围设备设置代理(这里在JLCentralViewController中设置)-->
外围设备寻找服务,特征这里在JLCentralViewController中设置) -->
外围设备发送通知,写,读等操作请求(这里在JLCentralViewController中设置) -->
外围设备管理器收到请求(didReceive...Requests),并调用代理方法 -->
外围设备管理器响应请求(respondToRequest)-->
外围设备接收到响应的回调(代理方法,这里在JLCentralViewController中设置)。
Demo下载
在iOS中进行蓝牙传输应用开发常用的框架有如下几种:
GameKit.framework:iOS7之前的蓝牙通讯框架,从iOS7开始过期,但是目前多数应用还是基于此框架。
MultipeerConnectivity.framework:iOS7开始引入的新的蓝牙通讯开发框架,用于取代GameKit。
CoreBluetooth.framework:功能强大的蓝牙开发框架,要求设备必须支持蓝牙4.0。
现在CoreBluetooth越来越受欢迎,准备研究一下。
CoreBluetooth设计是类似于客户端-服务器端的设计,作为服务器端的设备称为外围设备(Peripheral),作为客户端的设备叫做中央设备(Central),CoreBlueTooth整个框架就是基于这两个概念来设计的。
外围设备和中央设备在CoreBluetooth中使用CBPeripheralManager和CBCentralManager表示。
CBPeripheralManager:外围设备通常用于发布服务、生成数据、保存数据。外围设备发布并广播服务,告诉周围的中央设备它的可用服务和特征。
CBCentralManager:中央设备使用外围设备的数据。中央设备扫描到外围设备后会就会试图建立连接,一旦连接成功就可以使用这些服务和特征。
外围设备和中央设备之间交互的桥梁是服务(CBService)和特征(CBCharacteristic),二者都有一个唯一的标识UUID(CBUUID类型)来唯一确定一个服务或者特征,每个服务可以拥有多个特征,下面是他们之间的关系:
图片来源于网络
1、创建一个外围设备通常分为以下几个步骤:
创建外围设备CBPeripheralManager对象并指定代理。
创建特征CBCharacteristic、服务CBSerivce并添加到外围设备
外围设备开始广播服务(startAdvertisting:)。
和中央设备CBCentral进行交互。
2、中央设备的创建一般可以分为如下几个步骤:
创建中央设备管理对象CBCentralManager并指定代理。
扫描外围设备,一般发现可用外围设备则连接并保存外围设备。
查找外围设备服务和特征,查找到可用特征则读取特征数据。
外围设备,代码如下
#import "JLPeripheralViewController.h" #import <CoreBluetooth/CoreBluetooth.h> #define ServiceUUID @"A48D3B5C-353D-4093-8821-DDDEBFEFEA32" #define CharacteristicUUID @"6A3E4B28-522D-4B3B-82A9-D5E2004534FC" @interface JLPeripheralViewController ()<CBPeripheralManagerDelegate> - (IBAction)Start:(UIButton *)sender; - (IBAction)Send:(UIButton *)sender; @end @implementation JLPeripheralViewController { CBPeripheralManager *_PeripheralManager;// 外围设备管理器 CBMutableCharacteristic *_PerCharacteristic; // 特征值 NSMutableArray <CBCentral *>*_centrals;// 存储订阅特征的中心设备 } - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view. _centrals = [NSMutableArray array]; } - (IBAction)Start:(UIButton *)sender { NSLog(@"1111"); _PeripheralManager = [[CBPeripheralManager alloc] initWithDelegate:self queue:nil]; } - (IBAction)Send:(UIButton *)sender { [self _updateCharacteristicValue]; } #pragma mark - CBPeripheralManagerDelegate // 外围设备状态发生变化 -(void)peripheralManagerDidUpdateState:(CBPeripheralManager *)peripheral { NSLog(@"%ld",peripheral.state); if (peripheral.state == CBPeripheralManagerStatePoweredOn) { NSLog(@"蓝牙打开"); // 添加服务 [self _addService]; }else{ NSLog(@"蓝牙未开启,或不支持"); } } // 添加服务后调用 -(void)peripheralManager:(CBPeripheralManager *)peripheral didAddService:(CBService *)service error:(NSError *)error { if (!error) { NSLog(@"添加服务成功"); // 服务添加后开始广播 [peripheral startAdvertising:@{CBAdvertisementDataLocalNameKey:@"XIAOLE's Iphone"}]; }else{ NSLog(@"添加服务失败error:%@",error); } } -(void)peripheralManagerDidStartAdvertising:(CBPeripheralManager *)peripheral error:(NSError *)error { if (!error) { NSLog(@"服务启动"); }else{ NSLog(@"服务启动失败:%@",error); } } // 中心设备订阅特征调用 -(void)peripheralManager:(CBPeripheralManager *)peripheral central:(CBCentral *)central didSubscribeToCharacteristic:(CBCharacteristic *)characteristic { NSLog(@"中心设备订阅特征central:%@,characteristic:%@",central,characteristic); if (central) { // 保存中心设备 [_centrals addObject:central]; } } // 中心设备取消订阅特征 - (void)peripheralManager:(CBPeripheralManager *)peripheral central:(CBCentral *)central didUnsubscribeFromCharacteristic:(CBCharacteristic *)characteristic { NSLog(@"中心设备取消订阅特征:central%@,characteristic:%@",central,characteristic); } -(void)peripheralManager:(CBPeripheralManager *)peripheral didReceiveWriteRequests:(CBATTRequest *)request{ NSLog(@"didReceiveWriteRequests"); } -(void)peripheralManager:(CBPeripheralManager *)peripheral willRestoreState:(NSDictionary *)dic{ NSLog(@"willRestoreState"); } // 更新特征时调用 -(void)peripheralManagerIsReadyToUpdateSubscribers:(CBPeripheralManager *)peripheral { NSLog(@"ReadyToUpdateSubscribers"); } #pragma mark - - - (void)_addService { NSLog(@"添加服务"); // 特征 _PerCharacteristic = [[CBMutableCharacteristic alloc] initWithType:[CBUUID UUIDWithString:CharacteristicUUID] properties:CBCharacteristicPropertyNotify | CBCharacteristicPropertyRead |CBCharacteristicPropertyWrite value:nil permissions:CBAttributePermissionsWriteable]; // 创建服务 CBMutableService *service = [[CBMutableService alloc] initWithType:[CBUUID UUIDWithString:ServiceUUID] primary:YES]; // 设置服务的特征 [service setCharacteristics:@[_PerCharacteristic]]; // 外围设备添加服务 [_PeripheralManager addService:service]; } - (void)_updateCharacteristicValue { NSLog(@"更新特征值"); // 更新特征值 NSString *str = [@"特征值:" stringByAppendingString:[NSString stringWithFormat:@"%@",[NSDate date]]]; [_PeripheralManager updateValue:[str dataUsingEncoding:NSUTF8StringEncoding] forCharacteristic:_PerCharacteristic onSubscribedCentrals:_centrals]; } @end中心设备代码如下
#import "JLCentralViewController.h" #import <CoreBluetooth/CoreBluetooth.h> #define ServiceUUID @"A48D3B5C-353D-4093-8821-DDDEBFEFEA32" #define CharacteristicUUID @"6A3E4B28-522D-4B3B-82A9-D5E2004534FC" @interface JLCentralViewController ()<CBCentralManagerDelegate,CBPeripheralDelegate>//中央设备管理器代理,外围设备代理 - (IBAction)Start:(UIButton *)sender; @end @implementation JLCentralViewController { CBCentralManager *_CentralManager;// 中央设备管理器 NSMutableArray *_peripherals;// 发现的外围设备 } - (void)viewDidLoad { [super viewDidLoad]; _peripherals = [NSMutableArray array]; } - (IBAction)Start:(UIButton *)sender { // 设置代理为self,并将代理回调放在主线程中 _CentralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil]; } #pragma mark - CBCentralManagerDelegate // 必须实现的代理方法,中央设备管理器的状态发生改变时调用 -(void)centralManagerDidUpdateState:(CBCentralManager *)central { // 在这里判断CBCentralManager的stutas,并作出相应处理 /* stutas为枚举值,有以下几种 typedef NS_ENUM(NSInteger, CBCentralManagerState) { CBCentralManagerStateUnknown = 0, CBCentralManagerStateResetting, CBCentralManagerStateUnsupported, CBCentralManagerStateUnauthorized, CBCentralManagerStatePoweredOff, CBCentralManagerStatePoweredOn, }; */ NSLog(@"%ld",central.state); if (central.state == CBCentralManagerStatePoweredOn) { NSLog(@"蓝牙设备已打开"); // 扫描外围设备,serviceUUIDs设为nil会返回所有能扫描到的设备 [central scanForPeripheralsWithServices:nil options:@{CBCentralManagerScanOptionAllowDuplicatesKey:@YES}]; NSLog(@"正在扫描..."); }else{ NSLog(@"蓝牙未开启,或不支持"); } } -(void)centralManager:(CBCentralManager *)central willRestoreState:(NSDictionary<NSString *,id> *)dict { NSLog(@"RestoreState%@",dict); } // 发现外围设备 -(void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary<NSString *,id> *)advertisementData RSSI:(NSNumber *)RSSI { NSLog(@"发现外围设备"); // 停止扫描 [central stopScan]; NSLog(@"扫描停止"); if (![_peripherals containsObject:peripheral]) { [_peripherals addObject:peripheral]; } // 与外围设备建立连接 [central connectPeripheral:peripheral options:@{CBConnectPeripheralOptionNotifyOnConnectionKey:@YES}]; NSLog(@"开始连接外围设备"); } // 连接上外围设备 -(void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral { NSLog(@"连接上外围设备"); // 设置外围设备的代理 peripheral.delegate = self; // 外围设备搜寻服务,serviceUUIDs设为nil为搜索全部服务 [peripheral discoverServices:@[[CBUUID UUIDWithString:ServiceUUID]]]; NSLog(@"外围设备搜寻服务"); } // 丢失与外围设备的连接 -(void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error { NSLog(@"丢失连接"); } // 连接外围设备失败 -(void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error { NSLog(@"连接失败,%@",error); } #pragma mark - CBPeripheralDelegate // 发现服务调用 -(void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error { if (!error) { NSLog(@"发现服务"); // 找到指定服务,因为我前面已经写了搜寻指定服务,所以services应该有一个我指定的服务。写遍历,只是更好的认识外围设备--服务--特征之间的关系,后面搜索特征亦如此 for (CBService *service in peripheral.services) { if ([service.UUID.UUIDString isEqualToString:ServiceUUID]) { NSLog(@"找到指定服务"); // 寻找服务中的指定特征,characteristicUUIDs=nil则搜寻服务的所有特征 [peripheral discoverCharacteristics:@[[CBUUID UUIDWithString:CharacteristicUUID]] forService:service]; } } }else{ NSLog(@"未发现服务:%@",error); } } // 发现特征调用 -(void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(nonnull CBService *)service error:(nullable NSError *)error { if (!error) { NSLog(@"发现特征"); // 查找指定特征 for (CBCharacteristic *charcter in service.characteristics) { if ([charcter.UUID.UUIDString isEqualToString:CharacteristicUUID]) { NSLog(@"找到指定特征"); // 去到指定特征,根据特征值的属性(可通知,可读,可写。。),可以做相应的事 /** 通知 调用代理peripheral:didUpdateNotificationStateForCharacteristic:error **/ [peripheral setNotifyValue:YES forCharacteristic:charcter]; /** 读 调用代理peripheral:didUpdateValueForCharacteristic:error**/ [peripheral readValueForCharacteristic:charcter]; /** 写 调用peripheral:didWriteValueForCharacteristic:error **/ /* typedef NS_ENUM(NSInteger, CBCharacteristicWriteType) { CBCharacteristicWriteWithResponse = 0,// 写入成功有返回 CBCharacteristicWriteWithoutResponse,//写入成功无返回 }; */ [peripheral writeValue:[@"CoreBlueTooth Demo" dataUsingEncoding:NSUTF8StringEncoding] forCharacteristic:charcter type:CBCharacteristicWriteWithResponse]; } } } } // 外围设备管理器接收到中心设备是否订阅特征值后的回调 -(void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error { NSLog(@"特征值:%@",characteristic); } // 调用readValueForCharacteristic或外围设备更新特征值都会调用 -(void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error { NSLog(@"特征值:%@",characteristic); } //调用writeValue:forCharacteristic:type且type的值为CBCharacteristicWriteWithResponse 后的回调 -(void)peripheral:(CBPeripheral *)peripheral didWriteValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error { } @end
代码其实并没有很复杂,中心设备和外围设备的相互交流大概流程是这样的
外围设备管理器设置服务,特征 -->
外围设备管理器发出广播 -->
中心设备管理器发现外围设备 -->
找到需要的外围设备 -->
建立连接 --> 外围设备设置代理(这里在JLCentralViewController中设置)-->
外围设备寻找服务,特征这里在JLCentralViewController中设置) -->
外围设备发送通知,写,读等操作请求(这里在JLCentralViewController中设置) -->
外围设备管理器收到请求(didReceive...Requests),并调用代理方法 -->
外围设备管理器响应请求(respondToRequest)-->
外围设备接收到响应的回调(代理方法,这里在JLCentralViewController中设置)。
Demo下载
相关文章推荐
- LAoj 2678 - Subsequence (DP&技巧&排序)
- Guess the Permutation
- easyui datagrid 部分参数整理
- C# 项目迁移 Microsoft.VisualStudio.Tools.Office.BuildTasks 生成解决方法报错:请确认 <UsingTask> 声明正确,该程序集及其所有依赖项都可用
- Win8.1+Ubuntu双系统(UEFI+GPT)
- 取消UISearchbar背景色
- Property 'sqlSessionFactory' or 'sqlSessionTemplate' are required
- 给UIImage添加生成圆角图片的扩展API:
- iOS 键盘挡住UITextField
- iOS 事件响应者链的学习(也有叫 UI连锁链)
- Java中建造者(Builder)设计
- UINavigationController使用的注意事项
- android下Invalid layout of java.lang.String at value解决方法
- iOS之修改UIStatusbar 文字颜色
- win7 64位 旗舰版 右键菜单增加UE选项
- 详解 CALayer 和 UIView 的区别和联系
- 当键盘出现的时候,如何让UITextField自动上移
- Arduino Ethernet W5100扩展板的指示灯含义
- Arduino Ethernet W5100扩展板的指示灯含义
- OpenStack 系列之File Share Service(Manila) Install Guide