didDiscoverPeripheral: not working sometimes on background - ios

Happens both on iOS 12 & iOS 13.
I have Bluetooth-central correctly added on my Info.plist
I'm specifying a list of service UUIDs
What I am seeing:
If I interact with our BLE device on the foreground, I can still scan for it on background, even hours and days later, as long as I don't turn off Bluetooth or restart the iOS device.
If I have never interacted with it while the app is open, or If I restart the device, or turn off Bluetooth on the device, then when scanning in the background, didDiscoverPeripheral: never gets called, until I open the app, which triggers didDiscoverPeripheral: instantly.
If I use retrievePeripheralsWithIdentifiers: and iOs can return the object "cached" then I can skip the scan and connect directly, which works perfectly. But sometimes retrievePeripheralsWithIdentifiers: doesn't return the object so I can't always relay on that (And forces the user to interact with our device on the foreground first)

So, after quite a bit of back and forth between me and our firmware team, we found the reason behind our problems.
Turns out, apps on background when scanning won't read the advertisement extended packet. The problem was, the service UUID we were using to filter the scan for our devices was only being sent on that advertisement extended packet.
For this reason, when the app was scanning a new device, it would not find anything with that service UUID, but once it had found it with the app open, it would cache it internally with its services, and from that point it would work even while on background (because it already knows what services that device has).
The fix was to include that service UUID on the first advertisement packet.

Related

How to deliver a BLE message to an iOS app that isn’t running?

I am working on a device that sends a message/signal to an iOS app via BLE. It currently works fine if the app is running in the foreground or background; however, I need the device to deliver this signal to the app when it isn’t running so it can process it, in essence, “waking it up.”
A device that seems to be doing this well is Tile (used to keep track of keys, etc.). The Tile can signal the phone even when the Tile app isn’t running, making the Tile app come up and sound an alarm. My use case isn’t the same, but I need to achieve the same behavior.
Does anyone have any pointers as to how to achieve this? The OS needs to launch/wake the app upon receiving this BLE message/signal from my device.

Bluetooth Background mode IOS

I was searching for my Bluetooth problem a few days but I did not find any useful solution. I would like reading advertising data more precisely manufacturing data from peripheral devices via ios application when it is in the background. In my case, the peripheral devices are Nordic nrf51822 chips and a central device is ios phone. I have successfully implemented the Bluetooth background mode and it works well on the ios device. The Event handler DiscoveredPeripheral is called when the new peripheral device is discovered. But the problem is that it is called only first-time the peripheral device becomes visible. If I turn off and on the peripheral device the DiscoverdPeripheral event is not called anymore. I know that this is ios restriction, but I do not know how can I handle this ios limitation. In the end, I would like that app in the background starts scanning for peripheral devices with specific UUID periodically, for example, every 10minutes. At this point, I would like to ask if this scenario is possible to implement in ios if so I appreciate for any help.
The Event handler DiscoveredPeripheral is called when the new peripheral device is discovered.
This isn't correct. It will only be called once per call to scanForPeripherals. When the device connects, you should stop scanning. When the device disconnects, which you should see as centralManager(_:didDisconnectPeripheral:error:), you can begin scanning again.
Even better, if you only want to reconnect to the same device, don't scan at all. Just call connect for that peripheral UUID. It will continue running while you're in the background and wake you up when the connect succeeds.
To push this further, implement Bluetooth State Restoration, which will allow you to automatically reconnect even after reboots.

Connect to a backgrounded iOS app acting as a peripheral from a macOS app

I have an iOS and macOS app that make heavy use of Core Bluetooth. The core functionality of the app involves having a central device (CBCentralManager) connect to a peripheral device (CBPeripheralManager), retrieve some data, then disconnect. Either device, whether macOS or iOS can act as either a central or peripheral depending on who needs the data.
At first I thought there was an issue with my code, but after testing the app with two iOS devices, one is able to connect and extract data from the peripheral device even when the peripheral device is locked and the app is in the background. Now according to the docs concerning background advertising on iOS under "The bluetooth-peripheral Background Execution Mode" this is kind of expected:
...they can be discovered only by an iOS device that is explicitly scanning for them.
Is there any way to have a macOS app discover peripherals even when they're backgrounded? I'm sure the code I've written is correct because it's the same across iOS and macOS.
Update 1
I believe that this might be possible just unsure how to approach the issue. Using Apple's Bluetooth Explorer on macOS, I am able to find the desired device AND I'm able to see and read data for my custom service.
This finding is validated from logs from my iOS device about the read requests which are from my peripheralManager(CBPeripheralManager, didReceiveRead: CBATTRequest).

