Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android save BLE device to reconnect after app close

I'm developing an android BLE app in which i try to establish a stable Connection between the app and a BLE device.

To achieve this i want my app to keep the BLE device data in shared preferences or somewhere.

After app close, i'd like my app to retrive this data and attemp a connection without scan for devices.

I prefer to avoid scanning every time becouse scan gives me a lot of problems and it takes time.

How can do it? Is there a way to save BLE data?

like image 884
L. Gangemi Avatar asked Apr 18 '17 15:04

L. Gangemi


2 Answers

You need to store the Bluetooth Device Address (AB:CD:EF:01:02:03) of the device in for example shared preferences or in a sqlite db. Then use https://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html#getRemoteDevice(java.lang.String) when you later restart the app to retrieve a BluetoothDevice object. Once you have the BluetoothDevice object you can use the connectGatt method as usual.

There are some undocumented things you need to keep in mind however. Due to some horrible design flaws in Android's BLE API there is no way to tell it if you mean the given address is a Public Address or a Random Address. (You can read more about different address types at https://devzone.nordicsemi.com/question/43670/how-to-distinguish-between-random-and-public-gap-addresses/). The getRemoteDevice method should take an additional parameter "random address/public address" but it doesn't. Without the correct address type, the Bluetooth controller cannot connect to the device.

Android's BLE stack has some internal heuristics to "guess" if the address is public or random, but unfortunately that differs between Android versions and also if you use autoConnect=true or false. However if you have bonded the device (https://developer.android.com/reference/android/bluetooth/BluetoothDevice.html#createBond()) then it will store in its internal DB whether the given address is public or random. If the peripheral you want to connect to uses a random resolvable address it can handle that as well if you use bonding. Therefore I strongly suggest to use bonding.

If you don't use bonding you will need to scan before you connect to the device, since when you start a scan and a device is detected, Android's BLE stack will temporarily (until next restart of Bluetooth) remember the address type for an address.

like image 146
Emil Avatar answered Nov 09 '22 20:11

Emil


I will continue on Emil's answer. Thanks @Emil for the 'big picture'.

  • Google API is flawed and you can't use getRemoteDevice() because it only understand 48bit address and do not know about all BLE address types.
  • You can't use Bonding if the device is dumb (anyone would be able to bond to it).

So your only solution is a Bluetooth scan.
However, since Android6 (Marshmallow) the user has to give location permission to apps using Bluetooth scanning. If you don't permit, it won't work.
So if you buy a Bluetooth thermometer (or heart-rate monitor or whatever), you have to permit the app to access location of your phone (or tablet). That's absurd!
@Emil call it a 'Google flaw'. You may also call it a 'Google machination'.

If I was a thermometer designer, I would add a push-button to accept bonding. It seems ridiculous because the button will only be used once.
[1]: https://www.polidea.com/blog/a-curious-relationship-android-ble-and-location/

like image 44
user3435121 Avatar answered Nov 09 '22 22:11

user3435121