Connect sometimes does nothing

Hello,


We currently experience issues with bluetooth reconnects. We had this issue since iOS 9, but it got way worse with iOS 10.

We have developed a BTLE Device which is intended to track a users car drives. We want our App to reconnect to the device as soon as it comes into range (again).


Short overview of what the btle part of the app does:

- Scan and bond with device

- Saves device identifier

- Talks with device until out of range

- // Everything works great until here

- Call BtCentralManager.connect() for device (retrieved via btCentralManager.retrievePeripherals)

- Wait for didConnect or didFailToConnect to proceed.


Everythings works great, but sometimes (1/5) a BTCentralManager.connect() does seem to timeout. We then never get a onDeviceConnect and the only chance to reconnect to our btle device is to restart the app (so it's not a hardware issue, also works perfect with android)


We do:

- Keep a strong reference to all peripherals we requested a connect

- Set the delegate of all peripherals to our singleton bluetooth manager

- Use our own queue on the central manager

- Have only one CBCentralObject app-wide

- Only connect with one device per time

- It makes no difference if the app is in background or foreground

- The first connect always works, but then it is total random when a following requests "dies"

- CentralManager delegate set correctly

- Our hardware does NOT use random addresses for itself

- Our hardware can handle ios random addresses


Most times it even connects when the connection request is multiple days old (over the weekend or so) and the app is in background.


Is there anything we can do to make this more stable? It's extremly frustrating for our customers to close the app everytime we are in this faulty state.



Here are the relevant part of our code if that helps:


// Reconnecting
devicesToConnect = btCentralManager.retrievePeripherals(withIdentifiers: deviceUUIDs)


// We always get the correct devices
for device in devicesToConnect {
  if device.state == .disconnected {
    device.delegate = self
    btCentralManager.connect(device, options: nil)
  } else {
    // Log device state
    // When this happens the device(s) are always in ".connecting" state
  }
}


Regards, Mike

Well, unfortunately it is almost impossible to get a reliable background reconnect on iOS. I have reported many bugs regarding that but so far none have been resolved.

In your case there are a few issues in particular that I think you should pay attention to:


1. Calling connectPeripheral: immediately in the didFailToConnect or didDisconnect can cause the bluetooth framework to get stuck in a bad state where the state property is set to “connecting” when a pending connection is in fact not set. To avoid this you should wait at least around 20ms before connectiong, for example using a dispatch_after or something.

2. State Preservation and Restoration will completely stop working if a Bluetooth-state-change event happens while your app is in the terminated state. This essentially means that if the bluetooth chip gets reset for any reason (ex by toggling bluetooth/flight mode/etc..) then your app will never be relaunched again by Core Bluetooth whenever the peripheral is within range. The reason for this is because all pending connections that have been set by your app will be cleared whenever the bluetooth chip is restarted. The problem with this is that your app will not be relaunched to be notified of this change, so the pending connections will never be recovered. So your app will think that the peripherals will connect, while in fact they will not.

3. Using an iPhone 7 and at the same time having an Apple Watch (paired the phone) will completely break all reconnects from behind the lock screen while the Watch is not currently connected. This *****! But it looks like the Apple Watch for some reason has "priority" over other bluetooth peripherals.

Of course there are many other issues, but these I would say are the most critical. Given that you say ”It makes no difference if the app is in background or foreground” then I would suggest perhaps looking at 1. But regardless of how good your code is you will always have issues with Core Bluetooth itself.

/Anton

Hi Anton,


thanks for sharing your knowledge. It sounds that 1. is indeed what i need to try.



For my next tests, i also unpair my Apple Watch. It's ridicoulus that this happens....


Mike

Hi Mike,


Did you apply the trick that Antome suggested? does it work?


Thanks,


Hien

Hi Mike,


any good news about this issue?


Thanks,


Hien

I'm experiencing similar behaviour. Especially when trying to connect to a BT device in the today extension (widget). The only way to fix it is restart the app or turn bluetooth off and on again. Is there other solution? Maybe a timer.. if .didconnect or .didfail is not called after 5 seconds restart BT programmatically?

Hey Stephand,


How can we restart BT programmatically?


Hien

You can't restart BT programmatically as far as I know.

Connect sometimes does nothing
 
 
Q