9

我正在开发适用于 iOS 的蓝牙 LE 应用程序。我在 iOS 中使用 Core Bluetooth 框架来处理所有通信。

问题与描述:

当我使用单个标签时,尽管有许多连接和断开连接,但单个标签无缝连接并且手机发现它提供服务。

此外,当多个低功耗蓝牙标签首次连接时,它们会无缝连接,手机会发现它们的服务。

当标签断开连接然后重新连接到手机时,标签连接正常。但是两个标签之一(任何一个)似乎都没有宣传其服务。即当应用程序打开并且标签重新连接时,DiscoverServices方法不会调用didDiscoverServices委托。

为什么只有在与多个设备连接时才会发生这种情况。

我已经正确设置了peripheral.delegate。我已经尝试了一切,包括重复重新连接、重复对标签的 DiscoverServices 调用。似乎没有任何效果。

如何将多个标签重新连接到手机并仍然发现所有服务。

请帮忙

谢谢,
Manju

4

8 回答 8

22

我遇到了同样的问题,但意识到我没有将其设置delegateCBPeripheralafterdidConnectPeripheral被调用。

- (void) centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral
{
    NSLog(@"Peripheral Connected: %@", peripheral.name);

    peripheral.delegate = self;

    if (peripheral.services) {
        [self peripheral:peripheral didDiscoverServices:nil];
    } else {
        [peripheral discoverServices:@[[CBUUID UUIDWithString:CUSTOM_UUID]]];
    }  
}
于 2014-04-16T17:28:19.917 回答
16

我在使用 CoreBluetooth 连接到蓝牙 LE 设备时遇到了类似的问题,在我的情况下,我从我的 Mac(中央)连接到 iOS 设备(外围设备)。

如果我理解正确,模式非常一致,当我第一次运行我的 Mac 应用程序进行调试时,它总是检测到并连接到任何蓝牙 LE 设备(外围设备),最重要的是,它还可以很好地发现它们的服务/特性。问题从第二次运行开始(例如,更改一些代码,点击 cmd-R 重新启动调试)。中央仍然检测外围设备并连接到它们,但是它无法发现任何服务/特征。换句话说,委托peripheral:didDiscoverServices:永远peripheral:didDiscoverCharacteristicsForService:error:不会被调用。

经过大量试验和错误的解决方案非常简单。似乎 CoreBluetooth 缓存servicescharacteristics仍然连接的外围设备,虽然在本地看起来它已经与应用程序断开连接,但外围设备仍然保持与系统的蓝牙连接。对于这些类型的连接,不需要(重新)发现服务和特性,只需直接从外围对象访问它们,检查nil是否应该发现它们。此外,如前所述,由于外围设备处于连接之间的状态,因此最好cancelPeripheralConnection:在尝试连接之前立即调用。它的要点如下,假设我们已经发现了要连接的外围设备:

-(void) centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI
{
    [central cancelPeripheralConnection:peripheral]; //IMPORTANT, to clear off any pending connections    
    [central connectPeripheral:peripheral options:nil];
}

-(void) centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral
{
    peripheral.delegate = self;

    if(peripheral.services)
        [self peripheral:peripheral didDiscoverServices:nil]; //already discovered services, DO NOT re-discover. Just pass along the peripheral.
    else
        [peripheral discoverServices:nil]; //yet to discover, normal path. Discover your services needed
}

-(void) peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error
{
    for(CBService* svc in peripheral.services)
    {
        if(svc.characteristics)
            [self peripheral:peripheral didDiscoverCharacteristicsForService:svc error:nil]; //already discovered characteristic before, DO NOT do it again
        else
            [peripheral discoverCharacteristics:nil
                                     forService:svc]; //need to discover characteristics
    }
}

-(void) peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error
{
    for(CBCharacteristic* c in service.characteristics)
    {
        //Do some work with the characteristic...
    }
}

这对我来说适用于 Mac 应用程序中的 CBCentralManager。从未在 iOS 中测试过,但我认为它应该非常相似。

于 2014-02-03T14:58:12.527 回答
1

事实证明,我在“ didDiscovercharacteristicsForService ”委托方法中向设备发出了导致连接不稳定的命令。

如果您遇到类似问题,我建议您让委托方法在没有任何干预(任何类型)的情况下完成,并将 CBPeripheral 传递给您设计的另一个函数,以向设备传递任何值/发出命令。

无论如何,谢谢威廉森。

所以步骤如下..
1> 搜索标签,
2> 如果在范围内,连接到标签
3> 如果已连接,调用 DISCOVER 服务方法(不要中断)
4> 在 DidDiscoverServices,调用 DISCOVER 特征方法
..
在 DidDiscoverCharacteristics方法,等到发现所有特征。然后,最后,在代码中调用一个函数,该函数将进行必要的设置..
...
代码示例

