2

Here is my scenario:

I connect with two peripherals, put my app in the background mode and begin getting away with peripherals until they lost connection to my app. When coming back, they are not connecting again when in reach.

When I perform the same experiment when app is running in the foreground, no issues occurred - coming with peripherals closer to iPhone results in reconnecting.

However, I see in the console that when peripherals are losing connection, the DidDisconnectPeripheral method is being called. The problem is that scanning is not called inside this method

func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) {
    numberOfTagsSending = numberOfTagsSending - 1
    numberOfConnectedTags = numberOfConnectedTags - 1
    print("Tag was disconnected. Start scanning.")

    synchronizer.alreadySynced = false

    central.scanForPeripherals(withServices: arrayOfServices, options: [CBCentralManagerScanOptionAllowDuplicatesKey : true])
}

I read this answer and did everything exactly the same way, unfortunately it does not work.

Thanks in advance

Community
  • 1
  • 1
theDC
  • 6,364
  • 10
  • 56
  • 98
  • Did you try calling this function in `Application: didEnterBackground`? – KSigWyatt Oct 13 '16 at 15:25
  • Well, to be honest I did not. But I've never found any information that I should explicitly call it from AppDelegate – theDC Oct 13 '16 at 15:27
  • Try that and see if it works in the background, If not then it has to be some issue with your `central.scanForPeripherals()` method is not setup properly as you indicated in your question. – KSigWyatt Oct 13 '16 at 15:29
  • @KSigWyatt this is not working either – theDC Oct 13 '16 at 15:34
  • there is no need to scan. Simply call `connect` in `didDisconnectPeripheral` and iOS will automatically reconnect to the peripheral when it is visible again. What object is holding your CBCentralManager instance? Is it a singleton? – Paulw11 Oct 13 '16 at 19:56
  • Yes it is a singleton. Well I'm not sure if it's visible in background mode, is it? – theDC Oct 13 '16 at 20:40
  • @Paulw11 Now I understood that your point of view changes my approach of dealing with lost peripherals. If I understand it right, having a fixed number of peripherals, I can only call connect anytime a peripheral goes missing, there's no need need to scan at all unless I want to connect some new peripheral, do I get it right? – theDC Oct 13 '16 at 20:47
  • That's right. Once you have a `CBPeripheral` instance you can connect to it, even if that instance is the peripheral that was passed to `didDisconnect`. You can also store the peripheral identifier string in, say, userDefaults and then use this with `retrievePerioheralsWithIdentifiers` when your app runs again to avoid scanning in that instance too. – Paulw11 Oct 13 '16 at 21:11
  • @Paulw11 I will try this approach tomorrow (left hardware in the office) and get back to you with results, thanks a lot. If it works, I think it would be good to post it as answer to this question, which I will gladly accept :) – theDC Oct 13 '16 at 21:15
  • @Paulw11 Worked like magic, please answer the question, it is going to be extremely informative for all those who deal with BLE on iOS – theDC Oct 14 '16 at 07:14

1 Answers1

4

Once you have a CBPeripheral instance you don't need to discover it again. You can simply connect to it; if the peripheral isn't currently in range then iOS will automatically connect once the peripheral comes into range and will call your didConnectPeripheral delegate method.

func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) {
    numberOfTagsSending = numberOfTagsSending - 1
    numberOfConnectedTags = numberOfConnectedTags - 1

    central.connect(peripheral)
}
Paulw11
  • 108,386
  • 14
  • 159
  • 186