I'm using @capacitor-community/bluetooth-le to connect my Ionic 6 APP to a specific BLE device. In Android everything works fine. In iOS, first time connects to BLE successfully but next times (after pairing) gives the following error when try to connects: "Failed to encrypt the connection, the connection has timed out unexpectedly."
I have been tried a lot of different approachs: connects after scan. Connects when is scanning. But nothing works. What is strange is in first time everything works fine (after pairing).
Any help?
CodePudding user response:
Unfortunately this is kind of a known issue in iOS. What I think is happening is that because you have already paired/bonded with the device at the OS level, the connection is being re-established at the OS level when the remote BLE device is discoverable. When you are attempting to reconnect to the remote device from your app, a connection is already in place at the OS level which is why it is failing at the app level. Alternatively, maybe the stored keys from the bonding process is causing the rebonding/pairing process to clash. You can confirm the issue by doing the following:-
- Go to the iOS settings, Bluetooth, then unpair the device if it exists.
- Attempt to reconnect to the device from your iOS app.
- Disconnect the device from your iOS app (do not unpair from the Bluetooth settings this time).
- Try to connect to the remote device from your Android app (or any other device that you can use apart from the iOS device). If the connection doesn't succeed, it means that the iOS device is still connected to the remote device.
- If the connection succeeds from the Android device, try to disconnect and reconnect from the iOS device. If the connection succeeds, you'll know that the issue is with the OS level connection, and if the connection doesn't succeed, you'll know that the issue is with the stored bonding/pairing keys clashing.
As for the solution, I don't think there's a simple and straight-forward one unfortunately. Below is one suggested solution which I found useful in the past (you may need to modify this for your ionic app):-
In some cases, like for HID devices, once a peripheral is bonded, iOS will automatically connect to it whenever it sees the peripheral advertising. This behavior occurs independently of any app, and a peripheral can be connected to an iOS device, but not connected to the app that originally established the bond. If a bonded peripheral disconnects from an iOS device and then reconnects at the iOS level, the app will need to retrieve the peripheral object (retrieveConnectedPeripherals(with[Services/Identifiers]:) and explicitly connect again through a CBCentralManager to establish an app-level connection. To retrieve your device with this method, you must specify either the Apple-assigned device identifier from the previously-returned CBPeripheral object or at least one service it contains.
iOS does not allow developer apps to clear a peripheral’s bonding status from the cache. To clear a bond, the user must go to the Bluetooth section of iOS Settings and explicitly “Forget” the peripheral. It may be helpful to include this information in your app’s UI if it’ll affect user experience, as most users will not know this.
You can find more information about this in the links below:-
- The ultimate guide to Apple's CoreBluetooth
- CoreBluetooth iOS pairing issue
- CoreBluetooth pairing/forgetting
- Unable to reconnect after cancelling BLE peripheral
CodePudding user response:
In my case after iPhone pairs with peripheral, never connects anymore. What is strange, in my iPhone 6s with iOS 15.5 everythings works fine.
The pugin has this code (it's possible to some is wrong?)
https://github.com/capacitor-community/bluetooth-le/blob/main/ios/Plugin/Plugin.swift
let CONNECTION_TIMEOUT: Double = 10
let DEFAULT_TIMEOUT: Double = 5
@objc func connect(_ call: CAPPluginCall) {
guard self.getDeviceManager(call) != nil else { return }
guard let device = self.getDevice(call, checkConnection: false) else { return }
let timeout = self.getTimeout(call, defaultTimeout: CONNECTION_TIMEOUT)
device.setOnConnected(timeout, {(success, message) -> Void in
if success {
// only resolve after service discovery
call.resolve()
} else {
call.reject(message)
}
})
self.deviceManager?.setOnDisconnected(device, {(_, _) -> Void in
let key = "disconnected|\(device.getId())"
self.notifyListeners(key, data: nil)
})
self.deviceManager?.connect(device, timeout, {(success, message) -> Void in
if success {
log("Connected to peripheral. Waiting for service discovery.")
} else {
call.reject(message)
}
})
}
I already tried another plugins, and the result is the same.