-(void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error
{

    for (int i=0; i < peripheral.services.count; i++) {
        CBService *s = [peripheral.services objectAtIndex:i];
        printf("Fetching characteristics for service with UUID : %s\r\n",[self CBUUIDToString:s.UUID]);
        [peripheral discoverCharacteristics:nil forService:s];
    }

}


- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error
{        
    if (!error)
    {
        CBService *s = [peripheral.services objectAtIndex:(peripheral.services.count - 1)];
        if([self compareCBUUID:service.UUID UUID2:s.UUID])
        {
           // This is when the **Tag** is completely connected to the Phone and is in a mode where it can accept Instructions from Device well.

            printf("Finished discovering characteristics");
           // Now Do the Setup of the Tag
            [self setupPeripheralForUse:peripheral];

        }
    }

    else
    {
        printf("Characteristic discorvery unsuccessfull !\r\n");
    }
}

-(void) setupPeripheralForUse:(CBPeripheral *)peripheral
{

    // DO all your setup in this function. Separate Perpiheral Setup from the process that synchronizes the tag and the phone. 

}
于 2012-08-29T05:17:15.097 回答
1

我一直有同样的问题。在我的情况下,它似乎发生了大约 1/3 的时间。我尝试了 PL 提供的解决方案,但在 iOS 上没有成功。这里可能有许多移动部件在起作用,这可能会导致这个问题(蓝牙设备固件、CoreBluetooth 等),但我通过简单地跟踪 NSMutableDictionary 中等待服务/特征发现的设备并使用 GCD 来解决它检查它是否在合理的时间内完成了它的发现,并在必要时重试。所以是这样的:

- (void)requestDiscoverServicesForPeripheral:(CBPeripheral *)peripheral 
{
      peripheral.delegate = self;
      NSString *uuid =[self stringUUIDForUUID:peripheral.UUID];
      NSLog(@"discovering %d services ", self.interestingServices.count);
      [peripheral discoverServices:self.interestingServices];
      [self.pendingConnectionDevices setObject:peripheral forKey:uuid];
       __weak typeof(self) weakSelf = self;
      dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 *NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        if ([weakSelf.pendingConnectionDevices objectForKey:uuid]) {

               //request discover services again
               NSLog(@"services did not discover, requesting again!");
               [weakSelf.btManager cancelPeripheralConnection:peripheral];
               [weakSelf.btManager connectPeripheral:peripheral options:nil];
         }
    });
 }

然后,当peripheral:didDiscoverServices:error回调时,我将它从我的 pendingConnectionDevices 字典中删除。这似乎工作得很好。我已经看到它在成功之前尝试发现服务多达 3 次。我希望这有帮助。

于 2014-04-12T20:54:19.983 回答
1

有时是硬件问题。我刚刚遇到一个情况,硬件将进入可扫描、可连接的睡眠模式,但根本不回调discoverServices。

还有一种情况发生在我整夜开发BLE时,突然,无论我做什么,设备都会对discoverServices保持沉默。最后我发现如果我重新启动我的 iPhone5s 就会变得正常。

有一天,蓝牙硬件工程师告诉我,BLE 的规范只说设备必须在 30 秒内再次连接。因此,如果我一遍又一遍地连接和断开连接,它可能无法按预期工作......我仍然对此表示怀疑。

于 2016-01-28T06:59:15.030 回答
1

我试图应用上述所有答案,但它对我不起作用,因为我缺课CBPeripheralDelegate了。

class BLEHandler : NSObject, CBCentralManagerDelegate, CBPeripheralDelegate{

  func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {

    peripheral.delegate = self

    peripheral.discoverServices(nil)

    print("Connected: \(peripheral.state == .connected ? "YES" : "NO")")
  }

  func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {

    for service: CBService in peripheral.services! {
        peripheral.discoverCharacteristics(nil, for: service)
        print(service)
    }
  }

}
于 2017-11-24T01:03:25.670 回答
0

我正在做你在回答中所说的一切,但我仍然不时看到这个问题。我的猜测是核心蓝牙进入一个奇怪的状态,可能是由于特定的连接、订阅和断开顺序。

我发现解决问题的唯一方法是重新启动 iOS 设备。这个问题可能会在 iOS 7.1 中得到修复。

于 2014-01-20T16:05:34.463 回答
0

我的头痛是由于缺乏对外围设备的强烈参考引起的

所以我添加了参考,问题就消失了

private var activePeripheral: CBPeripheral?

func connect(_ peripheral: CBPeripheral) {
        disconnect(peripheral)
        activePeripheral = peripheral
        self.central.connect(peripheral, options: nil)
    }
于 2016-10-12T10:10:26.203 回答