chipweinberger / flutter_blue_plus

Flutter plugin for connecting and communicationg with Bluetooth Low Energy devices, on Android, iOS, macOS
Other
726 stars 442 forks source link

[Help]: Handling Android limiting 5 scans in 30 seconds #956

Closed jasaw closed 1 month ago

jasaw commented 1 month ago

Requirements

Have you checked this problem on the example app?

No

FlutterBluePlus Version

1.32.11

Flutter Version

3.22.2

What OS?

Android

OS Version

14

Bluetooth Module

Nordic nRF

What is your problem?

I've been looking into why sometimes my scans don't return any results and found this undocumented "feature". https://github.com/NordicSemiconductor/Android-Scanner-Compat-Library/issues/18 https://blog.classycode.com/undocumented-android-7-ble-behavior-changes-d1a9bd87d983 Also reported as #666

I've tested and can confirm this behavior on Android 14.

From the logs, when scan is working normally, we get onScannerRegistered() - status=0 scannerId=11 mScannerId=0 but when it hits the limit, we get onScannerRegistered() - status=6 scannerId=-1 mScannerId=0.

Question is, is there any plan to implement a scan wrapper to workaround this restriction? For example, have FBP enforce a 6 second minimum scan duration. If app calls stop scan before reaching minimum scan duration, FBP starts a timer to stop the scan at the end of the 6 seconds. During this time, received advertisement packets are discarded. If the app restarts advertisement before the 6 seconds expires, then just cancel the timer and resume scanning. If the current scan session has been running for 5 minutes, do not enforce the 6 second minimum duration so Android doesn't turn the scan into opportunistic scan (another Android "feature").

Logs

