iPhone не обнаруживает Службы по метке Bluetooth LE при повторном подключении

Я работаю над приложением Bluetooth LE для iOS. Я использую инфраструктуру Core Bluetooth в iOS для обработки всех коммуникаций.

Вопрос и описание:

Когда я использую один тег, несмотря на многочисленные подключения и отключения, один тег подключается без проблем, и телефон обнаруживает, что он обслуживается.

Кроме того, когда несколько тегов Bluetooth LE подключаются в первый раз, они подключаются без проблем, и телефон обнаруживает их службы.

Когда теги отключаются, а затем снова подключаются к телефону, теги подключаются. отлично. Но один из двух тегов (любой) похоже не рекламирует свои услуги. т. е. когда приложение открыто и тег повторно подключается, метод DiscoverServices не вызывает делегата didDiscoverServices.

Почему это происходит только тогда, когда происходит соединение с несколькими устройствами.

Я правильно установил peripheral.delegate. Я пробовал все, включая повторные повторные подключения, повторные вызовы DiscoverServices к тегу. Кажется, ничего не работает.

Как я могу повторно подключить несколько тегов к телефону и при этом обнаружить все службы.

Пожалуйста, помогите

Спасибо,
Манджу


person Manju Kiran    schedule 17.08.2012    source источник
comment
Вы должны опубликовать код для этого. corebluetooth немного глючит, и у меня самого были проблемы с этим обратным вызовом.   -  person chwi    schedule 23.08.2012


Ответы (8)


У меня была та же проблема, но я понял, что не устанавливал delegate в CBPeripheral после вызова didConnectPeripheral.

- (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]]];
    }  
}
person jhalla14    schedule 16.04.2014

Я столкнулся с аналогичной проблемой с CoreBluetooth для подключения к устройствам Bluetooth LE, в моем случае с подключением к устройствам iOS (периферийным устройствам) с моего Mac (центрального).

Если я вас правильно понимаю, шаблон вполне последователен, когда я впервые запускаю свое приложение Mac для отладки, оно всегда обнаруживает и подключается к любым устройствам Bluetooth LE (периферийным устройствам), что наиболее важно, оно также обнаруживает их сервисы / характеристики. Проблема начинается при втором запуске (например, измените какой-либо код, нажмите cmd-R, чтобы перезапустить отладку). Централ по-прежнему обнаруживает периферийные устройства и подключается к ним, но не может обнаружить какие-либо службы/характеристики. Другими словами, делегаты peripheral:didDiscoverServices: и peripheral:didDiscoverCharacteristicsForService:error: никогда не вызываются.

Решение после множества проб и ошибок оказалось на удивление простым. Кажется, что CoreBluetooth кэширует services и characteristics для периферийных устройств, которые все еще подключены, хотя локально это выглядит так, как будто оно было отключено от приложения, периферийное устройство все еще поддерживает соединение Bluetooth с системой. Для этого типа соединений нет необходимости (повторно) обнаруживать службы и характеристики, просто обращайтесь к ним напрямую из периферийного объекта, проверьте 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...
    }
}

Это хорошо работает для меня для приложения CBCentralManager в Mac. Никогда не тестировал его в iOS, но я предполагаю, что он должен быть очень похожим.

person P.L.    schedule 03.02.2014

Оказывается, я отдавал устройству команду в методе делегата didDiscovercharacteristicsForService», которая вызывала нестабильность подключения.

Если вы столкнулись с похожими проблемами, я предлагаю вам позволить методу делегирования завершиться без какого-либо вмешательства (любого рода) и передать CBPeripheral другой функции, разработанной вами для передачи любых значения / дать команду устройствам.

В любом случае спасибо Вильхемсен.

Таким образом, шаги следующие..
1> Поиск тега,
2> Если он находится в диапазоне, ПОДКЛЮЧИТЬСЯ к тегу
3> Если соединение установлено, вызовите метод службы DISCOVER (не прерывайте)
4 > В DidDiscoverServices вызовите метод DISCOVER Characteristics
..
В методе 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. 

}
person Manju Kiran    schedule 29.08.2012
comment
Странно, как я вернулся сюда :P У меня все та же проблема, не могли бы вы уточнить, какую команду вы дали? Или как теперь выглядит ваш обратный вызов? Это было бы очень полезно, спасибо. PS: рад видеть, что вы решили это :) - person chwi; 13.03.2013
comment
Привет, Вильгельмсен, ,‹br› Основное решение кода заключается в том, что мы не устанавливаем наши предпочтения в теге, пока услуги и характеристики обнаруживаются. Как только все службы и их характеристики будут обнаружены, мы можем вызвать вызов setupPeripheral. Я добавлю свой код в качестве еще одного ответа. - person Manju Kiran; 31.07.2013

У меня была такая же проблема. кажется, это происходит примерно в 1/3 раза в моем случае. Я попробовал решение, предоставленное P.L. но у меня не было успеха на iOS. Возможно, здесь работает много движущихся частей, которые могут способствовать этой проблеме (прошивка устройства Bluetooth, 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 раз, прежде чем добиться успеха. Надеюсь, это поможет.

person Grahambo    schedule 12.04.2014

Иногда это аппаратная проблема. Я только что столкнулся со случаем, когда оборудование переходит в спящий режим, который можно сканировать, подключать, но вообще не перезванивать для DiscoverServices.

Также есть ситуация, которая произошла со мной, когда я всю ночь разрабатывал BLE, и внезапно устройство перестало работать для DiscoverServices, независимо от того, что я делал. Наконец я обнаружил, что это станет нормальным, если я перезагружу свой iPhone5s.

И однажды инженер по оборудованию Bluetooth сказал мне, что спецификация BLE говорит только о том, что устройство должно быть снова подключено в течение 30 секунд. Поэтому, если я буду подключаться и отключаться снова и снова, это может работать не так, как ожидалось... В чем я все еще сомневаюсь.

person Orange    schedule 28.01.2016

Я пытался применить все приведенные выше ответы, но у меня это не сработало, потому что мне не хватало 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)
    }
  }

}
person Maihan Nijat    schedule 24.11.2017

Я делаю все, что вы говорите в своем ответе, но время от времени все еще вижу эту проблему. Я предполагаю, что Core Bluetooth переходит в странное состояние, вероятно, из-за определенной последовательности подключения, подписки и отключения.

Единственный способ, который я нашел для решения проблемы, — перезагрузить устройство iOS. Однако эта проблема может быть исправлена ​​​​в iOS 7.1.

person Mark    schedule 20.01.2014
comment
Привет, Марк, Одна вещь, на которую следует обратить внимание, это то, что радио BTLE следует определенному шаблону, когда оно взаимодействует с одним запросом на подключение устройства за раз. Возможно, вы могли бы запустить функции обнаружения и распознавания служб в строке NsOperation, используя NsOperationQueue в отдельном потоке? Это нам очень помогло - person Manju Kiran; 02.02.2014

Моя головная боль была вызвана отсутствием сильной ссылки на периферийные устройства.

Итак, я добавил ссылку, и проблема исчезла

private var activePeripheral: CBPeripheral?

func connect(_ peripheral: CBPeripheral) {
        disconnect(peripheral)
        activePeripheral = peripheral
        self.central.connect(peripheral, options: nil)
    }
person HotJard    schedule 12.10.2016