121

After upgrading to Android version 6.0 Bluetooth Low Energy (BLE) scanning will only work if Location services are enabled on the device. See here for reference: Bluetooth Low Energy startScan on Android 6.0 does not find devices

Basically, you need to have the permission enabled for the app as well as on for the phone. Is this a bug? Is it possible to scan without location services actually enabled? I don't want to have to have location for all my apps.

EDIT I failed to mention that I am using the startScan() method in BluetoothLeScanner provided in API 21. I am okay with the course and fine location permissions in the manifest that this method require. I just don't want the users of my app to have to enable location services on their device (GPS, etc.) to use my app.

Previously, the startScan() method would run and return results with the Location services disabled on the phone. On Marshmallow, however, the same application would "scan" but silently failed and returned no results when location services were not enabled on the phone and course/fine location permissions were still in the manifest.

Community
  • 1
  • 1
V-PTR
  • 3,183
  • 3
  • 20
  • 21
  • What devices are you using? I ran into the same problem with a Moto G 2nd Generation. Moto G 1st Generation and Nexus 6 run fine with exact the same code without explicitly enabling location services. – shadowhorst Apr 26 '16 at 12:16
  • I've noticed it on any device running Marshmallow - Nexus 5X, Samsung S6, Samsung S7, LG G4 – V-PTR Apr 26 '16 at 12:45

10 Answers10

108

No, this is not a bug.

This issue was brought up to Google where they responded saying that this was the intended behavior and they won't fix it. They directed developers to this site where it points out that location permission is now needed for hardware identifier access. It is now the developer's responsibility to make their users aware of the requirement.

In the issue, however, it doesn't address why Location services (GPS, etc.) are required and it doesn't seem like they are going to revisit the issue to explain this since it has been marked as the intended behavior.

To answer the second part of the question: Yes, it is possible to scan without enabling Location services. You can do a Bluetooth classic scan using BluetoothAdapter.getDefaultAdapter().startDiscovery() and that will work with Location services off. This will discover all Bluetooth devices, BLE and otherwise. However, BLE devices won't have a scan record that they would have had if they were seen as a result of startScan().

V-PTR
  • 3,183
  • 3
  • 20
  • 21
  • 21
    Google claiming it's not a bug leaves me cold. Their attitude is plain BS. – Marki Aug 31 '18 at 22:03
  • 31
    It's not really a bug - if a malicious app developer can scan for known bluetooth beacons, then they can figure out your location without raising the user's suspicions by asking for location permissions. So asking for BLE access must unfortunately be treated the same as asking for your rough location. – ArtHare Oct 01 '18 at 15:44
  • 1
    @ArtHare that's a great insight, and makes sense. thanks. do you have a citation for that ? – orion elenzil Dec 21 '18 at 15:35
  • 4
    @orionelenzil "The other permission that you must declare is either ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION. A location permission is required because Bluetooth scans can be used to gather information about the location of the user." from https://developer.android.com/guide/topics/connectivity/bluetooth – ArtHare Dec 22 '18 at 17:55
  • @ArtHare this works fine on iOS, because they decoupled the beacons from the general BLE scans (and google should copy this solution I guess). seems Apple indeed cares about user experience and have a competent team handling it.. – BjornW Mar 02 '19 at 13:28
  • 1
    @BjornW How does that help? If I'm malicious, I can still compare your detected local deviceIDs, beacons or not, to a known database of deviceID locations (gathered through people that _did_ accept the location permission). Same as using wifi router namesets. If I see "Art's Chromecast 13:24:56:ab:dc" detected, and I know that Art's Chromecast is at 53N, 78W because of some other person's submission, then I know where you are to within ~100m. – ArtHare Mar 02 '19 at 22:17
  • 18
    Let me see if I have this straight. The great advantage of BLE is the "LE" bit, i.e. Low Energy, meaning reduced drain on my battery. Of course, to gain those savings, I have to turn on GPS, which is a known battery hog, thus negating any power savings I might have gotten from use of BLE. /me shakes head in disbelief. – dgnuff Mar 26 '19 at 15:33
  • 3
    @dgnuff turning on the location service is not the same as powering up the GPS hardware. It means that apps then may use the GPS – usually in the foreground since recent versions of Android are very zealous about not allowing background apps. – Pierre-Luc Paour May 24 '19 at 07:36
  • @BjornW iOS attempts to obscure the identity of BLE devices in the area by providing a random UUID rather than the actual MAC address. This kind of works, but only if none of the devices nearby will identify themselves in any other way. As a result, a malicious app can often identify the user's location even without the MAC addresses, and without letting the user know that this could be happening. Meanwhile, obscuring MAC addresses causes problems for legitimate apps. I think Android's approach is both better for developers and more sensitive to user privacy. – divegeek Aug 20 '19 at 15:32
  • 18
    This is incredible. Surely if Google were concerned about BLE scans being used to infer location, they should have added a separate permission for that, rather than throwing the baby out with the bathwater by forcing the user to allow GPS access! – Desty Dec 26 '19 at 17:08
  • 3
    FYI : with Android 10 if GPS is off no device search callbacks in triggered, Classic or LE. The framework does not throw error or warning, just fails silently. – Ankit Jan 25 '20 at 11:19
  • 12
    @Pierre-LucPaour Forcing to turn on GPS means other apps that actually uses location services can use it behind the scene 'legally'. One of the reason users manually turns off GPS is to prevent apps from using it periodically and drain battery, forcing GPS to search for Bluetooth is the most counter intuitive way to let user know their location may be used. – Ankit Jan 25 '20 at 11:25
  • Is there a way for checking if a device needs GPS enabled in order to use BLE? Nexus 5x with Android 8.1 requires it; Redmi Note 5 with Android 9 doesn't. If possible, I'd avoid to ask the user to enable GPS if it is not strictly needed – Massimo Jun 25 '20 at 07:49
  • @Massimo Did you find some solution for that? – Arubu Feb 04 '21 at 17:09
  • Yes, adapt this to your needs: https://pastebin.com/XyytNe3S – Massimo Feb 08 '21 at 10:46
  • 4
    startDiscovery method requires GPS turned on on my Android 10 phone. This is a bug, because "Location Permission" != "GPS turned on". StartDiscovery requires "Location Permisiion" and this is ok, but why when i get permission i am still getting error until user physically turn on GPS localisation? This is a bug. – bzyku Aug 23 '21 at 08:33
  • Ok, but for the Play Store purposes, where no sensitive/personal data is collected in the app, but for BLE, the location must be enabled, and since Location is a data type treated as Sensitive, how should I answer the question "Does your app collect or share any of the required user data types?" from the Data Safety section for app releases? In this case, is ok to answer "No"? – a curious guy Feb 27 '23 at 17:05
