iOS学习-蓝牙
2021-08-28 本文已影响0人
快乐的tomato
一、Core Bluetooth
iOS中使用Core Bluetooth这个框架来进行蓝牙的开发
支持蓝牙4.0,蓝牙4.0以低功耗著称,一般也叫BLE。也是目前iOS开发最流行的。
最近在做使用APP连接电子秤的项目。
二、开发步骤
1、建立中心设备
CBCentralManager 是中心设备管理者
#import <CoreBluetooth/CoreBluetooth.h> // 添加蓝牙库文件
@interface BluetoothManager () <CBCentralManagerDelegate,CBPeripheralDelegate>//添加代理
- (CBCentralManager *)centralManager
{
if (!_pwCentralManager ) {
queue可以设置蓝牙扫描的线程 传入nil则为在主线程中进行
_pwCentralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil];
}
return _pwCentralManager;
}
判断蓝牙状况,能获得当前设备是否能作为 central
#pragma mark - CBCentralManagerDelegate
// 判断蓝牙状况
- (void)centralManagerDidUpdateState:(CBCentralManager *)central
{
switch (central.state) {
case CBCentralManagerStatePoweredOn:
NSLog(@"CBCentralManagerStatePoweredOn==>蓝牙已打开");
break;
case CBCentralManagerStatePoweredOff:
NSLog(@"CBCentralManagerStatePoweredOff==>蓝牙关闭状态");
// 代理监控蓝牙未开启,去开启本机蓝牙
[self bluetoothAlert];
break;
default:
break;
}
}
//状态未知
CBCentralManagerStateUnknown = 0,
//连接断开 即将重置
CBCentralManagerStateResetting,
//该平台不支持蓝牙
CBCentralManagerStateUnsupported,
//未授权蓝牙使用 hovertree.com
CBCentralManagerStateUnauthorized,
//蓝牙关闭
CBCentralManagerStatePoweredOff,
//蓝牙正常开启
CBCentralManagerStatePoweredOn,
};
去开启本机蓝牙
-(void)bluetoothAlert{
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"前往设置界面开启蓝牙功能" message:@"" preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *setBtn = [UIAlertAction actionWithTitle:@"开启蓝牙" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
[self ibeaconState];
}];
UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:nil];
[alertController addAction:setBtn];
[alertController addAction:cancelAction];
[self presentViewController:alertController animated:YES completion:nil];
}
-(void)ibeaconState{
NSURL *url = [NSURL URLWithString:UIApplicationOpenSettingsURLString];
[[UIApplication sharedApplication]openURL:url];
}
2、 扫描外部设备
如果中心设备的蓝牙正常,就可以进行外部设备的扫描
使用CBCentralManager的scanForPeripheralsWithServices:options:方法来扫描周围正在发出广播的 Peripheral 设备
- services: 中心要扫描的蓝牙设备类型,表示只搜索当前数组包含的设备(每个 peripheral 的 service 都有唯一标识——UUID)
- options:是否允许重复扫描 对应NSNumber的bool值,默认为NO,会自动去重复扫描,设置这个 option 会对电池寿命和 app 的性能产生不利影响,所以一定要在必要的时候,再对其进行设置
//如果Services:nil ,默认为扫描全部
[self.centralManager scanForPeripheralsWithServices:@[[CBUUID UUIDWithString:AICARE_SERVICE_UUID]] options:@{CBCentralManagerScanOptionAllowDuplicatesKey : @ YES}];
找到可用设备,系统会调用下面的方法(每找到一个都会回调)
// 扫描到设备会进入方法
- (void)centralManager:(CBCentralManager *)central//中心设备
didDiscoverPeripheral:(CBPeripheral *)peripheral//外围设备
advertisementData:(NSDictionary<NSString *,id> *)advertisementData//相关数据
RSSI:(NSNumber *)RSSI//信号强度
{
NSData *manufacturerData = [advertisementData valueForKeyPath:CBAdvertisementDataManufacturerDataKey];
// 打印出扫描的信息;
if (advertisementData.description.length > 0) {
DLog(@"/-------advertisementData:%@--------",advertisementData.description);
DLog(@"-------peripheral:%@--------/",peripheral.description);
}
// 标准是会收到: <ac02e215 afecb3a1> 是按照Byte值来数,是8位;
if (manufacturerData.length < 8) {
return;
}
// 抽取地址处理 <ac02e215 afecb3a1> 变成: A1:B3:EC:AF:15:E2
NSString *bindString = @"";
NSData *subData = [manufacturerData subdataWithRange:NSMakeRange(manufacturerData.length-8, 8)];
bindString = subData.description;
NSString *addressString = [self getVisiableIDUUID:bindString];//
NSLog(@" GG == %@ == GG",addressString);
[self.peripheralArray addObject:peripheralModel];
将外部设备信息进行列表进行展示,供用户选择
}
3、连接外部设备
自己写的方法
- (void)connectPeripheral:(CBPeripheral *)peripheral
{
// 名字按照自家的称做修改
if ([peripheral.name isEqualToString:@"SWAN"] || [peripheral.name isEqualToString:@"icomon"] || [peripheral.name isEqualToString:@"eufy T9140"] || [peripheral.name isEqualToString:@"himama"]) {
self.connectPeripheralUUID = AICARE_SERVICE_UUID;
self.connectPeripheralCharUUID = AICARE_NOTIFY_CHARACTERISTIC_UUID;
}else{
return;
}
// NSLog(@"111 %@, 22222 ",peripheral.identifier.UUIDString);
self.peripheral = peripheral;
[self.centralManager connectPeripheral:peripheral options:nil];
}
连接成功之后,接下来都是外围设备来做事情,设置外围设备的代理,调用代理方法
// 连接到Peripherals-成功
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral
{
// NSLog(@"-- 成功连接外设 --:%@",peripheral.name);
[self.centralManager stopScan];
[self.peripheral setDelegate:self];
[self.peripheral discoverServices:@[[CBUUID UUIDWithString:self.connectPeripheralUUID]]];
}
连接到Peripherals-失败
- (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error
{
NSLog(@">>>连接到名称为(%@)的设备-失败,原因:%@",[peripheral name],[error localizedDescription]);
}
Peripherals断开连接
- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error
{
NSLog(@">>>外设连接断开连接 %@: %@\n", [peripheral name], [error localizedDescription]);
}
4、扫描外部设备的服务和特征
扫描到服务的时候会调用
#pragma mark - CBPeripheralDelegate
// 扫描到Services
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error
{
if (error) {
NSLog(@">>>Discovered services for %@ with error: %@", peripheral.name, [error localizedDescription]);
return;
}
//去获取指定的服务,然后根据服务去查找特征
for (CBService *server in peripheral.services) {
//开始扫描特征
[self.peripheral discoverCharacteristics:nil forService:server];
}
}
扫描到特征时调用
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error
{
//在这里进行特征值的匹对,拿到特征值进行读写
if ([service.UUID isEqual:[CBUUID UUIDWithString:self.connectPeripheralUUID]]) {
for (CBCharacteristic *characteristic in service.characteristics) {
if (characteristic.properties & CBCharacteristicPropertyNotify) {
[peripheral readValueForCharacteristic:characteristic];
[peripheral setNotifyValue:YES forCharacteristic:characteristic];
NSLog(@"=---- %@ ----",characteristic);
}
if([characteristic.UUID isEqual:[CBUUID UUIDWithString:AICARE_WRITE_CHARACTERISTIC_UUID]]){
self.myCharacteristic = characteristic;
}
}
}
}
5、中心设备利用特征与外部设备进行数据交互
获取的charateristic的值,数据解析
// 获取的charateristic的值,数据解析
- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
{
NSLog(@"characteristic特征的值 %@",characteristic);
if (characteristic.value.length == 0){
return;
}
// 回来的数据都丢去分析类里面进行处理
[[AnalysisBLEDataManager shareManager] readBleComebackData:characteristic.value];
}
你和硬件设定的蓝牙传输格式类似于json,双方可识别的数据,因为蓝牙只能支持16进制,而且每次传输只能20个字节,所以要把信息流转成双方可识别的16进制。
- (void)readBleComebackData:(NSData *)characteristicValue {
//和硬件开发人员进行沟通,按照一定的规则获取数据
Byte *testByte = (Byte *)[characteristicValue bytes];
if (testByte[6] == 0XCA) { // 0xCA时是 稳定 体重(温度)数据
_weightsum = testByte[2]*256 + testByte[3];
//NSLog(@"体重数据=== %f ===",_weightsum);
}
}
6、断开连接
关闭蓝牙扫描
- (void)closeBleAndDisconnect
{
if (self.peripheral == nil) {
return;
}
[self.centralManager stopScan];
[self.centralManager cancelPeripheralConnection:self.peripheral];
}
- (void)stopScan_BLE{
[self.centralManager stopScan];
}
参考:
iOS蓝牙实现汇总