iOS Bluetooth-2

本文介绍了iOS设备作为蓝牙中心管理器如何启动扫描、连接外围设备、发现服务和特征、读写及订阅特征值,详细阐述了每个步骤的实现方法和注意事项。

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

中心端执行常见类型的蓝牙任务,例如发现和连接到可用的外围设备,以及探索外围设备必须提供的数据并与之交互。

  • 启动中央管理器
  • 发现并连接正在广播的外围设备
  • 连接到外围设备后探索外围设备上的数据
  • 向外围服务的特征值发送读写请求
  • 订阅特征值以在更新时得到通知

启动中央管理器

myCentralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil options:nil];

发现正在广播的外围设备

[myCentralManager scanForPeripheralsWithServices:nil options:nil];

注意:如果指定第一个参数为nil,中央管理器返回所有发现的外围设备,而不管它们支持的服务。在实际的应用中,通常会指定一组CBUUID对象,每个对象代表外围设备正在广播的服务的唯一标识符(UUID),中央管理器仅返回广播这些服务的外围设备,从而允许扫描感兴趣的设备。

每次中央设备发现外围设备,就会调用下面的代理方法。新发现的设备由CBPeripheral对象返回。如果要连接发现的外围设备,保持对它的引用,以便系统不会释放它。下面的例子演示了使用属性对外围设备引用的场景。

