iOS

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: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蓝牙实现汇总

上一篇下一篇

猜你喜欢

热点阅读