iOS Background BLE advertising not detectable by Android
Asked Answered
L

1

9

When an iOS BLE peripheral enters the background state, the advertising packets are not emitted in the regular manner and they are placed in a special “overflow” area which is only detectable by another iOS device explicitly looking for this device.

The bluetooth-peripheral Background Execution Mode

That said, you should be aware that advertising while your app is in the background operates differently than when your app is in the foreground. In particular, when your app is advertising while in the background:

• The CBAdvertisementDataLocalNameKey advertisement key is ignored, and the local name of peripheral is not advertised.

• All service UUIDs contained in the value of the CBAdvertisementDataServiceUUIDsKey advertisement key are placed in a special “overflow” area; they can be discovered only by an iOS device that is explicitly scanning for them.

Is there any way an Android central (scanner) can detect any advertised custom UUID without having to connect to the iOS peripheral?

Lozoya answered 14/11, 2019 at 19:47 Comment(14)
Were you able to find a way for Android devices to be able to detect iOS devices when the iOS app is in the background ?Plume
Specifically - if an iOS app is acting as a peripheral, and is in the background, and an Android app has never connected to it before, can an Android app detect the iOS peripheral based on a service UUID ?Plume
@KaizerSozay nope. The only work around could be to... queue every other iOS device -> connect -> look for your serviceUUID -> if present, then do your thing -> disconnect. Yes, this is slow and not asynchronous as opposed to just reading the advertisement packets without connecting, but it's the only work around I know as of now.Lozoya
Sorry - I don’t fully understand: are you saying an Android device can not detect an iOS device whose app is in the background?Plume
An Android central (scanner) will be able to detect an iOS peripheral (advertiser) that's in the background state, but will not be able to read any custom serviceUUID without connecting to it. You can tell that it's an Apple device by reading the manufacturer ID - look for Apple.Lozoya
Thanks - do you have any link / sample code for this? It seems like an android device will have to scan for all peripherals and then filter based on the manufacturer id, and then try and connect....and then check for service & characteristic ids - meaning it may detect iOS devices which do not have the app installed, and only after connecting be able to determine if it has the service you are looking for...Plume
Yes that's correct! You can try using this Blessed Library - but you'd have to write the queuing and connection logic by yourself based on your requirements / conditions.Lozoya
If you have a simple example of code for android, where the only thing it does is scan for and connect to an iOS device (where the iOS app is in the background, and the Android app is in the background), can you share it please?Plume
You can't write a generic code which will work for every case. You'd have to define your own UUIDs, scanning / advertising conditions & settings. Please go through the Android & iOS BLE docs, you can easily implement it once you've clearly defined your use case and requirements. Also, Apple & Google have teamed up in efforts to use BLE for contact tracing the COVID-19 pandemic. We may see some changes in the core BLE stacks for better cross platform inter-operability.Lozoya
Actually that’s the whole problem - can’t find a single code sample where they scan for all UUIDs rather than a specific set of uuids...Plume
Just perform a non-filtered scan and then manually look through each and every scanResult for your custom serviceUUID. If you can't find it here, then check if it's an Apple device and queue it for connecting (what we discussed above).Lozoya
Do you have an example for that one line of code?Plume
Unfortunately, it's not one line. You'll have to set your scanFilter and settings so that it scans for and returns every other peripheral to the callback method. Inside which you can implement the following... List<ParcelUuid> UUIDs = scanResult.getScanRecord().getServiceUuids(); if (UUIDs != null) { // Check for your custom serviceUUID here and if not found check if Apple device and queue it up for connection. } Note, this process is asynchronous. The connections need to be synchronous. There is a lot more! Please explore the docs you'll figure it out.Lozoya
Thanks. I’ve been exploring the docs, and it seems like it would save a lot of time to just ask someone who knows. While normally I would take the time to pour through the docs myself, having access to some code right now would be invaluable right now, and possibly help a lot of people. If you happen to have a spare moment and anything to share, it could really help a lot of people.Plume
B
1

With "overflow" area I guess they mean Scan Response Data. To get that data, a device must perform an active scan, rather than a passive scan. In an active scan, the scanner sends a scan request packet immediately after it detects an advertisement packet. The advertising device will only broadcast the scan response data if it detected a scan request.

Android devices only perform active scans, so you should be fine.

EDIT: the answer above is not correct. See http://www.davidgyoungtech.com/2020/05/07/hacking-the-overflow-area for correct information.

Borszcz answered 4/4, 2020 at 8:2 Comment(15)
Ok, so what is a passive/active scan on android and iOS? What does apple mean by overflow? Can both iOS and android devices see the iOS peripherals by doing "active scan" in background?Arrow
An iOS central (scanner) can detect an iOS peripheral (advertiser) that's either in the background or foreground state by mentioning the serviceUUID it's looking for in the instance method scanForPeripherals (). So you don't have to worry about the iOS scanner doing an active or passive scan.Lozoya
However, that's not the case with an Android central (scanner). Even if it only does active scans, when the iOS peripheral (advertiser) is in the background state, there is no trace of the custom serviceUUID in the Android scanner's scanResult callback. It does not detect the custom serviceUUID even if explicitly mentioned in the Android scanner's scanFilter.Lozoya
@FilipLuchianenco the 'overflow area' is a section of the BLE advertising packet emitted by an iOS peripheral (advertiser) that cannot be read or detected by any device, other than an iOS central (scanner) that's explicitly looking for it - using the serviceUUID as mentioned in my initial comment.Lozoya
I found at least some investigation here: github.com/crownstone/bluenet-ios-basic-localization/blob/….Borszcz
thank you so much guys for these invaluable insights. So to summarize: when app is in background, iOS devices will be able to see other iOS and android devices, android devices will only be able to see other Android devices and won't be able to see iOS devices. Is that right?Arrow
@Borszcz yes. So basically it is not possible to decipher the advertisement packets (more specifically the overflow area data) emitted by an iOS peripheral (advertiser) that's in the background state.Lozoya
@FilipLuchianenco it depends on what your definition of "see" is here. You will be able to detect any device in any state - but when it comes to reading a custom serviceUUID without connecting to the peripheral, you cannot do so if the peripheral (advertiser) is an iOS device in the background state and the central (scanner) is a non-iOS device.Lozoya
Thank you and I believe this fully answers the question now. Can you please summarize everything in one answer so I can accept it?Arrow
@AhimsaDas can you please summarize in an answer?Arrow
@Borszcz maybe you can summarize everything so it helps others understand the limitations/challenges. Thank youArrow
@FilipLuchianenco in all honesty this doesn't answer the question. It only elaborates on the question better. Apparently, there seems to be no way to detect a custom serviceUUID without connecting to an iOS peripheral (advertiser) that's in the background state - which actually happens to be my question lol.Lozoya
Why don't you just perform a non-filtered scan on Android and dump the whole raw scan record? Then it will be pretty clear if there is any data there (encoded in some proprietary format or not) containing the service uuid. Otherwise you have to connect and perform a service discovery.Borszcz
@Borszcz Yes that's exactly what we just discussed. Performing a non-filtered scan and simply printing out the scanResult shows some extra encoded data which cannot be deciphered / decrypted. Which is why connection seems to be the only work around.Lozoya
How large is the extra data? Is it big enough to contain a 16 byte random uuid?Borszcz

© 2022 - 2024 — McMap. All rights reserved.