BluetoothLeScanner.startScan with Android 6.0 does not discover devices

22,599

Solution 1

if permissions granted, have a try: turn ON the GPS.

Solution 2

Is you app prompting for Location permission on startup? If it's not, handle the code somewhere else so that it is being prompted.

Also you can check this to test if your app is working fine:

Open Settings > Apps > YourApplication > Permissions and enable Location and then try to scan for results.

Location will be listed under permissions only if you have provided ACCESS_COARSE_LOCATION on manifest.

Solution 3

Using the solutions provided above works but the side effect is that you have to have location services turned on for something that doesn't need it. An ugly and unsatisfying work around is to specify the target version in your manifest to

android:targetSdkVersion="21"

It allows scanning on my Nexus 7 even though the installed version is 6.0.1. I do not know what the side effects are of targeting a lower version than the installed version but at least scanning works. Might be the only solution for GPS-less devices (if such devices exist).

Google should be crucified for this.

Share:
22,599

Related videos on Youtube

Jacopo Tosi
Author by

Jacopo Tosi

Updated on July 09, 2022

Comments

  • Jacopo Tosi
    Jacopo Tosi almost 2 years

    I'm trying to use the function BluatoothLeScanner.startScan instead of the deprecated one BluetoothAdapter.startLeScan. Yesterday I updated my Nexus 5 to Android 6.0 and since that moment my app does not work anymore. I firstly add the preferences required ACCESS_COARSE_LOCATION as found here, https://developer.android.com/about/versions/marshmallow/android-6.0-changes.html#behavior-hardware-id. Then I added the permission as described here: https://developer.android.com/training/permissions/requesting.html. But at the end it seems not working, it does not send back the ble devices.

    This is my code:

    manifest

    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
              package="com.stm.sensitronapp">
              <uses-sdk android:maxSdkVersion="23"/>
              <uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/>
    
              <uses-permission android:name="android.permission.BLUETOOTH"/>
              <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
              <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>`
    

    DeviceScanActivity

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    ...
    
    if (ContextCompat.checkSelfPermission(this,Manifest.permission.ACCESS_COARSE_LOCATION)
                != PackageManager.PERMISSION_GRANTED){
            if (ActivityCompat.shouldShowRequestPermissionRationale(this,
                    Manifest.permission.ACCESS_COARSE_LOCATION)) {
            } else {
                ActivityCompat.requestPermissions(this,
                        new String[]{Manifest.permission.ACCESS_COARSE_LOCATION},
                        MY_PERMISSIONS_REQUEST_ACCESS_COARSE);
            }
        }
    
    // Device scan callback.
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            if (ContextCompat.checkSelfPermission(this,Manifest.permission.ACCESS_COARSE_LOCATION)
                    == PackageManager.PERMISSION_GRANTED) {
                mScanCallback = new ScanCallback() {
                    @Override
                    public void onScanResult(int callbackType, ScanResult result) {
                        super.onScanResult(callbackType, result);
                        mLeDeviceListAdapter.addDevice(result.getDevice());
                        mLeDeviceListAdapter.notifyDataSetChanged();
                    }
                };
            }
        } 
    }
    final BluetoothManager bluetoothManager =
                (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
    mBluetoothAdapter = bluetoothManager.getAdapter();
    
    if (mBluetoothAdapter.getState() == BluetoothAdapter.STATE_ON) {
            mSwipeRefreshLayout.setRefreshing(true);
            mLeDeviceListAdapter.clear();
            mBluetoothLeScanner = mBluetoothAdapter.getBluetoothLeScanner();
            if(ContextCompat.checkSelfPermission(this,
                        Manifest.permission.ACCESS_COARSE_LOCATION ) == PackageManager.PERMISSION_GRANTED) {
                    mBluetoothLeScanner.startScan(mScanCallback);
                }
            }
    

    EDIT: to solve this problem I only turned on the GPS. It is easy to do it programmatically in this way.

    • Matt Wolfe
      Matt Wolfe over 8 years
      I have the same issue. Have you found any workarounds? I'm thinking of trying the new scanning api but it's a pain to keep compatibility between both since they work so much differently.
    • Jacopo Tosi
      Jacopo Tosi over 8 years
      Yes, look here, there is the solution: Bluetooth Low Energy startScan on Android 6.0 does not find devices However, the solution is: add permissions in the manifest, add permissions at runTime in the activity with the ScanDevice, turn ON the GPS. Is incredible to think but my problem was the GPS off
    • Matt Wolfe
      Matt Wolfe over 8 years
      I just tested with GPS turned on and it worked (I was on a tablet which had it off).. This is crazy that we must have GPS turned on in order to scan for BLE devices, what if the device doesn't even have a GPS chip in it? A bug needs to get filed immediately. I would think the fitbit guys and others making BLE devices for the masses would have hit google with these questions already.
    • Lars Blumberg
      Lars Blumberg over 8 years
      WTF, enabling GPS on Android 6.0 makes the scanner finding BLE devices. Now I understand why the permission ACCESS_COARSE_LOCATION is required. Google, WTF?!?
    • BjornW
      BjornW about 5 years
      4 years later and still the same problem with GPS...
    • J. Ouwehand
      J. Ouwehand over 2 years
      In my case disabling battery optimization for the app solved the problem.
  • Jacopo Tosi
    Jacopo Tosi over 8 years
    I added Location permissions, but it is not working. It starts the scanning but it does not reply anything in the callback.
  • 4ntoine
    4ntoine over 8 years
    i've added 'fine' and 'coarse' permissions but still no luck. discovery callback is not fired. Marshmallow on Nexus 9. i've checked Location is allowed in android settings for the app. I can see the device is found but callback is not fired. Also i can check it's fired on Lollipop. Any solution?
  • Piotr Wittchen
    Piotr Wittchen over 8 years
    I can confirm that. After adding ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION to the Manifest AND enabling Location in the phone, BLE scan works. I've tested it on Nexus 6 with Android 6.0 and it works.
  • Mackovich
    Mackovich over 8 years
    That's the classic Bluetooth scan. OP is talking about LE scan.
  • Mackovich
    Mackovich over 8 years
    I'm sorry if you got the wrong impression. I am just pointing that there is absolutely no relation between Bluetooth Classic Discovery and Bluetooth Low Energy Scan. Those two scans are completely different. The first scan will never return BLE devices unless there are dual mode and discoverable. And finally, you don't need location permission and enabled for Classic Bluetooth Discovery (just tried that today).
  • Usman khan
    Usman khan over 8 years
    But why so? I am only accessing Bluetooth? P.S: your solution does work though
  • qinmiao
    qinmiao over 8 years
    Android 6.0 Changes:To provide users with greater data protection, starting in this release, Android removes programmatic access to the device’s local hardware identifier for apps using the Wi-Fi and Bluetooth APIs.
  • Anticro
    Anticro over 7 years
    Would be nice, but in my case it is not an option to turn on GPS, in order to receive beacon advertisements. You simply can't find a working explanation, what GPS is used for, when the task is to receive bluetooth signals... ;-)
  • Brian Reinhold
    Brian Reinhold over 7 years
    But the 'classic' search for devices in the standard settings options also scans for BTLE devices. So it discovers both classic and BTLE devices. The down side is that the only next step one can take is to pair with the device. Thus one cannot connect to BTLE devices that don't pair using this approach.
  • Brian Reinhold
    Brian Reinhold over 3 years
    Old, but ...The standard way to add the permissions is have the user give the app permission on a first time start up. It's a pain to implement.