don / cordova-plugin-ble-central

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

Android SDK 29 vs 28 issues #754

Closed GimpMaster closed 3 years ago

GimpMaster commented 4 years ago

I'm having an issue when I target Android SDK 29. Essentially everything LOOKS good. Permissions are all valid, etc.

Calling bluetoothAdapter.startLeScan(this); returns true.

However onLeScan is never called.

If I change the gradle settings to:

minSdkVersion = 21
compileSdkVersion = 28
targetSdkVersion = 28

with no other changes then onLeScan gets called as expected.

I've tried this on Pixel 2, Pixel 3, and Pixel 3a.

Any thoughts?

davidleal31 commented 4 years ago

Try to turn on location and check if you have ACCESS_BACKGROUND_LOCATION permission.

GimpMaster commented 4 years ago

Thank you for your response @davidleal31 . Unfortunately that did not work for us.

Are you currently using API 29 for targetSdkVersion?

davidleal31 commented 4 years ago

Yes targetSdk 29 and work with ble-central and bluetoothle scan. I had the same issue and scan works after these changes. There is a difference between our code, i used ble.scanWithOptions(). Good luck

RoopeHakulinen commented 4 years ago

I'm having the exactly same issue with SDK level 29. Once I go back to 28 everything works normally. The location permission modal looks a bit different if built with level 29 which might be a hint of some kind. Also adding the ACCESS_BACKGROUND_LOCATION makes no difference and I am using the scanWithOptions too. Odd, will continue to look into it.

GimpMaster commented 4 years ago

I wonder if the deprecated code was upgraded for scanning if that is the ultimate solution

RoopeHakulinen commented 4 years ago

I was just reviewing what has changed from 28 to 29 and one of the changes is that you now need ACCESS_FINE_LOCATION instead of ACCESS_COARSE_LOCATION for startLeScan/startScan. Going to try that first thing tomorrow. Seems promising.

GimpMaster commented 4 years ago

I tried both at the same time. Not sure if that makes a difference.

davidleal31 commented 4 years ago

Here is a part of my AndroidManifest.xml :

After some test cases : It works on my GS9/Android10 (only with location/GPS turn ON). But now BLE devices are not found on older Android version (GS4 and J3 2016).

RoopeHakulinen commented 4 years ago

Thanks for the information. Below is what I found out today..

Problem

  1. Androids older than 10 with compile/target SDK level 29 the scanning seems to be working (tested with Android 8.0 device). This is likely because on that Android level there is no need for the ACCESS_BACKGROUND_LOCATION. The important bit here is that user is allowed to choose any of the three options (picture below): allow on background, allow only when running foreground and don't allow.
  1. Android 10 with compile/target SDK level 29: I tested with ACCESS_FINE_LOCATION & ACCESS_BACKGROUND_LOCATION in my manifest on my Pixel 3 with Android 10 and that doesn't work out of the box. The problem is the same as above where you simply don't get any results but there are no errors whatsoever and I think this is due to the modal looking as above.

This modal is caused by this line in this plugin:

PermissionHelper.requestPermission(this, REQUEST_ACCESS_COARSE_LOCATION, ACCESS_COARSE_LOCATION);

which clearly is not asking for the background location. Thus, the wrong dialog in Android 10 (SDK level 29).

Solution

But, not to worry. I got this all to work.

First, a manual way to quickly try this is go to app settings and enable the background location access by yourself as follows:

Second, the proper way to handle this is to change the code in the plugin to be:

String[] permissions = { ACCESS_FINE_LOCATION, ACCESS_BACKGROUND_LOCATION };
PermissionHelper.requestPermissions(this, REQUEST_ACCESS_COARSE_LOCATION, permissions);

with this the modal changes to look like this:

Now, obviously this would need to be changed into this plugin so that we'd ask for the right permissions in the first place.

Here's a SO answer about the problem that pointed me to the right track.

Caveat

There's a bit of a caveat unfortunately. If user chooses the wrong option (allow when app is running) the scanning won't work at all. Android's documentation basically tells us to instruct users to not choose it or if already selected, change it manually. Highly inconvenient to be honest.

