IOS CoreBluetooth系列二:实战之本地 Central 和远程 Peripheral
2016-11-16 10:59
411 查看
前言:上文中我们主要是对CoreBluetooth一些术语和概念的介绍,接下来主要讲的是本地 Central 和远程 Peripheral。
大致步骤如下:
1、首先需要导入<CoreBluetooth/CoreBluetooth.h>这个框架,并在info配置Privacy - Bluetooth Peripheral Usage Description权限;
2、其次需要遵循CBCentralManagerDelegate,CBPeripheralDelegate这两个代理;
3、扫描外设;
3.1、懒加载创建中央设备;
- (CBCentralManager *)manager
{
if (!_manager) {
//1.创建中央设备
_manager = [[CBCentralManager alloc] initWithDelegate:self queue:nil];
}
return _manager;
}
3.2、利用中央设备扫描外设
#pragma mark 利用中央设备扫描外设设备
- (void)scanForPeripheral
{
NSDictionary *options = [NSDictionary dictionaryWithObject:[NSNumber numberWithBool:NO] forKey:CBCentralManagerScanOptionAllowDuplicatesKey];
//当没有指定对应的Services的时候,nil为全部
[self.manager scanForPeripheralsWithServices:nil options:options];
}
3.3、如果发现外设会执行centralManager:didDiscoverPeripheral:advertisementData:RSSI:这个方法;
#pragma mark 发现外设
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary<NSString *,id> *)advertisementData RSSI:(NSNumber *)RSSI
{
NSLog(@"查找设备peripheral is %@ name is %@",peripheral,peripheral.name);
//1.保存扫描得到设备,判断如果数组中不包含当前扫描到得外部设置才保存
NSMutableArray *uuidArray = [NSMutableArray array];
for (CBPeripheral *p in self.peripherals) {
[uuidArray addObject:p.identifier.UUIDString];
}
if (![uuidArray containsObject:peripheral.identifier.UUIDString]) {
[self.peripherals addObject:peripheral];
[self.tableView reloadData];
}
}
4、连接外设;
4.1、这个时候我们可以选择一个外设,进行连接,需要执行connectPeripheral:options:这个方法;
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
self.peripheral = self.peripherals[indexPath.row];
self.peripheral.delegate = self;
NSDictionary *options = [NSDictionary dictionaryWithObject:[NSNumber numberWithBool:YES] forKey:CBConnectPeripheralOptionNotifyOnDisconnectionKey];
[self.manager connectPeripheral:self.peripheral options:options];
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
4.2、连接外设会执行CBCentralManagerDelegate这两个方法;
#pragma mark 连接外设成功调用
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral
{
NSLog(@"连接成功");
//扫描外设中的服务,nil表示查找全部
[peripheral discoverServices:nil];
}
#pragma mark 连接外设失败调用
- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error
{
NSLog(@"连接失败");
}
5、连接上外设后,获取指定外设的服务(Service);
#pragma mark 只要扫描到就会调用
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error
{
NSLog(@"扫描服务");
//获取外设中所有扫描到的服务
if (!error) {
NSArray *services = peripheral.services;
for (CBService *service in services) {
NSLog(@"service.UUID is %@",service.UUID.UUIDString);
//判断service.UUID是否是我们需要的
if ([service.UUID.UUIDString isEqualToString:KServiceUUID]) {
//nil表示查找所有
[peripheral discoverCharacteristics:nil forService:service];
}
}
}else {
NSLog(@"Discovered services for %@ with error: %@", peripheral.name, [error localizedDescription]);
}
}6、获取服务后,遍历服务的特征,得到可读、可写等特征;
#pragma mark 只要扫描到特征就会调用
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error
{
if (!error) {
NSArray *characteristics = service.characteristics;
for (CBCharacteristic *characteristic in characteristics) {
NSLog(@"characteristic.UUID is %@",characteristic.UUID.UUIDString);
if ([characteristic.UUID.UUIDString isEqualToString:KCharacteristicUUID]) {
NSString *valueStr = [[NSString alloc] initWithData:characteristic.value encoding:NSUTF8StringEncoding];
NSLog(@"valueStr is %@",valueStr);
//保存特征
self.characteristic = characteristic;
//开启监听,为了保持连接
[self.peripheral setNotifyValue:YES forCharacteristic:characteristic];
}
}
}else {
NSLog(@"Discovered read characteristics:%@ for service: %@", service.UUID, service.UUID);
}
}7、与中心管理者进行数据交互;
7.1、写入数据
#pragma mark 写入数据
- (void)writeString:(NSString *)string
{
NSData *data = [NSData dataWithBytes:string.UTF8String length:string.length];
self.peripheral.delegate = self;
[self.peripheral writeValue:data forCharacteristic:self.characteristic type:CBCharacteristicWriteWithoutResponse];
}7.2、回调方法
#pragma mark 发送消息触发的方法
- (void)peripheral:(CBPeripheral *)peripheral didWriteValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
{
NSLog(@"发送消息回调 is %@",error);
}
#pragma mark 写描述信息时触发的方法
- (void)peripheral:(CBPeripheral *)peripheral didWriteValueForDescriptor:(CBDescriptor *)descriptor error:(NSError *)error
{
NSLog(@"描述信息回调 peripheral:%@,descriptor:%@,error:%@",peripheral,descriptor,error);
}
#pragma mark 有更新资料就会触发
- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
{
NSLog(@"更新资料 peripheral:%@,characteristic:%@,error:%@",peripheral,characteristic,error);
NSMutableData *recvData;
[recvData appendData:characteristic.value];
if (recvData.length >= 5) {
unsigned char *buffer = (unsigned char *)[recvData bytes];
int nLen = buffer[3]*256 + buffer[4];
if (recvData.length == nLen + 3 + 2 + 2) {
NSLog(@"recvData.length");
}
}
}8、停止连接
- (void)stopScanForPeripheral
{
//1.取消扫描
[self.manager stopScan];
//2.取消外设设备
if (self.peripheral != nil) {
[self.manager cancelPeripheralConnection:self.peripheral];
}
self.peripheral = nil;
//3.刷新表格
[self.tableView reloadData];
//4.设置标题
self.navigationItem.rightBarButtonItem.title = @"扫描";
}
demo详细代码如下:
#import <UIKit/UIKit.h>
@interface ViewController : UITableViewController
@end
大致步骤如下:
1、首先需要导入<CoreBluetooth/CoreBluetooth.h>这个框架,并在info配置Privacy - Bluetooth Peripheral Usage Description权限;
2、其次需要遵循CBCentralManagerDelegate,CBPeripheralDelegate这两个代理;
3、扫描外设;
3.1、懒加载创建中央设备;
- (CBCentralManager *)manager
{
if (!_manager) {
//1.创建中央设备
_manager = [[CBCentralManager alloc] initWithDelegate:self queue:nil];
}
return _manager;
}
3.2、利用中央设备扫描外设
#pragma mark 利用中央设备扫描外设设备
- (void)scanForPeripheral
{
NSDictionary *options = [NSDictionary dictionaryWithObject:[NSNumber numberWithBool:NO] forKey:CBCentralManagerScanOptionAllowDuplicatesKey];
//当没有指定对应的Services的时候,nil为全部
[self.manager scanForPeripheralsWithServices:nil options:options];
}
3.3、如果发现外设会执行centralManager:didDiscoverPeripheral:advertisementData:RSSI:这个方法;
#pragma mark 发现外设
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary<NSString *,id> *)advertisementData RSSI:(NSNumber *)RSSI
{
NSLog(@"查找设备peripheral is %@ name is %@",peripheral,peripheral.name);
//1.保存扫描得到设备,判断如果数组中不包含当前扫描到得外部设置才保存
NSMutableArray *uuidArray = [NSMutableArray array];
for (CBPeripheral *p in self.peripherals) {
[uuidArray addObject:p.identifier.UUIDString];
}
if (![uuidArray containsObject:peripheral.identifier.UUIDString]) {
[self.peripherals addObject:peripheral];
[self.tableView reloadData];
}
}
4、连接外设;
4.1、这个时候我们可以选择一个外设,进行连接,需要执行connectPeripheral:options:这个方法;
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
self.peripheral = self.peripherals[indexPath.row];
self.peripheral.delegate = self;
NSDictionary *options = [NSDictionary dictionaryWithObject:[NSNumber numberWithBool:YES] forKey:CBConnectPeripheralOptionNotifyOnDisconnectionKey];
[self.manager connectPeripheral:self.peripheral options:options];
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
4.2、连接外设会执行CBCentralManagerDelegate这两个方法;
#pragma mark 连接外设成功调用
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral
{
NSLog(@"连接成功");
//扫描外设中的服务,nil表示查找全部
[peripheral discoverServices:nil];
}
#pragma mark 连接外设失败调用
- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error
{
NSLog(@"连接失败");
}
5、连接上外设后,获取指定外设的服务(Service);
#pragma mark 只要扫描到就会调用
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error
{
NSLog(@"扫描服务");
//获取外设中所有扫描到的服务
if (!error) {
NSArray *services = peripheral.services;
for (CBService *service in services) {
NSLog(@"service.UUID is %@",service.UUID.UUIDString);
//判断service.UUID是否是我们需要的
if ([service.UUID.UUIDString isEqualToString:KServiceUUID]) {
//nil表示查找所有
[peripheral discoverCharacteristics:nil forService:service];
}
}
}else {
NSLog(@"Discovered services for %@ with error: %@", peripheral.name, [error localizedDescription]);
}
}6、获取服务后,遍历服务的特征,得到可读、可写等特征;
#pragma mark 只要扫描到特征就会调用
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error
{
if (!error) {
NSArray *characteristics = service.characteristics;
for (CBCharacteristic *characteristic in characteristics) {
NSLog(@"characteristic.UUID is %@",characteristic.UUID.UUIDString);
if ([characteristic.UUID.UUIDString isEqualToString:KCharacteristicUUID]) {
NSString *valueStr = [[NSString alloc] initWithData:characteristic.value encoding:NSUTF8StringEncoding];
NSLog(@"valueStr is %@",valueStr);
//保存特征
self.characteristic = characteristic;
//开启监听,为了保持连接
[self.peripheral setNotifyValue:YES forCharacteristic:characteristic];
}
}
}else {
NSLog(@"Discovered read characteristics:%@ for service: %@", service.UUID, service.UUID);
}
}7、与中心管理者进行数据交互;
7.1、写入数据
#pragma mark 写入数据
- (void)writeString:(NSString *)string
{
NSData *data = [NSData dataWithBytes:string.UTF8String length:string.length];
self.peripheral.delegate = self;
[self.peripheral writeValue:data forCharacteristic:self.characteristic type:CBCharacteristicWriteWithoutResponse];
}7.2、回调方法
#pragma mark 发送消息触发的方法
- (void)peripheral:(CBPeripheral *)peripheral didWriteValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
{
NSLog(@"发送消息回调 is %@",error);
}
#pragma mark 写描述信息时触发的方法
- (void)peripheral:(CBPeripheral *)peripheral didWriteValueForDescriptor:(CBDescriptor *)descriptor error:(NSError *)error
{
NSLog(@"描述信息回调 peripheral:%@,descriptor:%@,error:%@",peripheral,descriptor,error);
}
#pragma mark 有更新资料就会触发
- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
{
NSLog(@"更新资料 peripheral:%@,characteristic:%@,error:%@",peripheral,characteristic,error);
NSMutableData *recvData;
[recvData appendData:characteristic.value];
if (recvData.length >= 5) {
unsigned char *buffer = (unsigned char *)[recvData bytes];
int nLen = buffer[3]*256 + buffer[4];
if (recvData.length == nLen + 3 + 2 + 2) {
NSLog(@"recvData.length");
}
}
}8、停止连接
- (void)stopScanForPeripheral
{
//1.取消扫描
[self.manager stopScan];
//2.取消外设设备
if (self.peripheral != nil) {
[self.manager cancelPeripheralConnection:self.peripheral];
}
self.peripheral = nil;
//3.刷新表格
[self.tableView reloadData];
//4.设置标题
self.navigationItem.rightBarButtonItem.title = @"扫描";
}
demo详细代码如下:
#import <UIKit/UIKit.h>
@interface ViewController : UITableViewController
@end
#import "ViewController.h" #import <CoreBluetooth/CoreBluetooth.h> static NSString *const KServiceUUID = @"9830BC16-5CE7-43CD-996F-74E9110C4CEA"; static NSString *const KCharacteristicUUID = @"F6F6B7E0-897D-4F51-959F-387A94BF440E"; @interface ViewController ()<UITableViewDelegate,UITableViewDataSource,CBCentralManagerDelegate,CBPeripheralDelegate> //外设数组 @property (nonatomic,strong) NSMutableArray *peripherals; //中心管理者 @property (nonatomic,strong) CBCentralManager *manager; //外设 @property (nonatomic,strong) CBPeripheral *peripheral; //特征 @property (nonatomic,strong) CBCharacteristic *characteristic; @end @implementation ViewController //懒加载重写getter方法 - (NSMutableArray *)peripherals { if (!_peripherals) { _peripherals = [NSMutableArray array]; } return _peripherals; } - (CBCentralManager *)manager { if (!_manager) { //1.创建中央设备 _manager = [[CBCentralManager alloc] initWithDelegate:self queue:nil options:nil]; } return _manager; } - (void)viewDidLoad { [super viewDidLoad]; //1.设置导航Item self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"扫描" style:UIBarButtonItemStylePlain target:self action:@selector(openOrClosed)]; self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"open" style:UIBarButtonItemStylePlain target:self action:@selector(openTheDoor)]; } #pragma mark 扫描外设 - (void)openOrClosed { if ([self.navigationItem.rightBarButtonItem.title isEqualToString:@"扫描"]) { self.navigationItem.rightBarButtonItem.title = @"断开"; //开始扫描 [self scanForPeripheral]; } else { //停止扫描 [self stopScanForPeripheral]; } } #pragma mark 利用中央设备扫描外设设备 - (void)scanForPeripheral { //当没有指定对应的Services的时候,nil为全部 [self.manager scanForPeripheralsWithServices:nil options:nil]; } #pragma mark 停止扫描 - (void)stopScanForPeripheral { //1.取消扫描 [self.manager stopScan]; //2.取消外设设备 if (self.peripheral != nil) { [self.manager cancelPeripheralConnection:self.peripheral]; } self.peripheral = nil; //3.刷新表格 [self.tableView reloadData]; //4.设置标题 self.navigationItem.rightBarButtonItem.title = @"扫描"; } - (void)openTheDoor { //拿到可读可写的特征 [self writeString:@"OLWANDA_IL12345678"]; } #pragma mark 写入数据 - (void)writeString:(NSString *)string { NSData *data = [NSData dataWithBytes:string.UTF8String length:string.length]; self.peripheral.delegate = self; [self.peripheral writeValue:data forCharacteristic:self.characteristic type:CBCharacteristicWriteWithoutResponse]; } #pragma mark - CBCentralManagerDelegate代理 #pragma mark 更新状态 - (void)centralManagerDidUpdateState:(CBCentralManager *)central { NSLog(@"更新状态 is %ld",(long)central.state); switch (central.state) { case CBCentralManagerStatePoweredOn:{ [self scanForPeripheral]; } break; default: NSLog(@"Central Manager did change state"); break; } } #pragma mark 发现外设 - (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary<NSString *,id> *)advertisementData RSSI:(NSNumber *)RSSI { NSLog(@"查找设备peripheral is %@ name is %@",peripheral,peripheral.name); //1.保存扫描得到设备,判断如果数组中不包含当前扫描到得外部设置才保存 NSMutableArray *uuidArray = [NSMutableArray array]; for (CBPeripheral *p in self.peripherals) { [uuidArray addObject:p.identifier.UUIDString]; } if (![uuidArray containsObject:peripheral.identifier.UUIDString]) { [self.peripherals addObject:peripheral]; [self.tableView reloadData]; } } #pragma mark 连接外设成功调用 - (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral { NSLog(@"连接成功"); [self showTheAlertViewWithMessage:@"连接成功"]; //扫描外设中的服务 [peripheral discoverServices:nil]; } #pragma mark 连接外设失败调用 - (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error { NSLog(@"连接失败"); } - (void)centralManager:(CBCentralManager *)central willRestoreState:(NSDictionary *)dict { NSLog(@"dict is %@",dict); } - (void)centralManager:(CBCentralManager *)central didRetrieveConnectedPeripherals:(NSArray *)peripherals { NSLog(@"peripherals is %@",peripherals); } #pragma mark - CBPeripheralDelegate代理 #pragma mark 只要扫描到就会调用 - (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error { NSLog(@"扫描服务"); //获取外设中所有扫描到的服务 if (!error) { NSArray *services = peripheral.services; for (CBService *service in services) { NSLog(@"service.UUID is %@",service.UUID.UUIDString); //判断service.UUID是否是我们需要的 if ([service.UUID.UUIDString isEqualToString:KServiceUUID]) { //nil表示查找所有 [peripheral discoverCharacteristics:nil forService:service]; } } }else { NSLog(@"Discovered services for %@ with error: %@", peripheral.name, [error localizedDescription]); } } #pragma mark 只要扫描到特征就会调用 - (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error { if (!error) { NSArray *characteristics = service.characteristics; for (CBCharacteristic *characteristic in characteristics) { NSLog(@"characteristic.UUID is %@",characteristic.UUID.UUIDString); if ([characteristic.UUID.UUIDString isEqualToString:KCharacteristicUUID]) { NSString *valueStr = [[NSString alloc] initWithData:characteristic.value encoding:NSUTF8StringEncoding]; NSLog(@"valueStr is %@",valueStr); //保存特征 self.characteristic = characteristic; //开启监听,为了保持连接 [self.peripheral setNotifyValue:YES forCharacteristic:characteristic]; } } }else { NSLog(@"Discovered read characteristics:%@ for service: %@", service.UUID, service.UUID); } } #pragma mark 发送消息触发的方法 - (void)peripheral:(CBPeripheral *)peripheral didWriteValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error { NSLog(@"发送消息回调 is %@",error); } #pragma mark 写描述信息时触发的方法 - (void)peripheral:(CBPeripheral *)peripheral didWriteValueForDescriptor:(CBDescriptor *)descriptor error:(NSError *)error { NSLog(@"描述信息回调 peripheral:%@,descriptor:%@,error:%@",peripheral,descriptor,error); } #pragma mark 有更新资料就会触发 - (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error { NSLog(@"更新资料 peripheral:%@,characteristic:%@,error:%@",peripheral,characteristic,error); NSMutableData *recvData; [recvData appendData:characteristic.value]; if (recvData.length >= 5) { unsigned char *buffer = (unsigned char *)[recvData bytes]; int nLen = buffer[3]*256 + buffer[4]; if (recvData.length == nLen + 3 + 2 + 2) { NSLog(@"recvData.length"); } } } #pragma mark - TableView的代理和数据源 - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { return 1; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return _peripherals.count; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *cell_id = @"cell_id"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cell_id]; if (cell == nil) { cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:cell_id]; } CBPeripheral *peripheral = self.peripherals[indexPath.row]; cell.textLabel.text = peripheral.name; cell.detailTextLabel.text = peripheral.identifier.UUIDString; return cell; } - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { self.peripheral = self.peripherals[indexPath.row]; self.peripheral.delegate = self; NSDictionary *options = [NSDictionary dictionaryWithObject:[NSNumber numberWithBool:YES] forKey:CBConnectPeripheralOptionNotifyOnDisconnectionKey]; [self.manager connectPeripheral:self.peripheral options:options]; [tableView deselectRowAtIndexPath:indexPath animated:YES]; } #pragma mark 弹窗 - (void)showTheAlertViewWithMessage:(NSString *)message { UIAlertController *alertC = [UIAlertController alertControllerWithTitle:@"温馨提示" message:message preferredStyle:UIAlertControllerStyleAlert]; UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:nil]; [alertC addAction:okAction]; [self presentViewController:alertC animated:YES completion:nil]; } @end
相关文章推荐
- IOS CoreBluetooth系列三:实战之远程 Central 和本地 Peripheral
- IOS CoreBluetooth系列四:一个简单的BlueTooth管理类
- 小米手环iOS开发实战(一):iOS蓝牙框架CoreBluetooth
- IOS CoreBluetooth系列一:理论
- 【转】Core Bluetooth框架之一:Central与Peripheral
- Core Bluetooth框架之一:Central与Peripheral
- Core Bluetooth框架之一:Central与Peripheral
- Core Bluetooth框架之一:Central与Peripheral
- Git学习系列(四)远程仓库及其与本地仓库交互
- IOS CoreText系列四:图文混排之点击事件
- iOSCoreAnimation动画系列教程(一):CABasicAnimation
- iOS 开发系列:CoreData Object 变成 Fault 的一种方式
- iOS 上的蓝牙框架 - Core Bluetooth for iOS [译]
- iOS CoreBluetooth 教程 蓝牙
- GitHub实战系列~2.把本地项目提交到github中 2015-12-10
- 实战2 Cacti监控本地主机和远程主机
- CoreBluetooth第一节:Performing Common Central Role Tasks(执行常见的核心端任务)
- ios远程推送与本地推送
- ios 蓝牙4.0开发(CoreBlueTooth)
- iOS开发系列之远程控制事件