您的位置:首页 > 产品设计 > UI/UE

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
#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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: