【问题标题】:Objective-c bluetooth says it's connected but CBCentralManager does not discover itObjective-c 蓝牙说它已连接但 CBCentralManager 没有发现它
【发布时间】:2017-12-25 03:45:35
【问题描述】:

在我的应用程序中,我首先使用委托方法retrieveConnectedPeripheralsWithServices 搜索以前连接的设备,如果没有找到则扫描附近的设备。这是代码

- (void)searchForPeripherals {
    NSLog(@"***  scanning for Bluetooth peripherals...  ***");

    //Check to see if any devices were connected already
    if(self.ourPeripheral != nil) {
        [self connectToDevice];

    } else {
        //Search for previously paired devices...
        bool foundPairedDevices = [self checkForAndConnectToPreviouslyPairedDevices];

        //None found, scan for new devices nearby...
        if(!foundPairedDevices) {
            NSLog(@"No paired boxes found, checking device powered state...");

            //If the app user has "bluetooth" option turned on
            if(self.centralManager.state == CBCentralManagerStatePoweredOn) {
                NSLog(@"--- central manager powered on.");
                NSLog(@"...begin scanning...");

                [self.centralManager scanForPeripheralsWithServices:nil
                                                            options:@{CBCentralManagerScanOptionAllowDuplicatesKey: @(YES)}];

            //No, user has "bluetooth" turned off
            } else {
                NSLog(@"--- central manager is NOT powered on.");
            }
        }
    }
}


- (bool)checkForAndConnectToPreviouslyPairedDevices {
    NSLog(@"our peripheral device: %@", self.ourPeripheral);

    NSArray *dcBoxesFound = [self.centralManager retrieveConnectedPeripheralsWithServices:@[[CBUUID UUIDWithString:SERVICE_UUID]]];
    NSLog(@"Previously paired DC boxes?: %@", dcBoxesFound);

    //Are there any previously paired devices?
    if(dcBoxesFound != nil && [dcBoxesFound count] > 0) {
        CBPeripheral *newestBoxFound = [dcBoxesFound firstObject];
        newestBoxFound.delegate = self;

        self.ourPeripheral = newestBoxFound;
        self.deviceUUID = [CBUUID UUIDWithString:[newestBoxFound.identifier UUIDString]];

        [self connectToDevice];

        return YES;

    } else {
        return NO;
    }
}


- (void)connectToDevice {
    if(self.ourPeripheral != nil) {
        [self.centralManager connectPeripheral:self.ourPeripheral options:nil];
    }
}


- (void)centralManager:(CBCentralManager *)central
 didDiscoverPeripheral:(CBPeripheral *)peripheral
     advertisementData:(NSDictionary *)advertisementData
                  RSSI:(NSNumber *)RSSI {

    NSLog(@"scanned and found this peripheral: %@", peripheral);
    NSLog(@"advertisment data: %@", advertisementData);

    if(!self.isConnectedToDevice && [[advertisementData objectForKey:@"kCBAdvDataLocalName"] localizedCaseInsensitiveContainsString:@"dc-"]) {
        NSLog(@"\n");
        NSLog(@"-------------------------------------------");
        NSLog(@"DC peripheral found! Attempting to connect to the following...: %@", peripheral);

        peripheral.delegate = self;
        self.ourPeripheral = peripheral;

        self.deviceUUID = [CBUUID UUIDWithString:[peripheral.identifier UUIDString]];

        [self connectToDevice];

        NSLog(@"-------------------------------------------");
        NSLog(@"\n");
    }
}


- (void)centralManager:(CBCentralManager *)central
  didConnectPeripheral:(CBPeripheral *)peripheral {
    NSLog(@"--- didConnectPeripheral");

    peripheral.delegate = self;
    [peripheral discoverServices:@[[CBUUID UUIDWithString:SERVICE_UUID]]];
}

问题

当我启动应用程序时,它通常连接得很好。一切都很好。然后在非常不可预测和奇怪的时候,BT 连接会以某种方式“卡住”。我所说的卡住的意思是它永远不会真正连接。我的盒子上的蓝灯亮着,好像系统已连接到它,但在我的应用程序中会发生这种情况。

1) retrieveConnectedPeripheralsWithServices 方法找到一个空数组,其中包含以前连接的设备,告诉调用它的方法没有找到以前连接的设备。

2) 触发scanForPeripheralsWithServices:nil 方法并使用didDiscoverPeripheral 方法开始扫描。

3) didDiscoverPeripheral 从来没有发现附近的任何带有 kCBAdvDataLocalName 前缀的“dc-”或其他的盒子

如果我要进入 iOS 设置 -> 蓝牙 -> 忘记这个设备(必须按两次,这让我觉得它以某种方式“卡住”了)然后实际上一起关闭了 BT 选项......等等2秒,然后重新打开它...然后重新启动应用程序,一切正常。

1) 应用启动

2) 查看之前没有连接的设备

3) 扫描外围设备并找到我的前缀框名称“dc-whatever”

4) 要求我与 BT 设备配对,然后我恢复完整功能

如果我随后关闭应用程序并重新启动它,retrieveConnectedPeripheralsWithServices 会毫无问题地找到我之前连接的盒子并无缝连接...

那么...这里发生了什么?为什么它有时会随机“卡住”?

编辑:

我确实意识到配对和连接不是一回事,因此某些方法的命名非常糟糕。

【问题讨论】:

    标签: ios objective-c bluetooth cbperipheral cbcentralmanager


    【解决方案1】:

    这是蓝牙 LE 编程的一个常见问题,由于 API 都是异步的,这一点变得更加困难。

    典型的解决方案是让代码在某些事情没有完成时重试。而且因为您不一定会收到错误消息(您可能只是不会收到下一个回调),因此您最终需要做的是设置计时器以在合理的时间段后开始重试 - 例如 5-10 秒。

    正如您所注意到的,在某些情况下(例如在后台,如果设备连接,或以其他方式停止广告),您只会收到一个对 didDiscoverPeripheral 的回调。因此,您确实需要保存CBPeripheral 对象的副本,以便在发生超时时可以重新使用它。这是我将使用的基本逻辑:

    1. 当您在didDiscoverPeripheral 中发现新外设时,将对象实例保存在名为peripheralForConnectionAttempt 的变量中,然后启动5 秒计时器。
    2. 如果didConnectPeripheral中的连接成功完成,请将peripheralForConnectionAttempt的值设置为nil。
    3. 当计时器关闭时,检查peripheralForConnectionAttempt 是否不为零,如果是,则重试此对象,就像调用了didDiscoverPeripheral 一样。您可能需要一个计数器来将重试次数限制为 10 次或类似的值。

    旁注:

    当您说蓝灯一直亮着时,这可能意味着 BLE 外设设备认为它已经建立了 BLE 连接。执行此操作的外围设备通常会停止广播,直到连接中断。如果 iOS 设备认为它没有连接,而外围设备确实连接了,这会让你陷入一个糟糕的境地,你必须以某种方式断开连接。不幸的是,CoreLocation 没有为您提供执行此操作的 API。

    在一个项目中,我在蓝牙外设固件中实现了这一点,如果发生通信超时,我会断开连接。但如果你不控制固件,你显然无法做到这一点。

    如您所见,将电源循环至蓝牙会中断所有活动连接。但在 iOS 上,您不能以编程方式执行此操作。

    如果您不控制外围固件,并且无法找到任何方法来避免锁定与设备的连接(可能是通过更改操作时间?),那么您可能别无选择,只能简单地检测问题,在适当时提醒用户,并在用例需要时指示用户循环蓝牙。我知道,这不是一个理想的解决方案。

    【讨论】:

    • 太棒了,非常感谢。我确实拥有该设备并且能够更改固件,那么我应该在包装盒中更改什么?我还不太确定,因为我对草图和微控制器真的很陌生,如何像你提到的那样检查超时。
    • 这完全取决于您的设备的工作方式。如果它在大约 5 秒内没有得到任何通信,我会让它断开连接。这可能是在连接之后,或者总是,取决于您的用例。
    猜你喜欢
    • 2018-05-10
    • 1970-01-01
    • 1970-01-01
    • 2014-04-06
    • 1970-01-01
    • 1970-01-01
    • 2015-11-25
    • 2014-07-08
    • 1970-01-01
    相关资源
    最近更新 更多