Next steps

I'm not quite sure how this should be implemented to keep the plugin working with old Android SDK versions but I'm sure there's a way to do that too. Maybe it is necessary to change the logic to be like

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
    if (!PermissionHelper.hasPermission(this, ACCESS_FINE_LOCATION) || !PermissionHelper.hasPermission(this, ACCESS_BACKGROUND_LOCATION)) {
        // save info so we can call this method again after permissions are granted
        permissionCallback = callbackContext;
        this.serviceUUIDs = serviceUUIDs;
        this.scanSeconds = scanSeconds;
        string[] permissions = { ACCESS_FINE_LOCATION, ACCESS_BACKGROUND_LOCATION };
        PermissionHelper.requestPermissions(this, REQUEST_ACCESS_LOCATIONS, permissions);
        return;
    }
} else {
    if (!PermissionHelper.hasPermission(this, ACCESS_COARSE_LOCATION)) {
        // save info so we can call this method again after permissions are granted
        permissionCallback = callbackContext;
        this.serviceUUIDs = serviceUUIDs;
        this.scanSeconds = scanSeconds;
        PermissionHelper.requestPermission(this, REQUEST_ACCESS_COARSE_LOCATION, ACCESS_COARSE_LOCATION);
        return;
    }
}

@don would it be possible to get your input on this. I'm happy to make a PR if you are not up for it. Just need to know which way is the right one going forward.

Side note

I don't think the use-features should matter there as my understanding is that they are only for Play store to know which features are needed/used by the app?

GimpMaster commented 4 years ago

This is great research @RoopeHakulinen . Nice work. Eagerly awaiting a PR or @don to work some magic on this plugin.

dev1181 commented 4 years ago

@don please make confirm above note and provide solution. all android 10 device BLE doesn't work at all.

GimpMaster commented 4 years ago

Any updates on this? Do you need a PR to continue @don ?

manumazu commented 3 years ago

Hi, I'm a phonegap developer, and on my Huawei phone, after an upgrade to Android 10 + Emui 10, i had to enabled "location services" to make cordova BLECentralPlugin scan working again. This parameter did not exist in previous version, and it seems to be a Huawei's specific user condition, it was not easy to find it. Highly inconvenient and not user friendly.

don commented 3 years ago

@GimpMaster thanks for the info, @tiagoblackcode thanks for the PR.

I need RTFM and figure out some details. FINE location permissions aren't great I but I can live with that. I really don't want to always enable background scanning if it can be avoided. IMO background permissions should be explicitly enabled only when you need it.

tiagoblackcode commented 3 years ago

@don Glad to help!

I totally agree with you that permissions should only be requested as needed, but unfortunately it seems like it's the case for a continuous scan on Android 10.

According to @jrobeson in #771 there's the Companion Device Manager API which does not require access to FINE location permissions however it does not perform a continuous scan.

What we can do, as suggested in https://github.com/don/cordova-plugin-ble-central/pull/771#issuecomment-645909092, is to add a new option to the startScanWithOptions() method (or a new method altogether) that will use the Companion Device Manager API for a one-off scan a thus not request FINE location permissions.

I'd imagine the option being something like {continuous: false} or, if a method is more desirable, e.g. performScan() and performScanWithOptions() with the same signature as the corresponding startScan ones.

smartyw commented 3 years ago

I see @don assigned this issue to himself on June 22nd. Hi @don, it would be really useful to know what the outlook and timeline was for this issue. Google requires a change to target SDK level 29 by 2nd November so the question is whether a new release of the plugin will be available in good time to meet this deadline or whether people like should me should implement a workaround (there's some talk here of using GPS - I don't favour this) or fork the repo and implement something which is fit for purpose myself.

Thanks in anticipation.

giowild commented 3 years ago

Hi all, since you are experts about BLE, ionic and Background, I have the following issue:

https://github.com/don/cordova-plugin-ble-central/issues/850

Any advise or pointer would be greatly appreciated, thanks a lot!