Повторно подключите соединение Bluetooth 4.0, когда пользователь принудительно закроет приложение - PullRequest
0 голосов
/ 12 декабря 2018

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

  1. При первом запуске пользователь приложения должен подключиться к устройству BLE - это работает
  2. Когда приложение работает в фоновом режиме, соединения все еще работают
  3. Если я выключаю устройство BLE и включаю снова, соединение восстанавливается - работает
  4. Когда пользователь выходит и возвращается домой, соединение восстанавливается, и пользователь получает уведомление о том, что он находится близко к устройству - работает

Все это решается путем превращения Bluetooth 4.0 LE в iBeacon.Когда пользователь достаточно близко, iBeacon начинает посылать сигналы, и приложение iOS запускается, и пользователь получает push-уведомление, соединение восстанавливается.

Проблема возникает, когда пользователь принудительно покидает приложение.iBeacon по-прежнему работает, потому что, когда пользователь подключен к BLE, устройство BLE работает как устройство Bluetooth. Но когда соединение потеряно, BLE работает как iBeacon и рекламирует приложение iOS.Когда пользователь принудительно закрывает приложение, пользователь получает локальное push-уведомление о том, что приложение близко к iBeacon, так что это означает, что приложение перезапускается на пару секунд (я думаю, 10 секунд), но я не могу с этим восстановить соединение.

Это код для тигра уведомления и, как я надеялся, после повторного выхода BLE переподключится.

   func locationManager(_ manager: CLLocationManager, didDetermineState state: CLRegionState, for region: CLRegion) {
    // Check if the user's INSIDE the region, not outside...

    guard state == CLRegionState.inside else { print("Error"); return }

    if state == CLRegionState.inside{

        let content = UNMutableNotificationContent()
        content.title = "Device found!"
        content.body = "You're close to your BLE Device, reestablish connection!"

        let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 1, repeats: false)
        let request = UNNotificationRequest(identifier: "1389402823904", content: content, trigger: trigger)

        UNUserNotificationCenter.current().add(request) { (err:Error?) in
        }

        centralManager.scanForPeripherals(withServices: nil, options: nil)
        let uuid = UUID(uuidString: "74278BDA-B644-4520-8F0C-720EAF059935")!
        guard let mainPeripheral = mainPeripheral else {return}
        centralManager.connect(mainPeripheral, options: nil)

        centralManager.retrievePeripherals(withIdentifiers: [uuid])
        DispatchQueue.main.asyncAfter(deadline: .now() + 3.0) {
            self.centralManager.stopScan()
        }

    }

}

}

Для простоты, uuid жестко закодирован.Как я понимаю, didDeterminateState запускается, когда iBeacon отправляет сигнал, и я проверяю CLRegionState, находится ли область внутри, что означает, что рядом с iBeacon метод для локальных уведомлений получает триггеры, тогда мне нужно выполнить повторное сканирование для устройств BLE, чтобы яя звоню scanForPeripherals, но не connect метод.ScanForPeripherals должен вызывать метод didDiscover:

    func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
    print(peripheral)

    if peripheral.name == "DOPEY"{

        peripheral.delegate = self
        peripheral.discoverServices([HM_10_ServiceCharacteristic])
        mainPeripheral = peripheral
        centralManager.connect(peripheral, options: nil)

        centralManager.stopScan()

    }

}

Когда он находит DOPEY имя периферийного устройства, устройство должно подключиться.Для тестов я использую HM-10 Bluetooth 4.0 LE.Когда пользователь принудительно выходит из приложения, он отправляет локальное push-уведомление, но не восстанавливает соединение.

Я с нетерпением жду любой помощи.Цените!

Ответы [ 2 ]

0 голосов
/ 13 декабря 2018

Вам не нужно заставлять BLE действовать как маяк, если пользователь не убивает приложение.Я имею в виду, что после того, как периферийное устройство было отключено для повторного подключения, пока оно доступно, вам просто нужно снова вызвать connect в обратном вызове отключения, если ваше приложение имеет возможность работать в фоновом режиме в качестве центрального, оно будет работать отлично.Такое поведение представляется более надежным, чем мониторинг региона iBeacon.
Проблема запускается, если пользователь убивает ваше приложение.Вы должны знать, что именно такое поведение разработало Apple, я имею в виду, что если пользователь убивает ваше приложение, возможно, оно не захочет беспокоиться о подключении к некоторым устройствам.
В этом случае, похоже, единственным решением являетсясделать устройство работает как iBeacon.В этом случае, если обнаружено периферийное устройство, ваше приложение запускается в фоновом режиме на короткое время.Дело в том, что сканирование в фоновом режиме работает только в том случае, если вы настроили конкретную службу CBUUID вашего устройства.

Приложения, которые указали центральный режим Bluetooth, могут сканировать в фоновом режиме.При этом они должны явно сканировать одну или несколько служб, указав их в параметре serviceUUIDs.Параметр сканирования CBCentralManager игнорируется при сканировании в фоновом режиме.

Почему вы не используете только retrievePeripheralWithIdentifiers?После подключения к устройству этот UUID устанавливается.
Сканирование выполняется асинхронно, поэтому, почему вы пытаетесь подключиться к периферийному устройству сразу после вызова метода сканирования?
Вам следует выбрать один или другой способ

0 голосов
/ 13 декабря 2018

Нет необходимости повторно сканировать устройство;Вы должны сохранить свойство identier при первом обнаружении.Затем вы можете использовать retrievePeripherals(withIdentifiers:), чтобы попытаться получить ссылку на CBPeripheral.Если вам это удастся, просто позвоните connect.

. В вашем коде показана попытка сделать что-то подобное, но вы использовали (как я полагаю) ваш UUID службы, и вы ничего не делаете срезультат из retrievePeripherals(withIdentifiers:) (вы также не получите этот код из-за оператора guard).

Вы должны использовать что-то вроде:

func locationManager(_ manager: CLLocationManager, didDetermineState state: CLRegionState, for region: CLRegion) {
    // Check if the user's INSIDE the region, not outside...

    guard state == CLRegionState.inside else { print("Error"); return }


    let content = UNMutableNotificationContent()
    content.title = "Device found!"
    content.body = "You're close to your BLE Device, reestablish connection!"

    let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 1, repeats: false)
    let request = UNNotificationRequest(identifier: "1389402823904", content: content, trigger: trigger)

    UNUserNotificationCenter.current().add(request) { (err:Error?) in
    }

    if self.mainPeripheral == nil {
        let defaults = UserDefaults.standard
        if let uuidString = defaults.string(forKey:"peripheralID"),
           let uuid = UUID(uuidString: uuidString),
           let peripheral = centralManager.retrievePeripherals(withIdentifiers: [uuid]).first {
            self.mainPeripheral = peripheral
        }
    }


    if let mainPeripheral = mainPeripheral 
        centralManager.connect(mainPeripheral, options: nil)
    } else {
        //TODO: Scan for peripheral.  Note that you can't use `services:nil` in the background
    }

}


func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
    print(peripheral)

    if peripheral.name == "DOPEY" {
        let defaults=UserDefaults.standard
        defaults.set(peripheral.identifier.uuidString,forKey:"peripheralID")
        peripheral.delegate = self    
        mainPeripheral = peripheral
        centralManager.connect(peripheral, options: nil)
        centralManager.stopScan()
    }    
}

func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
    peripheral.discoverServices([HM_10_ServiceCharacteristic])
}
...