7

I'm trying to connect to a device using BLE, but I'm getting an error on Android 12. I've tried a lot of different methods, but I couldn't find any solution. How do I ask for Bluetooth permissions?

AndroidManifest.xml

 <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
 <uses-permission android:name="android.permission.BLUETOOTH"
        android:maxSdkVersion="30" />
 <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"
        android:maxSdkVersion="30" />
 <uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
 <uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />
 <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
 <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

 <uses-feature android:name="android.hardware.bluetooth_le"
        android:required="true" />

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

And Permission Request Code

private static final String[] BLE_PERMISSIONS = new String[]{
            Manifest.permission.ACCESS_COARSE_LOCATION,
            Manifest.permission.ACCESS_FINE_LOCATION,
    };
    
private static final String[] ANDROID_12_BLE_PERMISSIONS = new String[]{
            Manifest.permission.BLUETOOTH_SCAN,
            Manifest.permission.BLUETOOTH_CONNECT,
            Manifest.permission.ACCESS_FINE_LOCATION,
    };

public static void requestBlePermissions(Activity activity, int requestCode) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S)
        ActivityCompat.requestPermissions(activity, ANDROID_12_BLE_PERMISSIONS, requestCode);
    else
        ActivityCompat.requestPermissions(activity, BLE_PERMISSIONS, requestCode);
}

Error message:

Fatal Exception: java.lang.SecurityException
Need android.permission.BLUETOOTH_CONNECT permission for android.content.AttributionSource@3d290817: GattService registerClient
Matt Ke
  • 3,599
  • 12
  • 30
  • 49
Enes
  • 110
  • 1
  • 1
  • 9
  • 1
    Could you please [edit] your question and add the full error message to it? – Michael Kotzjan Jan 18 '22 at 10:59
  • Shouldn't you pass an array with all permissions when requesting permissions? – Emil Jan 18 '22 at 18:35
  • Could you check if you have already the permissions? [Here](https://stackoverflow.com/a/70688410/17913726) an example in the code. Does the runtime popup asking for permission appear? – fabik111 Jan 18 '22 at 22:11
  • I'm checking if it already has the permissions. Yes, A runtime popup appears asking for permissions. When I give permissions, it crashes when it starts scanning. @fabik111 – Enes Jan 19 '22 at 07:07
  • @Enes I suggest you to override the onRequestPermissionsResult function so you will be able to get the result of the request permission operation. – fabik111 Jan 19 '22 at 08:34
  • @fabik111 I can get the result of the request permission process, I have overridden the onRequestPermissionsResult function. I started having this problem after API 31. Android said it changed bluetooth permissions, but I still haven't figured out the right use. – Enes Jan 19 '22 at 11:40
  • @Enes I asked you to override that function hoping that the result value would help you in debugging. BTW According [google](https://developer.android.com/guide/topics/connectivity/bluetooth/permissions): The BLUETOOTH_ADVERTISE, BLUETOOTH_CONNECT, and BLUETOOTH_SCAN permissions are runtime permissions. Therefore, you must explicitly request user approval in your app before you can look for Bluetooth devices, [...], or communicate with already-paired Bluetooth devices. The problem should be in how you make the permissions requests, check my answer how to do. It should work also for API 31. – fabik111 Jan 19 '22 at 13:06

2 Answers2

12

It looks like it should work but if you don't actually need the location permissions, I would suggest the following.

<uses-permission
    android:name="android.permission.BLUETOOTH_SCAN"
    android:usesPermissionFlags="neverForLocation"
    tools:targetApi="s" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission
    android:name="android.permission.BLUETOOTH"
    android:maxSdkVersion="30" />
<uses-permission
    android:name="android.permission.BLUETOOTH_ADMIN"
    android:maxSdkVersion="30" />
<uses-permission
    android:name="android.permission.ACCESS_COARSE_LOCATION"
    android:maxSdkVersion="30" />
<uses-permission
    android:name="android.permission.ACCESS_FINE_LOCATION"
    android:maxSdkVersion="30" />

With permission request

private static final String[] BLE_PERMISSIONS = new String[]{
        Manifest.permission.ACCESS_COARSE_LOCATION,
        Manifest.permission.ACCESS_FINE_LOCATION
};

@RequiresApi(api = Build.VERSION_CODES.S)
private static final String[] ANDROID_12_BLE_PERMISSIONS = new String[]{
        Manifest.permission.BLUETOOTH_SCAN,
        Manifest.permission.BLUETOOTH_CONNECT
};
gaggleweed
  • 204
  • 3
  • 5
  • 1
    Answers such as these that include version dependent code with no explanation. i.e. tools:targetApi="s", android:maxSdkVersion="30", become stale quickly. As versions move on, it's hard to guess whether the version numbers remain relevant, should be changed to match new versions, be deleted, or something else. – Graeme Gill Nov 04 '22 at 00:57
  • The answer is necessarily version dependent, as the OP is asking about Android 12 (S), which is API level 31. There’s no reason for the answer to become stale, as API versions 30 and below will always require those permissions. It's probably best not to guess or copy code blindly from SO without verifying it anyway. – gaggleweed Feb 14 '23 at 04:59
4

I, too, followed code from the Android documentation. Please remove max. SDK version 30 if you are testing and running in Android 12 devices.

     <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
     <uses-permission android:name="android.permission.BLUETOOTH"/>
     <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
     <uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
     <uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />
     <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />

apart from that your code is good.

And you can use your same code too for requesting runtime bluetooth permissions

private static final String[] BLE_PERMISSIONS = new String[]{
            Manifest.permission.ACCESS_COARSE_LOCATION,
            Manifest.permission.ACCESS_FINE_LOCATION,
    };
    
private static final String[] ANDROID_12_BLE_PERMISSIONS = new String[]{
            Manifest.permission.BLUETOOTH_SCAN,
            Manifest.permission.BLUETOOTH_CONNECT,
            Manifest.permission.ACCESS_FINE_LOCATION,
    };

public static void requestBlePermissions(Activity activity, int requestCode) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S)
        ActivityCompat.requestPermissions(activity, ANDROID_12_BLE_PERMISSIONS, requestCode);
    else
        ActivityCompat.requestPermissions(activity, BLE_PERMISSIONS, requestCode);
}
Bö macht Blau
  • 12,820
  • 5
  • 40
  • 61
Jeeva
  • 1,791
  • 2
  • 23
  • 42