don / cordova-plugin-ble-central

Bluetooth Low Energy (BLE) Central plugin for Apache Cordova (aka PhoneGap)
Apache License 2.0
941 stars 601 forks source link

iOS background scan not working #984

Closed linkitapps closed 9 months ago

linkitapps commented 9 months ago

iOS background scan not working.

https://github.com/don/cordova-plugin-ble-central#background-scanning-and-notifications-on-ios

I followed the link above, but the background scan doesn't work on my iPhone.

The iOS version is 16.6.

Is there any solution?

peitschie commented 9 months ago

Hi @linkitapps

Seems interesting.

I have an iOS 16 device coming my way soon (I don't have one currently) so will give this a shot when I have one available to me.

What's the exact steps you're testing here with the system? Also, are you able to paste the start scan command you're using here?

linkitapps commented 9 months ago

thank you for the reply. It works fine in the foreground, but not in the background. The scan command I used is as follows:

window.ble.startScanWithOptions(["FEF5"], {"reportDuplicates": true}, function(device) {
    console.log(device);
});

And the background-related settings in the info.plist file are as follows.

<key>UIBackgroundModes</key>
<array>
    <string>bluetooth-central</string>
    <string>location</string>
    <string>nearby-interaction</string>
    <string>processing</string>
    <string>audio</string>
</array>
peitschie commented 9 months ago

Are you starting the app and then sending it to the background?

How are you confirming that the scanning is not working in the background? Is this via console logs, or some other mechanism?

linkitapps commented 9 months ago

Yes I am using console.log .

First, I set the scan to be performed periodically, once every 2 minutes, using setInterval.

Then, run the app in the foreground while connecting the MacBook and iPhone via USB.

Through the developer tool console of safari, it was confirmed that the log for the scanned device is well displayed on the console.

In this state, the app has been switched to the background. After some time, the console will not show any scanned devices.

At this time, if you switch the app back to the foreground and wait, the scanned device will be displayed in the console.

Through this test, I thought that scanning worked well in the foreground and not scanning in the background.

peitschie commented 9 months ago

Ah. There's possibly a bit of confusion going on there πŸ™‚

At a high level, iOS will pause the app in the background... always, irrespective of those settings.

What happens though is that if you start a Bluetooth scan before your app is put into the background, the scan will continue to function. iOS will then wake up your app on occasion to respond to Bluetooth-related things. Exactly when the app gets woken up is something the OS itself decides... you have few guarantees about this.

The correct way to implement background scanning on iOS is to launch a long-running scan with no timeout (this is safe to do forever... iOS doesn't really penalise you much for this). Then, when your app is pushed to the background and paused, if a new device appears in the scan, your app will be woken up for a short time (usually about 10s) to process things before being put back to sleep again.

Additionally, you need iOS background state restore to be active (via --variable BLUETOOTH_RESTORE_STATE=true) so that if iOS ever terminates your app due to memory pressure or power saving, it re-instantiates it correctly and resumes the long-running scan you started.

When I'm testing background scanning, I generally use a Bluetooth peripheral/device that I can see the connection status on (e.g., via an indicator light or some kind of log). I'll usually wait for the console logs to stop reporting and then bring the BLE device into range. iOS logs will show the app waking up and starting to process things again for about 10s before being put back to sleep again.

Note the caveats for when background scanning will not be resumed as per https://developer.apple.com/library/archive/qa/qa1962/_index.html

I'd definitely suggest a really close read of https://developer.apple.com/library/archive/documentation/NetworkingInternetWeb/Conceptual/CoreBluetooth_concepts/CoreBluetoothBackgroundProcessingForIOSApps/PerformingTasksWhileYourAppIsInTheBackground.html#//apple_ref/doc/uid/TP40013257-CH7-SW13 πŸ™‚

linkitapps commented 9 months ago

Ah. There's possibly a bit of confusion going on there πŸ™‚

At a high level, iOS will pause the app in the background... always, irrespective of those settings.

What happens though is that if you start a Bluetooth scan before your app is put into the background, the scan will continue to function. iOS will then wake up your app on occasion to respond to Bluetooth-related things. Exactly when the app gets woken up is something the OS itself decides... you have few guarantees about this.

The correct way to implement background scanning on iOS is to launch a long-running scan with no timeout (this is safe to do forever... iOS doesn't really penalise you much for this). Then, when your app is pushed to the background and paused, if a new device appears in the scan, your app will be woken up for a short time (usually about 10s) to process things before being put back to sleep again.

Additionally, you need iOS background state restore to be active (via --variable BLUETOOTH_RESTORE_STATE=true) so that if iOS ever terminates your app due to memory pressure or power saving, it re-instantiates it correctly and resumes the long-running scan you started.

When I'm testing background scanning, I generally use a Bluetooth peripheral/device that I can see the connection status on (e.g., via an indicator light or some kind of log). I'll usually wait for the console logs to stop reporting and then bring the BLE device into range. iOS logs will show the app waking up and starting to process things again for about 10s before being put back to sleep again.

Note the caveats for when background scanning will not be resumed as per https://developer.apple.com/library/archive/qa/qa1962/_index.html

I'd definitely suggest a really close read of https://developer.apple.com/library/archive/documentation/NetworkingInternetWeb/Conceptual/CoreBluetooth_concepts/CoreBluetoothBackgroundProcessingForIOSApps/PerformingTasksWhileYourAppIsInTheBackground.html#//apple_ref/doc/uid/TP40013257-CH7-SW13 πŸ™‚

Thank you for your reply. I'll try to fix it and try again. thank you

linkitapps commented 9 months ago

Ah. There's possibly a bit of confusion going on there πŸ™‚

At a high level, iOS will pause the app in the background... always, irrespective of those settings.

What happens though is that if you start a Bluetooth scan before your app is put into the background, the scan will continue to function. iOS will then wake up your app on occasion to respond to Bluetooth-related things. Exactly when the app gets woken up is something the OS itself decides... you have few guarantees about this.

The correct way to implement background scanning on iOS is to launch a long-running scan with no timeout (this is safe to do forever... iOS doesn't really penalise you much for this). Then, when your app is pushed to the background and paused, if a new device appears in the scan, your app will be woken up for a short time (usually about 10s) to process things before being put back to sleep again.

Additionally, you need iOS background state restore to be active (via --variable BLUETOOTH_RESTORE_STATE=true) so that if iOS ever terminates your app due to memory pressure or power saving, it re-instantiates it correctly and resumes the long-running scan you started.

When I'm testing background scanning, I generally use a Bluetooth peripheral/device that I can see the connection status on (e.g., via an indicator light or some kind of log). I'll usually wait for the console logs to stop reporting and then bring the BLE device into range. iOS logs will show the app waking up and starting to process things again for about 10s before being put back to sleep again.

Note the caveats for when background scanning will not be resumed as per https://developer.apple.com/library/archive/qa/qa1962/_index.html

I'd definitely suggest a really close read of https://developer.apple.com/library/archive/documentation/NetworkingInternetWeb/Conceptual/CoreBluetooth_concepts/CoreBluetoothBackgroundProcessingForIOSApps/PerformingTasksWhileYourAppIsInTheBackground.html#//apple_ref/doc/uid/TP40013257-CH7-SW13 πŸ™‚

As you said, the scan continued without stopping.

Scan works fine when the app is minimized by clicking the Home button. Scan didn't work before applying the method you suggested. thank you

However, when the screen is off, Scan does not work.

For reference, even in this situation, other operations such as displaying certain values ​​in console.log or making API calls in the app work fine. Only ble scan is not allowed.

Is there a way to scan even when the screen is off?

thank you

peitschie commented 9 months ago

Only ble scan is not allowed.

Is there some kind of error being reported here, or is it simply that no devices are being found?

If the scan was started before the screen turned off, it ought to continue. I wouldn't be surprised to have scan reporting throttled while the screen is off in order to conserve power, but I still expect occasional reports.

linkitapps commented 9 months ago

Only ble scan is not allowed.

Is there some kind of error being reported here, or is it simply that no devices are being found?

If the scan was started before the screen turned off, it ought to continue. I wouldn't be surprised to have scan reporting throttled while the screen is off in order to conserve power, but I still expect occasional reports.

I got the test wrong. sorry. It works well even when the screen is off. Thanks again for letting me know how.

To be more precise, when the scan works well, if you turn off the screen, the scan will not work for about 30 seconds. I saw this phenomenon and said that scan does not work when the screen is off.

After about 30 seconds, the scan works well even when the screen is off. However, it seems that the scan is executed less frequently than when the screen is not off.

In the way you told me, scan is working well regardless of whether the screen is off in the background. thank you

peitschie commented 9 months ago

Fantastic news @linkitapps . Glad you were able to get to the bottom of this πŸ™‚

The "less frequently" part is one of the bits documented by Apple:

Although you can perform many Bluetooth-related tasks while your app is in the background, keep in mind that scanning for peripherals while your app is in the background operates differently than when your app is in the foreground. In particular, when your app is scanning for device while in the background: ...

  • If all apps that are scanning for peripherals are in the background, the interval at which your central device scans for advertising packets increases. As a result, it may take longer to discover an advertising peripheral.

So it sounds like you've got the solution working as well as possible. Nice job πŸ™‚

I'll close this issue, but feel free to re-open it or raise a new issue if you encounter any further problems.