I'm looking to create a BLE Beacon which does not follow Apples iBeacon specification. The reason being that the "beacon" will be an arduino device which the app should also be able to communicate to to instruct it to do things. Is this supported on iOS? I've heard rumours of iOS 8 locking down on generic device advertising via Bluetooth.
Thanks in advance.
Yes, you can do this using the CoreBluetooth APIs, but there are a few restrictions depending on what type of Bluetooth LE advertisement you use.
1. Manufacturer Advertisement
You can read all the bytes of the manufacturer advertisement (up to 24 bytes) using CoreBluetooth, but only when an app is in the foreground. In the background, you will get no callbacks. This is often paired with a second iBeacon advertisement that wakes the app up in the background on iOS. For an example of this type of advertisement, see the AltBeacon specification.
2. GATT Service Advertisement
A GATT service advertisement detection will be sent to an app by CoreBluetooth even when the app is in the background, provided that the app is specifically looking for the GATT service UUID of the beacon. The disadvantage of this approach is that the data payload is generally limited to only 18 bytes after the 2-byte service UUID.
Other Details
In the case of both advertisement types, you can connect to the device using GATT, and read and write data. Note, however, that once you connect the device will generally stop advertising as a beacon.
Both of the above work as described with iOS 8. It's hard to predict the future, but it seems unlikely that Apple will lock down on the above two use cases as they are widely used for Bluetooth LE applications aside from Beacons.
You can see the basic steps to read these advertisements in this blog post. While the post is specifically about how Apple filters out iBeacon advertisements, if you make your own custom manufacturer advertisement, it will allow you to read the bytes as described in the post.
For the sake of completeness, both of the advertisement types above can be picked up by Android devices both in the foreground and the background.
Related
I work on iOS application which is using BLE for communication with our custom made BLE unit.
We want to send specific commands via BLE to the unit automatically.
When user is near unit and specific criteria are met, the app should connect to the unit, "login" the user, send command via BLE and disconnect right away.
These specific criteria are based on manufacturer data from advertisement (i.e. the unit is in "available to login" state when manufacturer data has last byte 0x01, when it's "NOT available to login", last byte is 0x00).
In foreground, this mechanism works flawlessly.
We want to do this even when app is in background or terminated (swipe up in dashboard on iPhone).
The mechanism we have implemented:
the unit has capability of acting as iBeacon
when unit is NOT available for login, the iBeacon is OFF
when it IS available for login, the iBeacon will turn ON and wakes up application, upon that the BLE scan will start in background mode
background mode setting is bluetooth-central
Problem here is that no matter what I tried, the advertisement:
sometimes it's not discovered at all (looks like it's timing issue?)
when it's discovered, it does NOT contain manufacturer data
Did anyone come across something similar?
Any help is appreciated and have a nice day!
An app simply cannot read raw BLE manufacturer advertisement data when in the background on iOS -- the operating system prohibits it.
Two exceptions to this rule:
iBeacon, which itself is implemented as a specific type of manufacturer advertisement. An app can detect iBeacons in the background on iOS, although only four bytes of readable data (encoded in the major and minor fields) are fully usable. If you can modify your device to send information this way, it will do what you want. However you must use CoreLocation APIs to detect iBeacon, as CoreBluetooth does not allow reading manufacturer data from iBeacon advertisements. If you do use CoreLocation, you cannot use the detections to establish a Bluetooth connection with CoreBluetooth as the two APIs are sandboxed.
Overflow Area advertisements. Backgrounded iOS apps can read these special types of manufacturer advertisements when in the background but only if the screen is turned on. (It is often possible to force the screen on at specific times by sending a local notification.) See my blog post here for more info: http://www.davidgyoungtech.com/2020/05/07/hacking-the-overflow-area
An alternative to detecting manufacturer advertisements is to use BLE Service advertisements with attached data. For this to work, you'd need to define a 16 bit or 128 bit GATT Service UUID and send out an advert with attached data bytes. Eddystone beacon formats work this way, and allow detection in the background on iOS. This is probably the best approach if you can alter the BLE hardware.
I need my app to act as a BLE beacon, even when it is in the background.
I've already made the beacon part - works fine when I'm using the app.
The problem is I've never made anything run in the background before, and not sure what the limitations are - if I will be allowed to let the app act as a beacon in the background.
Was wondering if this is possible or not (both technically, as well according to App Store rules)
Is this technically possible ? Can my app act as a beacon, even when the app is not in the foreground.
Is it within App Store rules ?
Unfortunately, iOS apps cannot emit iBeacon advertisements unless they are in the foreground. If you program your app to advertise iBeacon frames, as soon as the screen turns off or the app is not visible, iOS changes the advertising format to a special generic background advertisement that does not match the iBeacon format.
This proprietary background advertisement is useless for identification of a device. It is designed for connection to BLE GATT services from other iOS devices. Unless you want to advertise a connectable BLE GATT service to other iOS devices this advertisement has little value. EDIT: There is a way to make use of this advertisement. See below.
Apple's documentation describes this limitation here in the section titled "The bluetooth-peripheral Background Execution Mode":
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.
If all apps that are advertising are in the background, the frequency at which your peripheral device sends advertising packets may decrease.
It may not be obvious that the above causes iBeacon transmissions to break, but I assure you that is absolutely a consequence.
Read my blog post here for more information on how to put useful beacon data into this background "Overflow Area" advertisement.
We are developing an app which needs to scan for beacons in the background. This requires us for iOS to specify a service UUID while scanning. See Apple documentation:
Apps that have specified the bluetooth-central background mode are allowed to scan while in the background. That said, they must explicitly scan for one or more services by specifying them in the serviceUUIDs parameter. The CBCentralManagerOptionShowPowerAlertKey scan option is ignored while scanning in the background.
We are using a Raspberry Pi with a bluetooth adapter to send a beacon signal (conforming the AltBeacon spec). Unfortunately we are not able to find out how the service UUID should be set in the BLE Advertising PDU, is it part of the Bluetooth specification or part of the Manufacturer specific data structure? We did find examples for setting the service UUID for when you use an iOS device as beacon, but since we are using a generic bluetooth adapter we cannot use that.
Could anyone clarify us how and where the service UUID should be set in the beacon transmission?
is it part of the Bluetooth specification or part of the Manufacturer specific data structure?
the later.
generally when you setting the advertising parameters, you can set the UUID(or name, tx power, etc) to it.
I work on iOS application with acts as Bluetooth peripheral. I need to implement a searching for my iOS peripheral from non iOS centrals. I’m faced with a problem while my iOS application advertising in background mode. When it is advertising in foreground, my central can read primary service UUID from advertising data, but when it is advertising in background, I can’t see the name or the UUID of peripheral – there is only Apple manufacturer data in advertising packet.
The essence of the problem lies in the fact that my non iOS central can’t determinate – is it advertising my peripheral in background or any other peripheral in background. I have to connect every iOS device with advertising in background, enumerate its services to look for my service UUID.
The documentation says that during background advertising all service UUIDs go to special “overflow” area and only iOS devices can read it specifying service in CBCentralManager’s scanForPeripherialWithServices method. It looks like Apple have an ability to check background advertising packet data for service UUID.
After searching on SO I found some interesting information about service hashed UUID. Background mode advertising packet always contains Apple manufacturer data (14 FF 4c 00 01) and undocumented 128 bit value, where one of these 128 bits equals 1. I tried to change my service UUID several times and found out than this 128 bit value after Apple manufacturer data changes too.
I’d like to use this value to filter peripherals around and reduce
connections to wrong (not mine) peripherals. Can anyone give any
information how this value depends on service UUID? Is there any
hash function that is used on specified service UUID in
scanForPeripherialWithServices method?
Can I be sure that the background advertising packet will always be the same for the immutable service UUID which will never change?
Is there any other way to send my custom information while
advertising in background mode? Maybe I can add my data into BLE
SCAN RESPONSE packet?
Best Regards,
Dezmond
I'd like to ask whether it is possible to access the raw advertisement data from a custom BLE device built using a Raspberry Pi from the Core Bluetooth API?
The use case is to broadcast constantly changed data from the Raspberry Pi to multiple iOS devices in the proximity and consume them in an iOS app. See the topology description in this article.
I already found out that the iBeacon advertisements are filtered out from the Core Bluetooth API and are only accessible from the Core Location API only, which requires the knowledge of the UUID. Due to the constantly changed data a custom iBeacon wouldn't work for this particular use case anyway. But I am unsure whether I could achieve that with Core Bluetooth?
You can do what you want if you change the Raspberry Pi to transmit a non-iBeacon format. CoreBluetooth only filters out the raw bytes of advertisements if they are iBeacon advertisements. See here: Obtaining Bluetooth LE scan response data with iOS
A simple solution is to change your iBeacon advertisement to an open-source AltBeacon advertisement. CoreLocation will no longer pick it up, but CoreBluetooth will.
Here's an example of what you get in the advertisementData NSDictionary in the CoreBluetooth centralManager:didDiscoverPeripheral:advertisementData:RSSI: callback. This example is the result of detecting an AltBeacon advertisement (an open-source beacon standard), with identifiers 2F234454-CF6D-4A0F-ADF2-F4911BA9FFA6 1 2:
{
kCBAdvDataIsConnectable = 0;
kCBAdvDataManufacturerData = <1801beac 2f234454 cf6d4a0f adf2f491 1ba9ffa6 00010002 be00>;
}
You can see how to decode the above bytes by looking at the AltBeacon spec here. Note that the above are the actual contents of the NSDictionary for a detected advertisement on iOS8 that were printed to the console using an NSLog statement.
Quick answer is "there is no direct way".
Why:
Because CoreBluetooth filters out advertisement data, except kCBAdvDataServiceUUIDs, kCBAdvDataLocalName, so there is now way to pass custom data from peripheral to central via advertising.
How can we workaround:
Peripheral
1) Holds some custom service (let's name it 'BeaconService').
2) BeaconService contains Beacon's UUID, major, minor characteristics.
3) Advertises BeaconService UUID (via kCBAdvDataServiceUUIDs key).
Central
1) Scans for peripherals that have BeaconService UUID.
2) Found peripherals are queued.
3) Connection is opened to queued peripherals, and the iBeacon information is read from BeaconService.
4) Read values can be used to start CoreLocation beacon monitoring/ranging.
So by this way you can make bridge from CoreBluetooth to CoreLocation.