iOS蓝牙开发流程
2019-06-04 本文已影响0人
夕儿77
配置
- 引入头文件 #import <CoreBluetooth/CoreBluetooth.h>
- 协议 <CBCentralManagerDelegate,CBPeripheralDelegate>
创建一个CBCentralManager实例来进行蓝牙管理
/*
* 初始化 将self设置为代理 用于接收各种 central 事件
* 将queue设置为nil,则表示直接在主线程中运行
* 可以自己设置线程
*/
CBCentralManager *centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil];
获取蓝牙状态 可用状态下搜索扫描外围设备
/*
* 创建Central管理器时,管理器对象会调用代理对象的centralManagerDidUpdateState:方法。
* 我们需要实现这个方法来确保本地设备支持BLE
*/
- (void)centralManagerDidUpdateState:(CBCentralManager *)central{
switch (central.state) {
case CBManagerStateUnknown:
NSLog(@">>>初始的时候是未知的(刚刚创建的时候)");
break;
case CBManagerStateResetting:
NSLog(@">>>正在重置状态");
break;
case CBManagerStateUnsupported:
NSLog(@">>>设备不支持的状态");
break;
case CBManagerStateUnauthorized:
NSLog(@">>>设备未授权状态");
break;
case CBManagerStatePoweredOff:
NSLog(@">>>设备关闭状态");
break;
case CBManagerStatePoweredOn:
{
NSLog(@">>>设备开启状态 -- 可用状态");
[self.centralManager scanForPeripheralsWithServices:nil options:nil];
}
break;
default:
break;
}
}
查找外设
/*
* @param services 中心要扫描的蓝牙设备类型 每个peripheral的 service 都有唯一标识——UUID
* @param options 可选 设置这个 option 会对电池寿命和 app 的性能产生不利影响,所以一定要在必要的时候
* @{CBCentralManagerScanOptionAllowDuplicatesKey : @NO } key值是NSNumber,默认值为NO表示不会重复扫描已经发现的设备,如需要不断获取最新的信号强度RSSI所以一般设为YES
* options:@{CBCentralManagerScanOptionSolicitedServiceUUIDsKey:@[[CBUUID UUIDWithString:[USER_DEFAULT objectForKey:KEY_SELECED_FOB]]]} 想要扫描的服务的UUID,以一个数组的形式存在。也就是说指定这个选项后central便会找指定的服务的UUID。
*/
[self.centralManager scanForPeripheralsWithServices:nil options:nil];
停止扫描外围设备。
[self.centralManager stopScan]
发现外设
/*
* 找到可用设备,系统会回调(每找到一个都会回调)
* @param peripheral 找到的外设可以是多个
* @param advertisementData 外设携带的数据
* @param RSSI 外设发出的蓝牙信号强度
*/
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary*)advertisementData RSSI:(NSNumber *)RSSI
{
//显示外设
}
连接外设
/*
* @param peripheral 连接的外设
* @param options 可选
* @{CBConnectPeripheralOptionNotifyOnConnectionKey: @YES} 在程序被挂起时,连接成功显示Alert提醒框
* @{CBConnectPeripheralOptionNotifyOnDisconnectionKey: @YES} 在程序被挂起时,断开连接显示Alert提醒框
* @{CBConnectPeripheralOptionNotifyOnNotificationKey: @YES} 在程序被挂起时,显示所有的提醒消息
*/
[self.centralManager connectPeripheral:peripheral options:nil];
连接外设--失败
- (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error{
}
连接外设--断开
- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error{
}
连接外设--成功
/*
* 外设的服务、特征、描述等方法是CBPeripheralDelegate的内容,所以要先设置代理 设置外设的代理
* 查找外设的服务
*/
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral{
peripheral.delegate = self;
/*
* @param discoverServices 的值是空的时候是不过滤 查找所有的外设服务
* 可以自定义 [CBUUID UUIDWithString:@"你要用的服务UUID"]
*/
[self.peripheral discoverServices:nil];
}
发现服务回调 查找对应的特征
/*
*Core Bluetooth 提供了CBService类来表示 service,
*找到以后,它们以数组的形式存入了当前 peripheral 的services属性中,
*你可以在当前回调中遍历这个属性
*/
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error{
CBService * __nullable findService = nil;
// 遍历服务
for (CBService *service in peripheral.services)
{
if ([[service UUID] isEqual:[CBUUID UUIDWithString:@"你要用的服务UUID"]])
{
findService = service;
}
}
if (findService)
/*
*@param discoverServices 空的时候是搜索全部的特征 或者写入你要用的特征UUID
*@param forService 你需要的查服务
*/
[peripheral discoverCharacteristics:NULL forService:findService];
}
发现特征回调
/*
*Core Bluetooth 提供了CBCharacteristic类来表示characteristic。可以通过以下代码来遍历找到的 characteristic
*
*/
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error{
for (CBCharacteristic *characteristic in service.characteristics) {
if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:@"你要用的特征UUID"]]) {
self.characteristic = characteristic;
/*
* 接收特征的两个方法
* [peripheral readValueForCharacteristic:characteristic]; read这种方法是需要主动去接收的
* notify方法订阅,当有数据发送时,可以直接在回调中接收,如果 characteristic 的数据经常变化,那么采用订阅的方式更好
* setNotifyValue YES 为订阅 为NO来取消订阅
*/
[peripheral setNotifyValue:YES forCharacteristic:characteristic];
}
/*
* 当发现characteristic有descriptor,回调didDiscoverDescriptorsForCharacteristic
*/
[peripheral discoverDescriptorsForCharacteristic:characteristic];
}
}
获取外设发来的数据
/*
* 不论是read和notify,获取数据都是从这个方法中读取。
*/
- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{
// characteristic.value就是蓝牙给我们的值(我这里是json格式字符串)
// NSData *jsonData = [characteristic.value dataUsingEncoding:NSUTF8StringEncoding];
// NSDictionary *dataDic = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableContainers error:nil];
// 将字典传出去就可以使用了
}
中心读取外设实时数据
/*
*标识订阅成功吧,获取蓝牙返回数据还是上边的那个方法
*/
- (void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{
if (characteristic.isNotifying) {
[peripheral readValueForCharacteristic:characteristic];
} else {
NSLog(@"Notification stopped on %@. Disconnecting", characteristic);
NSLog(@"%@", characteristic);
[self.centralManager cancelPeripheralConnection:peripheral];
}
}
写入数据
/*
* @param data 你想要写入的数据
* @param Characteristic 你想要写入的数据
* @param type
*CBCharacteristicWriteWithResponse 外围设备的响应来指示写入是否成功
*CBCharacteristicWriteWithoutResponse 不需要来自外围设备的任何响应来指示写入是否成功
*/
[self.peripheral writeValue:data forCharacteristic:self.characteristic type:CBCharacteristicWriteWithResponse];
数据写入成功回调
- (void)peripheral:(CBPeripheral *)peripheral didWriteValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{
NSLog(@"写入成功");
}
断开连接
/*
* 断开连接后回调didDisconnectPeripheral
* 这个方法是非阻塞的,所以其他正在进行的通讯可能完成也可能因此没完成
* 因为其他应用可能仍保持跟这个设备的连接,
* 所以当前的取消连接并不能保证底层就立即断开物理上的连接
*/
[self.centralManager cancelPeripheralConnection:peripheral];