- (void)centralManager:(CBCentralManager *)central
 didDiscoverPeripheral:(CBPeripheral *)peripheral
     advertisementData:(NSDictionary *)advertisementData
                  RSSI:(NSNumber *)RSSI {
 
    NSLog(@"Discovered %@", peripheral.name);
    self.discoveredPeripheral = peripheral;
    ...

如果希望连接到多个设备,则可以改为使用一个NSArray持有发现的外围设备。无论如何,一旦找到感兴趣的所有外围设备,停止扫描以节省电量。

[myCentralManager stopScan];

发现外围设备后连接它

发现感兴趣的外围设备广播服务后,调用中央管理器的连接方法,请求连接到外围设备

[myCentralManager connectPeripheral:peripheral options:nil];

如果连接请求成功,中央管理器调用其代理方法

- (void)centralManager:(CBCentralManager *)central
  didConnectPeripheral:(CBPeripheral *)peripheral {
 
    NSLog(@"Peripheral connected");
    peripheral.delegate = self;
    ...

发现连接的外围设备的服务

与外围设备连接后,可以探索其数据。探索数据的第一步是发现可用的服务。因为外围设备可广播的数据量存在大小限制,可能发现外围设备的服务比它广播的要多。可以通过调用外围设备的方法,来发现外围设备提供的所有服务

[peripheral discoverServices:nil];

在实际应用中,通常不会将nil作为参数传入,因为这样会返回外围设备上所有可用的服务。因为外围设备可能包含更多比你感兴趣的服务,所以发现这些服务会浪费电池的寿命并且是不必要的时间花费。相反,通常指定已经知道的感兴趣的服务的UUID。

当发现指定的服务时,外围设备(连接的CBPeripheral对象)调用委托对象的peripheral:didDiscoverServices:方法。Core Bluetooth创建一个CBService数组,存储外围设备发现的所有服务。如下面演示的,你可以实现下面代理方法,去访问发现的服务数组。

- (void)peripheral:(CBPeripheral *)peripheral
didDiscoverServices:(NSError *)error {
 
    for (CBService *service in peripheral.services) {
        NSLog(@"Discovered service %@", service);
        ...
    }
    ...

发现服务的特征

当找到感兴趣的服务时,探索外设必须提供的下一步是发现该服务的所有特征。发现服务的所有特征就像调用外围设备的发现特征方法一样简单

NSLog(@"Discovering characteristics for service %@", interestingService);
[peripheral discoverCharacteristics:nil forService:interestingService];

在实际应用中,通常不会讲nil作为第一个参数传入,因为这样做会返回外围设备服务的所有特征。因为外围设备的服务可能包含比你感兴趣的特征的更多的特性,所以发现这些特性可能会浪费电磁寿命并且是不必要的时间花费。相反,通常指定感兴趣的特征的UUID。

当发现服务的特征时,外围设备调用其委托对象的peripheral:didDiscoverCharacteristicsForService:error:方法。Core Bluetooth创建一个CBCharacteristic对象的数组存储所有发现的特征。

- (void)peripheral:(CBPeripheral *)peripheral
didDiscoverCharacteristicsForService:(CBService *)service
             error:(NSError *)error {
 
    for (CBCharacteristic *characteristic in service.characteristics) {
        NSLog(@"Discovered characteristic %@", characteristic);
        ...
    }
    ...

检索特征值

特征包含一个值,表示有关外围设备服务的信息。可以通过直接订阅特征来检索特征的值

读取特征值

找到感兴趣的服务的特征后,可以通过调用外围设备的readValueForCharacteristic:方法读取特征值。

NSLog(@"Reading value for characteristic %@", interestingCharacteristic);
[peripheral readValueForCharacteristic:interestingCharacteristic];

当尝试读取特征的值时,外围设备会调用其委托对象的peripheral:didUpdateValueForCharacteristic:error:方法来检索值。如果成功检索到值,则可以通过特征的value属性访问它。

- (void)peripheral:(CBPeripheral *)peripheral
didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic
             error:(NSError *)error {
 
    NSData *data = characteristic.value;
    // parse the data as needed
    ...

注意:并非所有的特征都是可读的。可以通过检查其属性是否包含CBCharacteristicPropertyRead常量来确定特征是否可读。如果尝试读取不可读的特征值,则peripheral:didUpdateValueForCharacteristic:error:委托方法会返回适当的错误。

订阅特征值

尽管使用readValueForCharacteristic:方法读取特征值对于静态值是有效的,但它并不是检索动态值的最有效方法。通过订阅它们来检索随时间变化的特征值(例如,你的心率)。当订阅一个特征的值时,会再值更改时收到来自外围设备的通知。

通过调用外围设备的方法订阅感兴趣的特征值setNotifyValue:forCharacteristic:,第一个参数指定为YES。

[peripheral setNotifyValue:YES forCharacteristic:interestingCharacteristic];

当订阅一个特征的值时,外围设备会调用委托对象的peripheral:didUpdateNotificationStateForCharacteristic:error:方法。如果订阅请求因任何原因失败,可以实现此委托方法来访问错误原因。

- (void)peripheral:(CBPeripheral *)peripheral
didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic
             error:(NSError *)error {
 
    if (error) {
        NSLog(@"Error changing notification state: %@",
           [error localizedDescription]);
    }
    ...

注意:并非所有的特征都提供订阅。可以通过检索其属性是否包含CBCharacteristicPropertyNotify或CBCharacteristicPropertyIndicate常量来确定特征是否提供订阅。

成功订阅值后,外围设备会在值发生更改时通知您的应用。每次更改时,外围设备都会调用其委托对象的peripheral:didUpdateValueForCharacteristic:error:方法。要检索更新的值,可以按照上述读取特征值中所述的相同方法实现此方法。

写特征的值

有时写特征的值是有意义的。例如,如果你的应用程序与蓝牙低能耗数字恒温器交互,可能希望为恒温器提供一个设置房间温度的值。如果一个特征的值是可写的,可以通过外设的writeValue:forCharacteristic:type:方法用NSData写它的值,如下所示:

NSLog(@"Writing value for characteristic %@", interestingCharacteristic);
[peripheral writeValue:dataToWrite forCharacteristic:interestingCharacteristic
        type:CBCharacteristicWriteWithResponse];

当写入特征的值时,指定要写入的类型。在上面的示例中,写入类型是,它指示外围设备通过调用委托对象CBCharacteristicWriteWithResponse的方法让你的应用应用程序知道是否写入成功。实现peripheral:didWriteValueForCharacteristic:error:委托方法来处理错误情况,如下所示:

- (void)peripheral:(CBPeripheral *)peripheral
didWriteValueForCharacteristic:(CBCharacteristic *)characteristic
             error:(NSError *)error {
 
    if (error) {
        NSLog(@"Error writing characteristic value: %@",
            [error localizedDescription]);
    }
    ...

相反,如果将写入类型指定为CBCharacteristicWriteWithoutResponse,则将尽最大努力执行写入成功操作,并且不保证也不报告交付。外围设备不调用任何委托方法。

注意:特性可能只支持某些类型的写入,或者根本不支持。可以通过检索其属性CBCharacteristicPropertyWrite或常量CBCharacteristicPropertyWriteWithoutResponse中的一个来确定特征支持的写入类型。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值