iOS蓝牙技术

本文介绍了iOS蓝牙开发的中心者模式和管理者模式,重点讲解了蓝牙开发中的服务、特征和UUID等核心概念,以及蓝牙连接的七个步骤,包括设备搜索、连接、服务和特征发现以及数据读写。提供了一个基本的蓝牙通信传输过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

蓝牙开发分为中心者和管理者模式:
1.中心者模式是常用模式(99.99%),即我们的手机作为主机,连接蓝牙外部设备;
2.管理者模式用得比较少,这种模式是手机作为外设,自己创建服务和特征,由其他设备连接手机。

蓝牙开发需要先了解几个概念:
服务 (services) :蓝牙外设对外广播必定会有一个服务,可能有多个,服务下面包含一些特征,服务可以理解成一个模块的窗口;
特征 (characteristic) :存在于服务下面的,一个服务下面可以存在多个特征,特征可以理解成具体实现功能的窗口,一般特征都会有value,也就是特征值,特征是与外界交互的最小单位;
UUID:可以理解成蓝牙上的唯一标识符 (硬件上肯定不是这个意思,但是这样理解便于我们开发) ,为了区别不同的服务和特征,或者给服务和特征取名字,我们就用UUID来代表服务和特征。

蓝牙连接大致分为以下几个步骤:
1.建立一个central Manager实例进行蓝牙管理
2.搜索外围设备
3.连接外围设备
4.获取外围设备的服务
5.获取服务的特征
6.从外围设备读取数据
7.给外围设备发送数据

//导入系统的BLE框架
#import <CoreBluetooth/CoreBluetooth.h>

//遵守2个协议
@interface ViewController ()<CBCentralManagerDelegate,CBPeripheralDelegate>

@property (nonatomic, strong) CBCentralManager *cbManager;  //中心管理者
@property (nonatomic, strong) CBPeripheral *peripheral;     //连接到的外围设备

@end

初始化中心管理者,并设置代理

_cbManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil];
#pragma mark - delegate
//只有中心管理者初始化,就会触发此代理方法,判断手机蓝牙状态
- (void)centralManagerDidUpdateState:(CBCentralManager *)central {
    /*
     {
     CBManagerStateUnknown = 0,
     CBManagerStateResetting,
     CBManagerStateUnsupported,
     CBManagerStateUnauthorized,
     CBManagerStatePoweredOff,
     CBManagerStatePoweredOn,
     }
     */
    switch (central.state) {
        case 0:
            NSLog(@"CBManagerStateUnknown");
            break;
        case 1:
            NSLog(@"CBManagerStateResetting");
            break;
        case 2:
            NSLog(@"CBManagerStateUnsupported");
            break;
        case 3:
            NSLog(@"CBManagerStateUnauthorized");
            break;
        case 4:
            NSLog(@"CBManagerStatePoweredOff");
            break;
        case 5:
        {
            NSLog(@"CBManagerStatePoweredOn");//蓝牙已开启
            //搜索外设
            //services 通过某些服务筛选外设   option 条件
            [self.cbManager scanForPeripheralsWithServices:nil options:nil];

            //搜索成功之后,会调用找到外设的代理方法
        }

            break;
        default:
            break;
    }

}

如果手机的蓝牙已经开启,就可以开始搜索外围设备。发现了外围设备,就会调用下面的代理方法

//发现外设
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary<NSString *,id> *)advertisementData RSSI:(NSNumber *)RSSI {

    //中心管理者             central
    //外设                  peripheral
    //外设携带的数据          advertisementData
    //外设发出的蓝牙信号强度    RSSI
    NSLog(@"peripheral = %@\n data = %@\n rssi = %@", peripheral, advertisementData, RSSI);

    /*小米手环获得的数据
     peripheral = <CBPeripheral: 0x1702e1800, identifier = EC3BFC7E-0BAF-41B5-B043-3BA19C2F34D7, name = MI_SCALE, state = disconnected>
     data = {
     kCBAdvDataIsConnectable = 1;
     kCBAdvDataManufacturerData = <5701880f 10ad8a4c>;
     kCBAdvDataServiceData =     {
     181D = <820000e1 07031116 0719>;
     };
     kCBAdvDataServiceUUIDs =     (
     181D
     );
     }
     rssi = -62
     */

    //加过滤条件
    if ([peripheral.name hasPrefix:@"MI"]) {

        //此处可以对advertisementData(外设携带的广播数据)进行一些处理
        //通过过滤,通常会有一些外设,然后把这些外设存储到一个可变数组中,此处只有一个手环,先按照一个外设进行处理

        self.peripheral = peripheral;

        //连接外设
        [self.cbManager connectPeripheral:self.peripheral options:nil];

    }


}

发现外设之后,可以通过一些过滤条件,连接你想连接的外围设备。连接外设,是否连接成功,通过以下代理方法返回。

#pragma mark - 连接外围设备状况
//中心管理者连接外设成功
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral {

    NSLog(@"连接外设成功 name : %@", peripheral.name);
    //连接成功之后,可以进行服务和特征的发现

    //设置外设的代理
    self.peripheral.delegate = self;

    //外设发现服务器  nil代表不过滤   这里会触发代理方法(void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error
    [self.peripheral discoverServices:nil];

}

