21
votes

I am working on BLE Bluetooth scanning is working on all devices except the Android 10. Android 10 is not working, anyone please answer the question for the version 10 issues for scanning BLE Bluetooth

8
You don't provide any information in what way it fails. But if you target Android 10 then you need ACCESS_FINE_LOCATION to scan BLE. ACCESS_COARSE_LOCATION doesn't work anymore in Android 10.Emil
yes, i implemented all permission , the device is scan and get a address, but it could not connect ,IBluetoothGatt class is can not resolve is not work on connecting the device, in api 29 is only not workingraj.a
Then you should change your question since you say scanning woks but it is connect that fails. Include your code and the error messages.Emil
currently i get this errorD/BluetoothGatt: onClientConnectionState() - status=133 clientIf=8 device=88:BF:E4:95:55:51 D/BluetoothGatt: refresh() - device: 88:BF:E4:95:55:51 D/BluetoothGatt: close() D/BluetoothGatt: unregisterApp() - mClientIf=8 D/BluetoothGatt: connect() - device: 88:BF:E4:95:55:51, auto: false D/BluetoothGatt: registerApp() D/BluetoothGatt: registerApp() - UUID=af64bcfc-a9dc-40a9-994a-71b2ac16d5e0 D/BluetoothGatt: onClientRegistered() - status=0 clientIf=8raj.a
Android 10 is not working on BLE Bluetooth connection tittle i post the coderaj.a

8 Answers

26
votes

To make BLE scanning work on Android apps targeting Android 10 you need to ask the user for

ACCESS_BACKGROUND_LOCATION

along with ACCESS_FINE_LOCATION and also don't forget to add the permission in the manifest:

<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />

Here's the explanation why:

Android 10 (API level 29) introduces a number of features and behavior changes to better protect users' privacy. These changes extend the transparency and control that users have over their data and the capabilities they give to apps.

Your problem in short:

Access to device location in the background requires permission

To support the additional control that users have over an app's access to location information, Android 10 introduces the ACCESS_BACKGROUND_LOCATION permission.

Unlike the ACCESS_FINE_LOCATION and ACCESS_COARSE_LOCATION permissions, the ACCESS_BACKGROUND_LOCATION permission only affects an app's access to location when it runs in the background. An app is considered to be accessing location in the background unless one of the following conditions is satisfied:

An activity belonging to the app is visible. The app is running a foreground service that has declared a foreground service type of location.

To declare the foreground service type for a service in your app, set your app's targetSdkVersion or compileSdkVersion to 29 or higher. Learn more about how foreground services can continue user-initiated actions that require access to location.

Hope this fixes your problem :)

10
votes

You need to have location enabled to perform a BLE scan on android 10. To check if location is enabled and ask user to enable location service (Kotlin):

val lm = getSystemService(Context.LOCATION_SERVICE) as LocationManager
if (!LocationManagerCompat.isLocationEnabled(lm)) {
    // Start Location Settings Activity, you should explain to the user why he need to enable location before.
    startActivity(Intent(android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS))
}

LocationManagerCompat class is available in androidx.appcompat:appcompat:1.1.0 dependency, if you don't use androidx, you can use instead :

lm.isLocationEnabled()
7
votes

Adding the following permissions to AndroidManifest.xml is not enough

android.permission.ACCESS_FINE_LOCATION,  
android.permission.ACCESS_COARSE_LOCATION,  
android.permission.ACCESS_BACKGROUND_LOCATION. 

Add permissions to MainActivity such as

ActivityCompat.requestPermissions(
  this, 
  new String[] 
    {
      Manifest.permission.ACCESS_FINE_LOCATION, 
      Manifest.permission.ACCESS_COARSE_LOCATION, 
      Manifest.permission.ACCESS_BACKGROUND_LOCATION, 
      Manifest.permission.READ_EXTERNAL_STORAGE
  }, 0);
1
votes

For me it is working if i use fine permission in AndroidManifest. Switch on the location in Settings of the phone manually, and set app permission to location.

1
votes

try this

//gradle
dependencies {
implementation 'no.nordicsemi.android.support.v18:scanner:1.4.3'
}
//import
import no.nordicsemi.android.support.v18.scanner.BluetoothLeScannerCompat;
import no.nordicsemi.android.support.v18.scanner.ScanCallback;
import no.nordicsemi.android.support.v18.scanner.ScanResult;
import no.nordicsemi.android.support.v18.scanner.ScanSettings;
//init scan setting
final ScanSettings settings = new ScanSettings.Builder().setReportDelay(1000).setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY).build();
//start scan
scanner.startScan(null, settings, scanCallback);
//scan callback
private final ScanCallback scanCallback = new ScanCallback() {
        @Override
        public void onScanResult(final int callbackType, @NonNull final ScanResult result) {
            super.onScanResult(callbackType, result);
        }
        public void onBatchScanResults(@NonNull final List<ScanResult> results) {
            for (final ScanResult result : results) {
                //result.getDevice() is scanned device
            }
        }
        @Override
        public void onScanFailed(final int errorCode) {
            // should never be called
        }
    };
1
votes

I faced the same problem, and I have just fixed it using cordova-plugin-android-permissions.

Android 10 (SDK 29) requires ACCESS_FINE_LOCATION, while previous versions require only ACCESS_COARSE_LOCATION. (more info in this Android Developers page)

Unlike some other answers state, the ACCESS_BACKGROUD_LOCATION is not required. It's better not to require it unless you really need it. Play Store considers background location a dangerous permission, and will ask you to fill in some forms to justify why do you need it.

Old plugins would ask only ACCESS_COARSE_LOCATION permission, which was enough for Android 9 (SDK 28) and older versions. The best solution is to update the plugin. But if it is hard to do, there is an easy workaround.

Add cordova-plugin-android-permissions (npm link) to your project, and use it to ask ACCESS_FINE_LOCATION permission.

Add this code to your "device ready" function to check if your app already has this permission or not:

permissions = cordova.plugins.permissions;
permissions.checkPermission(permissions.ACCESS_FINE_LOCATION, checkPermissionSuccessCallback, checkPermissionErrorCallback);

And then create the following callback function to ask user permission:

function checkPermissionSuccessCallback(status) {
    if (status.hasPermission) {
        console.log("Permission OK");
    } else {
        console.log("Permission not OK");
        // ask user permission
        permissions.requestPermission(permissions.ACCESS_FINE_LOCATION, requestPermissionSuccessCallback, requestPermissionErrorCallback);
    }
}

You don't need to add anything to your "config.xml" to get this permission.

1
votes

I suppose in android 10 having just the location permission is not enough. Your location service should be turned on while you are scanning for your device. So, ask the user for turning on the location service if it is turned off.

Alternative Solution: You can use Companion device pairing for android 8 and higher. Mind you, In my opinion, it is not well documented, and it might be a bit unstable. For example, when I assigned a scan filter (BLE Service UUID) the Companion device pairing crashed, but without that filter, it worked.

0
votes

Try setting the callbackType to CALLBACK_TYPE_ALL_MATCHES, it solves the problem for me.

val scanSettings = ScanSettings.Builder()
scanSettings.setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
scanSettings.setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES)
scanSettings.setMatchMode(ScanSettings.MATCH_MODE_AGGRESSIVE)

val filter = ScanFilter.Builder()
filter.setServiceUuid(ParcelUuid(Service_UUID))
bluetooth.bluetoothLeScanner.startScan(mutableListOf<ScanFilter>(filter.build()), scanSettings.build(), callback)