Halvtysk
Halvtysk

Reputation: 317

Understanding the different BLE modes for communication

I'm working with app development for a HW-driven device company. Our current (BLE) HW-devices communicates with the phone, and when the HW is considered "active" (triggered by a physical activation on the HW), the phone retrieves continuous data from said HW.

In order for the application to be ready for the HW to become active, it is holding a permanent "binding" to the HW. On Android, the application holds a permanent ("sticky") notification, that prevents the app from being killed, and lets the background process stay alive at all times and listens for the HW to announce that it is active. On iOS, I believe that the HW is spamming "ping-requests" to the app in order to keep it alive.

All in all, the setup works, but is not ideal. I've tried to wrap my head around the different "peripheral modes" and master/slave-setups, but have yet to understand how to setup a relationship between phone and HW that behaves as we would like:

We would like to have the HW to behave like (for instance) BT-headphones work, i.e. when I open the case for my headphones, the application starts up (in the case of my earplugs, a battery status notification is shown) and communication starts. When I put the plugs back in the case, the application closes (at least as far as the user can tell). Once the HW is in range again and is activated (i.e. equivalent to opening the case) the app/communication is ready/resumed.

Is the described functionality reserved for headphones only, or is this a setup that can be achieved by any BLE-device?

tl;dr I don't want to have a persistent notification on Android to make sure that the app is always ready when the device is "active", but without it, the app is easily killed in the background.

Upvotes: 0

Views: 401

Answers (1)

Paulw11
Paulw11

Reputation: 115041

It is tricky when you ask a question that covers both Android and iOS as both platforms will have different approaches.

I will answer for iOS as that is what I know, but I presume there is something similar on Android.

First, a little on how the BLE GATT service works in simple terms;

In BLE there are two roles; central and peripheral. 99% of the time, the peripheral advertises services and the central discovers peripherals advertising the services it is interested in. The central can then connect to the peripheral.

Once connected, the central can initiate reads from and writes to the peripheral. The central can also register for notifications from the peripheral. This allows the peripheral to send new data when it has it, rather than waiting until the central reads it.

Now, for how you can use all of this in iOS Core Bluetooth.

Your initial task is to discover the peripheral you are interested in. You do this by scanning for a peripheral advertising your specific service. You typically need to provide some sort of UI to show what has been discovered and allow the user to select the device to which they want to connect, but this depends on your specific use case.

Once you have discovered (and the user has selected) a peripheral, you can store the identifier that Core Bluetooth provides. This is a unique value for this peripheral on this iOS device; It is not the peripheral MAC address and it cannot be used on a different iOS device to identify the same peripheral.

In future you can use this identifier to try and retrieve a CBPeripheral object from Core Bluetooth without needing to scan for it.

Once you have a CBPeripheral you can issue a connect. Once the connect completes you can read/write data or register for notifications.

If you have enabled Core Bluetooth background mode in your app then the connect and notification events will be delivered to your app even when it is in the background. You can also issue read and write commands in the background in response to the connect and notification events, although you only have a few seconds execution time.

At some point it is likely that the peripheral will go out of range/be turned off and the connection will disconnect. Again, this event may be delivered in the background or foreground.

In response your app should immediately issue a new connect. If the device is not currently available then this connect will be pending and will complete when/if the peripheral is seen again. iOS will deliver this to your app in the foreground or background.

The final point to consider is the case where your app is not currently in the suspended state; Perhaps the iOS device has been rebooted or your app has been offloaded from memory by iOS because it hasn't been active for some time.

Your app can opt in to Core Bluetooth State Restoration by providing a n identifier parameter when it creates its CBCentralManager. This will relaunch your app.

On relaunch you need to re-establish your CBCentralManager with the same identifier and then you will receive the connect callback that triggered your apps relaunch. From this point you can proceed normally.

This is an article from Apple that, while old, explains Core Bluetooth background and state restoration pretty well.

Note that all of this can happen without pairing/bonding. If your peripheral requires encryption for any of its attributes then iOS will automatically present a pairing dialog the first time you connect. Once this pairing is in place it is not required again. Pairing/bonding only exchanges keys for encryption. It is not explicitly required to allow future connections.

Upvotes: 1

Related Questions