- (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error {
    NSLog(@"外设连接失败 name : %@", peripheral.name);
}

- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error {
    NSLog(@"断开连接 name : %@", peripheral.name);
}

如若外设连接成功,即可进行服务和特征的发现discoverServices

#pragma mark - 获取外设的服务 和 特征
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error {

    NSLog(@"发现外设服务");

    if (error) {
        NSLog(@"服务不可用");
    }else {
        for (CBService *ser in peripheral.services) {
            NSLog(@"discover service : %@", ser);

            //添加条件,只针对UUID是181D的服务进行特征发现。也可以不加条件,对设备的所有服务进行特征发现,去掉if判断即可。
            if ([ser.UUID isEqual:[CBUUID UUIDWithString:@"181D"]]) {
               [peripheral discoverCharacteristics:nil forService:ser];
            }

        }
    }

}

- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(nonnull CBService *)service error:(nullable NSError *)error {

    NSLog(@"发现外设特征");
    CBService *finalService = [peripheral.services objectAtIndex:peripheral.services.count -1];
    if (service.UUID == NULL || finalService.UUID == NULL) {
        return;
    }

    if (error) {
        NSLog(@"特征发现失败!");
    }else {
        NSLog(@"discover characteristics:%@", service);

        for (CBCharacteristic *cbchar in service.characteristics) {
            NSLog(@"%@", cbchar);

            if ([service.UUID isEqual:[CBUUID UUIDWithString:@"181D"]]) {

                if ([cbchar.UUID isEqual:[CBUUID UUIDWithString:@"2A9E"]]) {
                    [self notification:service.UUID characteristicUUID:cbchar.UUID peripoheral:peripheral];
                    NSLog(@"2A9E========2A9E");
                }else if ([cbchar.UUID isEqual:[CBUUID UUIDWithString:@"2A9D"]]) {
                    [self notification:service.UUID characteristicUUID:cbchar.UUID peripoheral:peripheral];
                    NSLog(@"2A9D========2A9D");
                }else if ([cbchar.UUID isEqual:[CBUUID UUIDWithString:@"2A9C"]]) {
                    [self notification:service.UUID characteristicUUID:cbchar.UUID peripoheral:peripheral];
                    NSLog(@"2A9C========2A9C");
                }else {
                    NSLog(@"没有相关的特征UUID");
                }

            }else {
                NSLog(@"不是181D的服务!");
            }

        }

    }

    if ([self compareCBUUID:service.UUID UUID2:finalService.UUID]) {
        //全部服务读取完毕时才能使用
//        [self.cbManager cancelPeripheralConnection:peripheral];
//        NSLog(@"关闭外设连接!!!!");
    }

}

- (void)notification:(CBUUID *)serviceUUID characteristicUUID:(CBUUID *)characteristicUUID peripoheral:(CBPeripheral *)peripheral {

    CBService *service = [self getServiceFromUUID:serviceUUID peri:peripheral];
    if (!service) {
        NSLog(@"could not find service");
        return;
    }

    CBCharacteristic *cbChar = [self getCharacteristicFromUUID:characteristicUUID service:service];
    if (!cbChar) {
        NSLog(@"could not find characteristic");
        return;
    }

    //读取数据,如果数据是不断更新的,则需要用setNotifyValue这个
    [peripheral readValueForCharacteristic:cbChar];
//    [peripheral setNotifyValue:YES forCharacteristic:cbChar];
    NSLog(@"setNotifyValue for charac:%@", cbChar);
}

- (CBService *)getServiceFromUUID:(CBUUID *)UUID peri:(CBPeripheral *)peri {

    for (CBService *ser in peri.services) {
        if ([self compareCBUUID:ser.UUID UUID2:UUID]) {
            return ser;
        }
    }

    return nil;//在这个外设中没有找到相应服务
}

- (BOOL)compareCBUUID:(CBUUID *)UUID UUID2:(CBUUID *)UUID2 {

    if ([UUID isEqual:UUID2]) {
        return YES;
    }else {
        return NO;
    }

}

- (CBCharacteristic *)getCharacteristicFromUUID:(CBUUID *)UUID service:(CBService *)service {

    for (CBCharacteristic * cbChar in service.characteristics) {
        if ([self compareCBUUID:cbChar.UUID UUID2:UUID]) {
            return cbChar;
        }
    }

    return nil;//在这个服务中没有找到相应特征

}

发现了特征以后,针对某一特征进行数据读取,readValueForCharacteristic读取数据,如果数据是不断变化的,则要用setNotifyValue这个方法。数据读取都通过下面这个方法,获取到。

#pragma mark - 从外设读数据
//蓝牙传过来的数据都要经过这个回调
- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error {

    NSLog(@"value = %@", characteristic.value);

    if (error) {
        NSLog(@"读取数据出错了:%@",error);
    }else {
        if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:@"2A9E"]]) {
            if (characteristic.value || !error) {
                //处理数据
            }
        }

        if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:@"2A9D"]]) {
            [self writeValueToPeripheraleWithCharac:characteristic];
        }
    }

}

#pragma mark - 给外围设备发送数据
- (void)writeValueToPeripheraleWithCharac:(CBCharacteristic *)cbChar {

    uint8_t val = 1;
    NSData *valData = [NSData dataWithBytes:(void *)&val length:sizeof(val)];
    [self.peripheral writeValue:valData forCharacteristic:cbChar type:CBCharacteristicWriteWithResponse];

}

以上就是蓝牙通信的一个基本通信传输过程。

参考:http://www.cocoachina.com/ios/20161021/17813.html
如果文章有任何问题,可留言我,进行更改,谢谢!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值