IOS Developpement : Background BLE scanning

I'm currently trying to develop a Background Bluetooth related app, and I'm having some trouble scanning in background.
I followed the entire Apple IOS Bluetooth Background tutorial, but I cant figure out why scanning doesn't work in background (my info.plist is correctly set up to manage BLE Background tasks, both central and peripheral).
What I've tested so far :
1 - When my two devices are in range and in foreground, scanning works well.
2 - When the peripheral is in background, and the central comes active in foreground, scanning also works, peripheral is well detected.
Here comes the troubles
3 - first I launch my peripheral device, and I put the app in the background. Then on the peripheral device, I power off the bluetooth, I launch the app, I put it in background, and I power on the bluetooth.
In my code, the -(void)centralManagerDidUpdateState:(CBCentralManager *)central calls the scan [centralmgr scanForPeripheralsWithServices:[NSArray arrayWithObject:servicesUUID] options:scanOptions];, function which works perfectly in the foreground. But nothing happened, the peripheral is never detected by the central.
4 - I launch the central, bluetooth activated, and I put it in background. Then I took my peripheral device, I went out of the bluetooth range (in the specific case I went to my supermarket to buy some beers to drown my sorrow), I launch it there -also bluetooth activated- I put it in background and I came back in the proximity of my peripheral. Once again nothing happened, the centrals did not detect the peripheral.
Furthermore, after the cases 3 and 4, if I just put the central on the foreground (the peripheral stays in background), detection restart, without doing anything else. As if the scan was successfully triggered in the case 4, but waiting the app to come active to actually start detecting other devices.
Does somebody have an idea on how to proceed/overcome the problem?
Thank you!
Ps: I appologize for my English, I'm a bit rusty
Hi for details you can see this answer
but the short answer is one of your Apps must be in Foreground to connect to each other
Either your central device or the peripheral
Reason: for central you an only scan with providing the service UUIDs of the peripheral
and in background a peripheral cannot adverise its UUIDs
so even they are there they just don't know of each others presence
Moreover some more notable things about background scanning are
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.
See Apple Docs

retrieveConnectedPeripheralsWithServices and retrievePeripheralsWithIdentifiers return an empty array

I have two apps running one on OSX and one on iOS. A bluetooth connection is established between them using the CoreBluetooth framework, and support for background capabilities for the iOS app has been added. This is working perfectly fine, and communication with the iOS app in the background still works even after a while in the background.
However, when the iOS device goes out of range, I have to use retrievePeripheralsWithIdentifiers to re-connect when the device is back in range since the app is in the Background and therefore I cannot scan for it as its UUID would not be advertised (as mentioned in Core Bluetooth Background Processing for iOS Apps). I tried using retrieveConnectedPeripheralsWithServices with the iOS app in the foreground to figure what the problem is, but the function is always returning an empty array, although the connection is already established. For the former case, I am passing my custom service CBUUID object as specified in the documentation:
let connectedPeripherals = centralManager!.retrieveConnectedPeripheralsWithServices([CBUUID(string: "109F17E4-EF68-43FC-957D-502BB0EFCF46")])
Trying to get the peripheral to re-connect to the OSX app while it's in the background, using
let peripherals = centralManager!.retrievePeripheralsWithIdentifiers([NSUUID(UUIDString: "109F17E4-EF68-43FC-957D-502BB0EFCF46")!])
as per the documentation also yields an empty array. Also to mention that I tried this function with the iOS app in the foreground but also to no avail.
Any idea what could possibly be going wrong here?

Resources