We need in our project to detect the proximity of an iPhone that is running a custom APP that is using Bluetooth LE.
The detector (Scanner, Central...) will be implemented using a BLE Integrated Circuit (from Texas or Nordic). I mean that the scanner is not another IOS device... running Core Bluetooth as a Central..
For the detector to guess the proximity, the idea is very simple, just advertise a service with an UUID proprietary.
While in foreground all works OK, and the UUID and a Local name are advertised (The UUID in the main advertise packet, and the Local Name in the SCAN Response packet....), and our scanner is able to decide if this iOS device is running our App.
The problem arises when going to background .....
The iOS stops broadcasting UUID and Local Name. (As the documentation of Core Bluetooth Explains... I Know...)
At this moment (Background), IOS begin to broadcast a SPECIAL MANUFACTURER DATA in the main advertise packet, and nothing in the SCAN Response packet)
The data packet we see using a Bluetooth Sniffer is :
0x14 (length of packet not including this byte).
0xFF (Manufacturer specific data AD Type).
And then :
0x4C, 0x00 (this data is the manufacturer identifier, if the packet is compliant with BLE 4.0 specification).
0x01, 0x00,0x00, 0x00, 0x00,0x00,0x80, and ten 0x00 more....
I know Apple says that while in background ONLY ANOTHER IOS DEVICE SEARCHING FOR A SPECIFIC SERVICE CAN DISCOVER IT. (Really I do not know how they can achieve that, unless they connect to the peripheral and retrieve the services, or if the peripheral knows about other IOS device is scanning because of it´s Address in the SCAN REQUEST and then changes the advertisement data in background).
The main questions are :
Is there any documentation or knowledge of what this manufacturer data means....Perhaps it would be possible to the scanner to know based on this info that this is an iOS device advertising in background and then connect to look if the custom service is there. (Not a quick and clean solution...but I do not see any other workaround....)
Does anybody worked with this scenario...and found a clean solution .....
I have heard from people that forces the application not to go to background.
This limitation, will stop a lot of possible projects.
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.
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?
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.
I have MFi device which uses BLE for control and Classic Bluetooth for audio streaming.
In the App, i use coreBluetooth framework to scan BLE and EAAccessory framework to scan Classic Bluetooth.
I don't want the BLE of target device to be connected if its Classic Bluetooth is not yet connected. So i need to know which EAAccessory is corresponding to target CBPeripheral.
I am familiar with coreBluetooth, there is UUID string to identify the CBPeripheral. But it looks not exist in EAAccessory.
I have an idea but not sure: maybe firmware side can config EAAccessory's serial number and CBPeripheral's manufacture data in advertisement data with the same
serial number, so that App side can check if they are the same.
Dose anyone knows the general way to implement this in App side and firmware side?
I really do not think there is s relationship between the 2. BT and BTLE are managed by different chip at peripheral side and phone side.
Usually in BT you use the MAC address to identify the peripheral on BTLE side the MAC address is not used anymore since iOS at the first connection give its own identifier to the peripheral.
What you can do is probably at firmware side, by exposing a service with a characteristic that somehow relate the 2.
UPDATE AFTER COMMENT
I see, as far as I know there a best practice doesn't exist.The worst part is that you have to handle connections differently, mostly due to how connection are made on iOS side. While on the BLE you can choose a not encrypted connection that would not require paring or bonding, on BT side I guess that bonding is required.
Probably the most simple flow would be, user bond the BT device. Once you are in the app and detect the connected BT device, use a scan method for detect BLE companion device by filtering for a specific service id that your device exposes, once you do that you can also filter discoveries using BLE name without still making a connection.
Adv packet are restricted in size (29 usable byte) but you can also use the scan response (31 byte), that exposes some additional properties such as manufacturer data that will be exposed in a dictionary (kCBAdvDataManufacturerData).
Once you know that is the correct device you can start a connection, that does not require pair or bond but is NOT encrypted (Pair and Bond will require the user to accept the connection inside your app).
I'm trying to use an iOS BLE device as BLE peripheral which also advertises in background.
I already figured out how to advertise in background and got it detected by another device looking for the specific bluetooth UUDID.
Unfortunately the advertiser-info is not transmitted when the app is in background. Is there a way to send a short string or something else device specific when the app is in background? It would be ok if the app would be woken up for a short period (if this is possible).
The advertised services are removed from the advertisement packages when the app is backgrounded. Only foreground scanning iOS devices will be able to obtain the services.
The advertised services are arbitrary UUIDs. You can easily figure out some encoding to store characters in them. However, this has several caveats, like
the general scheme is usually that the scanner finds your peripheral by the service UUIDS. If the data can be anything, then this is tricky.
the peripheral will not be able to change the advertisement data while backgrounded.
I suggest you not try to trick around with the system. Rather plan for connecting to the peripheral for a short time and sending the data to the central during this interval.
I'm developing an iOS app with an accompanying Bluetooth LE peripheral. The one step I don't seem to be able to solve is how to actually transmit the data from my app to the peripheral or vice versa.
What I've built so far is a test app that can connect to my sample Bluetooth peripheral, and read all of its services/characteristics/descriptors. It can toggle notifications for a given characteristic, and write to given characteristics. It is just this last step of "transmit n bytes to the peripheral, and receive m bytes from the peripheral" that I can't seem to figure out.
Looking at the External Accessory Framework (what I would use if Apple would actually give me MFi approval for this project), they give you input and output streams on a given session to communicate with the accessory, but no such object exists for CoreBluetooth.
Is this simply an oversight on Apple's part on the functionality of CoreBluetooth? Or do I simply need to develop my own Bluetooth service profile to handle the inflow/outflow of data to and from the peripheral?
LE is fundamentally designed to work with these GATT based profiles, which are suited for monitoring sensors, not for data streams. While LE does allow for additional L2CAP streams to be opened for custom protocols, Apple's CoreBluetooth doesn't provide access to do so.
You can build a custom profile with private services and characteristics and have it work kind of like SSP; that's the way I'm using my BLE module to get data from some sensors to my app. The module I bought (Microchip's RN-4020) already has a custom profile made specifically for this known as MLDP (Microchip Low-energy Data Profile).
The way I get the data in my iOS app is by subscribing to the private characteristic, thus being notified when the values are updated. So far it has been working great, and the data rate can go up to 20 kbps according to Microchip (I haven't tested its limits, since I don't need much speed). Here's a link to Microchip's product page: http://www.microchip.com/wwwproducts/Devices.aspx?product=RN4020
Good luck!
You can use the bluetooth.org 'Immediate Alert Service' uuid=1802 with characteristic uuid=2A06 with property=write_no_response to send one byte values to your peripheral device from your iPhone. The peripheral device must be programmed to act on the data that is sent. For example, you might use a button on an iPhone app to send a hex address that causes one or more port pins to turn on or off on the peripheral. While this is not using the Alert Service as it was intended, it does provide an easy way to test out data transfer to a peripheral device. The same process could be used to send sequential data bytes similar to a serial data stream. I have not yet tried sending more complex data streams. The write_no_response does not provide any feedback to the app as to whether the data was received by the peripheral.
The IOS TemperatureSensor.xproj is an example of code for reading temperature data from a peripheral. The OSX HealthThermometerClient.xproj has the code needed to decode the somewhat complex thermometer data structure. The IOS TI-BLE-Demo.xproj TIBLECBKeyfob.m has code for reading and writing characteristic values, such as, reading temperature or battery levels from a peripheral device.