12

I solved this by setting targetSdkVersion to 22 in the Gradle file. You must declare ACCESS_COARSE_LOCATION in the manifest but, BLE scanning will work even if the user denies this permission from App Settings.

This is just a hack to avoid requesting location permission. It's better to target the latest android versions.

Edit

This solution should no longer be used as Google Play will require that new apps target at least Android 8.0 (API level 26). Apps should request for location permission for BLE scanning.

JiTHiN
  • 6,548
  • 5
  • 43
  • 69
  • Great, thanks! Do you have an idea what to do with libraries that simulates monitoring like AltBeacon for instance? The do not work without location on :( and they are using basically the same mechanism... And what about the min compile version? @JiTHiN – Shahar Lahav Nov 08 '17 at 19:46
  • Downgraded from 23 to 22 and it works even on Android 7.0. My initial problem was that you had to enable localization, now I can scan BLE devices with localization disabled. – Mariusz Wiazowski Nov 28 '17 at 14:41
  • 1
    This is a hack, however this is **NOT RECOMMENDED** it is always better to target latest sdk versions. The proper way of doing this is to request `ACCESS_COARSE_LOCATION` in runtime – Aaron Oct 16 '18 at 02:57
  • 2
    This is not a solution any more ( see https://developer.android.com/distribute/best-practices/develop/target-sdk "Google Play will require that new apps target at least Android 8.0 (API level 26) from August 1, 2018, and that app updates target Android 8.0 from November 1, 2018.") – Étienne Nov 06 '18 at 08:44
10

What I found is that after Android 6 you must grant ACCESS_COARSE_LOCATION permission. But on some devices is also necessary your phone location service (GPS) to be switched on, so you can discover peripheral devices. I found that using Nexus 5x, with Android 7.0.

Ivaylo Pankov
  • 99
  • 1
  • 5
3

I also tried this on manifest but did not request permission, not sure why. Is you app prompting for Location permission on startup? If it's not, we need to request for permission on runtime.

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 here only if you have provided ACCESS_COARSE_LOCATION on manifest.

Kamal Kishore
  • 399
  • 4
  • 6
  • 1
    Yeah, you have to explicitly request the permission at runtime as well as turn on location services for the device. But I was wondering if there was a way to do a BLE scan without having to turn location services on or request the course location permission at runtime. – V-PTR Oct 13 '15 at 14:27
  • 1
    Requesting permissions are not enough, you need to check if location services are enabled too. – drindt Jul 03 '20 at 12:14
  • why google permitt this issue? sincerily that I don't understand – Duran k Nov 14 '21 at 23:47
3

You can use BluetoothAdapter.startDiscovery().
It will scan for both Bluetooth Smart and classic Bluetooth devices, but location services do not need to be enabled.
(You still need ACCESS_COARSE_LOCATION permissions on Android 6.)

You can call BluetoothDevice.getType on found devices to filter for Bluetooth Smart / Low Energy devices.

Neuron
  • 5,141
  • 5
  • 38
  • 59
Noctis
  • 190
  • 3
  • 7
2

after you add ACCESS_COARSE_LOCATION to Manifest, ask for permission on runtime:

 public void checkPermission() {
            if (Build.VERSION.SDK_INT >= 23) {
                if (checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED && checkSelfPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED) {

            } else {
                ActivityCompat.requestPermissions(this, new String[]{
                        Manifest.permission.ACCESS_FINE_LOCATION,
                        Manifest.permission.ACCESS_COARSE_LOCATION,}, 1);
            }
        }
    }
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        if (requestCode == 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED && grantResults[1] == PackageManager.PERMISSION_GRANTED) {
        } else {
            checkPermission();
        }
    }

worked for me!

batsheva
  • 2,175
  • 1
  • 20
  • 32
1

You can scan BLE devices without location access using CompanionDeviceManager (API26). https://developer.android.com/reference/android/companion/CompanionDeviceManager.

antaki93
  • 704
  • 7
  • 10
  • 1
    Note that it doesn't work or even crashes in Android 8 & 9. I can use it on a Pixel 3a, but on my Samsung test devices, the system service just crashes. So unfortunately not a very stable solution. – Peterdk Feb 20 '21 at 19:43
  • Thank you @Peterdk. I used this component only experimentally. It's a pity that it doesn't develop properly. – antaki93 Feb 21 '21 at 15:02
  • When I scanned with filters Companion Device Manager crashes (Samsung Android 8) without scan filters it works. I think this feature is not a stable solution. The documentation is also doesn't help. – Ehsan Shadi Mar 14 '21 at 11:55
  • Could you @Peterdk name the exception it throws? – Dushyant Suthar Nov 28 '22 at 14:42
0

Well, I have looked at my code written in Eclipse and I use there the startScan (API 21) function without declaring location stuff in manifest file. I still get the proper callback. Have you tried running the code without the location declaration? In the other hand - you can use the deprecated startLeScan (API 18) which does not require these permissions. However, in my opinion searching and reading desired characteristic in service is more complicated with API 18 methods.

Michał Dobi Dobrzański
  • 1,449
  • 1
  • 20
  • 19
  • I am using the `startScan` function in `BluetoothLeScanner`. I am purposefully using the non-deprecated methods. In fact, I am checking for devices that are using APIs greater than 21 to specifically use the new methods provided. I tried without the location and it just silently fails. The scanning runs but nothing is returned (using the post- API 21 method) – V-PTR Oct 09 '15 at 20:03
0

From what I recently noticed on android 8.0, it is not required to turn on your GPS to do a BLE Scan, but you have to declare it in the manifest, but the user must allow the permission.

Android will prompt the user to allow location permission when you attempt to do a scan with startScan() method. Your scan will fail if the permission is not allowed.

Lee Boon Kong
  • 1,007
  • 1
  • 8
  • 17
0

Starting with API 31, you can use a new BLUETOOTH_SCAN permission instead of location permission.

If the app does not derive physical locations, you can add the android:usesPermissionFlags="neverForLocation" attribute to the BLUETOOTH_SCAN permission declaration:

<manifest ...>
    <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
    <uses-permission
        android:name="android.permission.BLUETOOTH_SCAN"
        android:usesPermissionFlags="neverForLocation" />

    ...
</manifest>

And then:

val requiredPermissions = if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) {
    arrayOf(Manifest.permission.ACCESS_FINE_LOCATION)
} else {
    arrayOf(Manifest.permission.BLUETOOTH_CONNECT, Manifest.permission.BLUETOOTH_SCAN)
}
requestPermissions(requiredPermissions, 9999)

More: https://xizzhu.me/post/2021-10-05-android-12-bluetooth-permissions/

antaki93
  • 704
  • 7
  • 10