I/flutter (20275): 0:02:22.988055   W   BleDevice:   *** scan attempt 1
D/[FBP-Android](20275): [FBP] onMethodCall: startScan
D/BluetoothAdapter(20275): getBleEnabledArray(): ON
D/BluetoothAdapter(20275): getBleEnabledArray(): ON
D/BluetoothAdapter(20275): semIsBleEnabled(): ON
D/BluetoothAdapter(20275): getBleEnabledArray(): ON
D/BluetoothLeScanner(20275): Start Scan with callback
D/BluetoothLeScanner(20275): onScannerRegistered() - status=0 scannerId=11 mScannerId=0
W/[FBP-Android](20275): [FBP] *** onScanResult
D/[FBP-Android](20275): [FBP] onMethodCall: stopScan
D/BluetoothAdapter(20275): getBleEnabledArray(): ON
D/BluetoothAdapter(20275): getBleEnabledArray(): ON
D/BluetoothLeScanner(20275): Stop Scan with callback
I/flutter (20275): 0:02:23.106579   W   BleDevice:   *** scan attempt 2
D/[FBP-Android](20275): [FBP] onMethodCall: startScan
D/BluetoothAdapter(20275): getBleEnabledArray(): ON
D/BluetoothAdapter(20275): getBleEnabledArray(): ON
D/BluetoothAdapter(20275): semIsBleEnabled(): ON
D/BluetoothAdapter(20275): getBleEnabledArray(): ON
D/BluetoothLeScanner(20275): Start Scan with callback
D/BluetoothLeScanner(20275): onScannerRegistered() - status=0 scannerId=11 mScannerId=0
W/[FBP-Android](20275): [FBP] *** onScanResult
D/[FBP-Android](20275): [FBP] onMethodCall: stopScan
D/BluetoothAdapter(20275): getBleEnabledArray(): ON
D/BluetoothAdapter(20275): getBleEnabledArray(): ON
D/BluetoothLeScanner(20275): Stop Scan with callback
I/flutter (20275): 0:02:23.235624   W   BleDevice:   *** scan attempt 3
D/[FBP-Android](20275): [FBP] onMethodCall: startScan
D/BluetoothAdapter(20275): getBleEnabledArray(): ON
D/BluetoothAdapter(20275): getBleEnabledArray(): ON
D/BluetoothAdapter(20275): semIsBleEnabled(): ON
D/BluetoothAdapter(20275): getBleEnabledArray(): ON
D/BluetoothLeScanner(20275): Start Scan with callback
D/BluetoothLeScanner(20275): onScannerRegistered() - status=0 scannerId=11 mScannerId=0
W/[FBP-Android](20275): [FBP] *** onScanResult
W/[FBP-Android](20275): [FBP] *** onScanResult
W/[FBP-Android](20275): [FBP] *** onScanResult
W/[FBP-Android](20275): [FBP] *** onScanResult
D/[FBP-Android](20275): [FBP] onMethodCall: stopScan
D/BluetoothAdapter(20275): getBleEnabledArray(): ON
D/BluetoothAdapter(20275): getBleEnabledArray(): ON
D/BluetoothLeScanner(20275): Stop Scan with callback
W/[FBP-Android](20275): [FBP] *** onScanResult
W/[FBP-Android](20275): [FBP] *** onScanResult
I/flutter (20275): 0:02:23.367853   W   BleDevice:   *** scan attempt 4
D/[FBP-Android](20275): [FBP] onMethodCall: startScan
D/BluetoothAdapter(20275): getBleEnabledArray(): ON
D/BluetoothAdapter(20275): getBleEnabledArray(): ON
D/BluetoothAdapter(20275): semIsBleEnabled(): ON
D/BluetoothAdapter(20275): getBleEnabledArray(): ON
D/BluetoothLeScanner(20275): Start Scan with callback
D/BluetoothLeScanner(20275): onScannerRegistered() - status=0 scannerId=11 mScannerId=0
D/[FBP-Android](20275): [FBP] onMethodCall: stopScan
D/BluetoothAdapter(20275): getBleEnabledArray(): ON
D/BluetoothAdapter(20275): getBleEnabledArray(): ON
D/BluetoothLeScanner(20275): Stop Scan with callback
I/flutter (20275): 0:02:23.405971   W   BleDevice:   *** scan attempt 5
D/[FBP-Android](20275): [FBP] onMethodCall: startScan
D/BluetoothAdapter(20275): getBleEnabledArray(): ON
D/BluetoothAdapter(20275): getBleEnabledArray(): ON
D/BluetoothAdapter(20275): semIsBleEnabled(): ON
D/BluetoothAdapter(20275): getBleEnabledArray(): ON
D/BluetoothLeScanner(20275): Start Scan with callback
D/BluetoothLeScanner(20275): onScannerRegistered() - status=0 scannerId=11 mScannerId=0
W/[FBP-Android](20275): [FBP] *** onScanResult
D/[FBP-Android](20275): [FBP] onMethodCall: stopScan
D/BluetoothAdapter(20275): getBleEnabledArray(): ON
D/BluetoothAdapter(20275): getBleEnabledArray(): ON
D/BluetoothLeScanner(20275): Stop Scan with callback
I/flutter (20275): 0:02:23.479250   W   BleDevice:   *** scan attempt 6
D/[FBP-Android](20275): [FBP] onMethodCall: startScan
D/BluetoothAdapter(20275): getBleEnabledArray(): ON
D/BluetoothAdapter(20275): getBleEnabledArray(): ON
D/BluetoothAdapter(20275): semIsBleEnabled(): ON
D/BluetoothAdapter(20275): getBleEnabledArray(): ON
D/BluetoothLeScanner(20275): Start Scan with callback
D/BluetoothLeScanner(20275): onScannerRegistered() - status=6 scannerId=-1 mScannerId=0
chipweinberger commented 1 month ago

i dont like your proposed fix

but perhaps we should log a warning

or throw an exception

jasaw commented 1 month ago

After implementing this workaround in my own app, I admit that this workaround should be app specific because the app needs to manage the scan filter.

A warning from FBP would be nice. Not sure whether there's a native API or callback to get this limit state. If there's no native API, we could record the scan start time in an array of 5 entries and print a warning if the current scan time against the oldest scan time is less than 30 seconds. System.nanoTime() in Java is a monotonic clock, so we could use this as the source of time.

chipweinberger commented 1 month ago

if you want to implement that pr, do it

but it's not so important. maybe let's just improve the docs