Android 12 New Bluetooth Permissions
Asked Answered
U

12

91

Bluetooth is the main dependency of our app. So, We already try to implement new Android 12 Bluetooth permissions. Our only resource is Android developers New Bluetooth permissions in Android 12. There is just saying add permissions

"android.permission.BLUETOOTH_CONNECT"

"android.permission.BLUETOOTH_SCAN"

I add and I got runtime permissions for both and of course location(usual as pre 12)).
There is no other change in my codebase. Should be? I don't know. So, the problem is my app can't find the BLE device. I couldn't find the reason.

Do you have any suggestions or resources?

Unchaste answered 27/5, 2021 at 13:16 Comment(3)
not able to find BLE device on Android 12 or pre 12 as well?Sociology
i am trying to add these permissions too but they dont exist in android studio... i only see the old ones (BLUETOOTH, BLUETOOTH_ADMIN, BLUETOOTH_ADMIN_PRIVILEGED). i set my targetSdkVersion to "S", my compileSdkVersion to "android-S", and my buildToolsVersion to "3.0.0-rc5". any idea?Crag
I can see. My settings like this: compileSdkVersion "android-S" buildToolsVersion "30.0.3" targetSdkVersion 31Fallacious
U
-4

This was a platform bug. Google fixed the bug in the new Android 12 Beta version.

Unchaste answered 19/8, 2021 at 6:13 Comment(2)
Got a link to the bug?Augustusaugy
Issues is reproduced on 13Tier
A
67

100% working solution : no need any 3rd party plugin

manifest code:

<!-- BLUETOOTH PERMISSION -->
<!-- Request legacy Bluetooth permissions on older devices. -->
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<!-- Needed only if your app looks for Bluetooth devices.
     If your app doesn't use Bluetooth scan results to derive physical
     location information, you can strongly assert that your app
     doesn't derive physical location. -->
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
<!-- Needed only if your app makes the device discoverable to Bluetooth
     devices. -->
<uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />
<!-- Needed only if your app communicates with already-paired Bluetooth
     devices. -->
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<!-- bibo01: hardware option -->
<uses-feature
    android:name="android.hardware.bluetooth"
    android:required="false" />
<uses-feature
    android:name="android.hardware.bluetooth_le"
    android:required="false" />

Kotlin code:

fun requestBluetooth() {
    // check android 12+
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
        requestMultiplePermissions.launch(
            arrayOf(
                Manifest.permission.BLUETOOTH_SCAN,
                Manifest.permission.BLUETOOTH_CONNECT,
            )
        )
    } else {
        val enableBtIntent = Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE)
        requestEnableBluetooth.launch(enableBtIntent)
    }
}

private val requestEnableBluetooth =
    registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
        if (result.resultCode == RESULT_OK) {
            // granted
        } else {
            // denied
        }
    }

private val requestMultiplePermissions =
    registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { permissions ->
        permissions.entries.forEach {
            Log.d("MyTag", "${it.key} = ${it.value}")
        }
    }

Read more: https://developer.android.com/guide/topics/connectivity/bluetooth/permissions

enter image description here

Autotomy answered 15/11, 2021 at 10:25 Comment(8)
Working Fine. But Why Nearbyshare permission showing?Mook
Not totally working for me, I'm on Android 10. I don't see any popup asking for permissions, I immediately get to the part where the permissions are granted.Graphics
@Mook need this flag <uses-permission android:name="android.permission.BLUETOOTH_SCAN" android:usesPermissionFlags="neverForLocation" />Gudrun
The application gets crashed if you Don't allow permission for the first time. After that not able to get the permission dialog and got crashed every time.Mimas
Share your code in a stack or git link, I will help u, @Bhoomika ChauhanAutotomy
Used the same code as you have provided. I have just added val enableBtIntent = Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE) requestBluetooth.launch(enableBtIntent) after below block permissions.entries.forEach { Log.d("test006", "${it.key} = ${it.value}") }Mimas
@BhoomikaChauhan in case the user denies a permission for more that once, the system never shows permission dialogues again, check this section developer.android.com/training/permissions/requesting#explainMurmansk
I used this snippet, and it works on first launch, asks permissions and i allow and app works fine. Next time i start the app it crashes instantly and nothing in logcat. When i reinstall or clear all app data then it runs again and asks permissions but again next launch it crashes. Any help?Eec
S
20

This worked for me,

In the manifest, add the following permissions:

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

Then, before executing a Bluetooth function, check the permission:

//--------------------------Java--------------------------
if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.BLUETOOTH_CONNECT) == PackageManager.PERMISSION_DENIED) 
                {
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) 
                    {
                        ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.BLUETOOTH_CONNECT}, 2);
                        return;
                    }
                }

//--------------------------Kotlin--------------------------
if (ContextCompat.checkSelfPermission(this@MainActivity, Manifest.permission.BLUETOOTH_CONNECT) == PackageManager.PERMISSION_DENIED) 
               {
                   if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) 
                   {
                       ActivityCompat.requestPermissions(this@MainActivity, arrayOf(Manifest.permission.BLUETOOTH_CONNECT), 2)
                       return
                   }
               }

For an example,

if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.BLUETOOTH_CONNECT) == PackageManager.PERMISSION_DENIED) {
                        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
                            ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.BLUETOOTH_CONNECT}, 2);
                            return;
                        }
                    }
                    mBTSocket.connect();
Sympathize answered 7/3, 2022 at 1:38 Comment(2)
How would this be done in Kotlin?Gabi
why is BLUETOOTH_ADVERTISE added ?Inscription
R
10

I just added to the manifest:

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

and then I requested those permissions from Main Activity as any other. For requesting permission I am using library

implementation 'pub.devrel:easypermissions:3.0.0'

then you can just call this function

public static final String[] BLUETOOTH_PERMISSIONS_S = { Manifest.permission.BLUETOOTH_SCAN, Manifest.permission.BLUETOOTH_CONNECT} ;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
     if (!EasyPermissions.hasPermissions(this, BLUETOOTH_PERMISSIONS_S)) {
                EasyPermissions.requestPermissions(this, message, yourRequestCode,BLUETOOTH_PERMISSIONS_S);
            }
        }

and override onRequestPermissionResult

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this);
    }

UPDATE FOR JETPACK COMPOSE

If you are using jetpack compose you can handle it like this:

Create a list of your permissions inside of rememberMultiplePermissionState function

rememberMultiplePermissionsState(
            permissions = listOf(
                Manifest.permission.BLUETOOTH_CONNECT,
                Manifest.permission.BLUETOOTH_SCAN
            )
        )

Then observe a lifecycle events and on resume launch permission request

val lifecycleOwner = LocalLifecycleOwner.current
DisposableEffect(key1 = lifecycleOwner,
    effect = {
        val observer = LifecycleEventObserver { _, event ->
            if(event == Lifecycle.Event.ON_START) {
                permissionsState.launchMultiplePermissionRequest()
            }
        }
        lifecycleOwner.lifecycle.addObserver(observer)

        onDispose {
            lifecycleOwner.lifecycle.removeObserver(observer)
        }
    })

Observe the permission state

permissionsState.permissions.forEach { permissionState ->
            when(permissionState.permission) {
                Manifest.permission.ACCESS_FINE_LOCATION -> {
                    when {
                        permissionState.hasPermission -> {}
                    }
                }
            }
        }
    }
Recovery answered 21/6, 2021 at 11:3 Comment(4)
Why use easypermissions instead of Android SDK?Gabi
No particular reason, we were using in the old java project. Since we migrated to kotlin and compose we stopped using it.Recovery
why ON_START and not ON_RESUME?Expunge
that depends on your implementation :)Recovery
E
10

It happens with Android 12 and Android 13. Adding new permissions could not solve the issue in my case: I have all related permissions set up for bluetooth and WiFi:

<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" />
<uses-feature android:name="android.hardware.bluetooth" android:required="false"/>
<uses-feature android:name="android.hardware.bluetooth_le" android:required="false"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"
    android:maxSdkVersion="32" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.NEARBY_WIFI_DEVICES"
    android:usesPermissionFlags="neverForLocation" />

Manual solution(Screenshot added): Go to settings of the app and click on permissions. You will see Allowd and Denied(Not allowed) permissions. There will be "Nearby devices" permission in the "Not allowed" permissions list. Allow that one and the app will work without probem in Android 12 and Android 13. enter image description here

Euroclydon answered 21/11, 2022 at 1:13 Comment(1)
This is the answer, for year 2022!Ketty
F
1

If you want your app to initiate device discovery or manipulate Bluetooth settings, you must declare the BLUETOOTH_ADMIN permission in addition to the BLUETOOTH permission. Most apps need this permission solely for the ability to discover local Bluetooth devices. Don't use the other abilities granted by this permission unless the app is a "power manager" that modifies Bluetooth settings upon user request. Declare the Bluetooth permission(s) in your app manifest file

from developer android we see you have to add

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

in your manifest file but you did not add it to discover other devices i think this is the resource of your problem

Film answered 31/5, 2021 at 9:54 Comment(1)
Thanks for your answer Barney and sorry for didn't mention it before but BLUETOOTH_ADMIN is already added. It is not working with that also.Fallacious
F
1

I had an error with BLUETOOTH_ADVERTISING missing in the android manifest when switching to Android 12

Basically, I just added checkSelfPermission(Manifest.permission.BLUETOOTH) == PackageManager.PERMISSION_GRANTED in my conditions where startAdvertising was called.

Flor answered 18/7, 2022 at 15:38 Comment(0)
D
1

In android 12, after adding below line is working fine for me.

<uses-permission android:name="android.permission.BLUETOOTH_SCAN"
        android:usesPermissionFlags="neverForLocation"
        tools:targetApi="s"/>
Duster answered 2/12, 2022 at 12:37 Comment(0)
V
1

On Android 13, I followed the top voted answer and it fixed my "Bluetooth Scan" request issue. However, I was getting a new error for "Bluetooth Connect". After spending some time I was able to figure out that in Android 13, they made Bluetooth Connect a runtime request, so just having it in the manifest file isn't enough. I had to overwrite my OnCreate in my MainActivity.cs file, so that it could get the permission at runtime.

private const int REQUEST_FINE_LOCATION_PERMISSION = 100;
private const int REQUEST_BLUETOOTH_SCAN_PERMISSION = 101;
private const int REQUEST_BACKGROUND_LOCATION_PERMISSION = 102;
private const int REQUEST_BLUETOOTH_CONNECT_PERMISSION= 103;

protected override void OnCreate(Bundle savedInstanceState)
{
    base.OnCreate(savedInstanceState);

    RequestedOrientation = ScreenOrientation.Portrait;

    // Request the ACCESS_FINE_LOCATION permission at runtime
    if (CheckSelfPermission(Manifest.Permission.AccessFineLocation) != Permission.Granted)
    {
        RequestPermissions(new string[] { Manifest.Permission.AccessFineLocation },
            REQUEST_FINE_LOCATION_PERMISSION);
    }

    if (CheckSelfPermission(Manifest.Permission.AccessBackgroundLocation) != Permission.Granted)
    {
        RequestPermissions(new string[] { Manifest.Permission.AccessBackgroundLocation },
            REQUEST_BACKGROUND_LOCATION_PERMISSION);
    }

    // Request the BLUETOOTH_SCAN permission at runtime
    if (CheckSelfPermission(Manifest.Permission.BluetoothScan) != Permission.Granted)
    {
        RequestPermissions(new string[] { Manifest.Permission.BluetoothScan },
            REQUEST_BLUETOOTH_SCAN_PERMISSION);
    }

    //Request the BLUETOOTH_CONNECT permission at runtime
    if (CheckSelfPermission(Manifest.Permission.BluetoothConnect) != Permission.Granted)
    {
        RequestPermissions(new string[] { Manifest.Permission.BluetoothConnect },
            REQUEST_BLUETOOTH_CONNECT_PERMISSION);
    }
}

Once I added the runtime permission, it began to work on Android 13.

Veasey answered 24/5, 2023 at 22:44 Comment(0)
S
0

I'm not sure if they announced anything regarding Bluetooth changes, but if nothing else helps they introduced this recently which MIGHT help in your use case unless you do more complex stuff.

https://developer.android.com/guide/topics/connectivity/companion-device-pairing#kotlin

In the newer versions, you also don't need the location permission anymore if this does everything you need.

Regarding the sample: you can just not include these 2 lines:

.setNamePattern(Pattern.compile("My device"))
.addServiceUuid(ParcelUuid(UUID(0x123abcL, -1L)), null)

I use it to search for devices without any problems, connecting works similarly

Sacramental answered 2/6, 2021 at 22:23 Comment(0)
S
0

this worked for me:

[AndroidManifest.xml]

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

[MainActivity.java]

 private static final String[] PERMISSIONS = new String[]{Manifest.permission.BLUETOOTH_CONNECT, Manifest.permission.BLUETOOTH_ADVERTISE };

_

public void getPermissionFromUser()
{
    if(BA == null){
        BA = BluetoothAdapter.getDefaultAdapter();
    }


    int i=0;
    for(String permission : PERMISSIONS){
        String title = "bluetooth permission needed";
        String msg="";
        if(i==0){
            msg = "Give the app permission to use Bluetooth";
        }else if(i==1) {
            msg = "Give permission to search for the current device on other Bluetooth devices";
        }

        if (ActivityCompat.checkSelfPermission(MainActivity.this, PERMISSIONS[i]) == PackageManager.PERMISSION_DENIED) {
            int finalI = i;
            final AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
            builder.setTitle(title);
            builder.setMessage(msg);
            builder.setPositiveButton(android.R.string.ok, null);               
            builder.setOnDismissListener(new DialogInterface.OnDismissListener() {
                @Override
                public void onDismiss(DialogInterface dialogInterface) {
                    requestPermissions(new String[]{PERMISSIONS[finalI]}, 3);        
                }
            });
            builder.show();
        }
        i++; 
    }
}
Sprocket answered 8/3, 2023 at 4:8 Comment(0)
A
0

manifest file:

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

private static final int REQUEST_CODE_BLUETOOTH_SCAN = 1;

The check permission method. Permission request is required for Android 12(s) or above,So if the version is lower, it returns true

    private boolean checkPermission() {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
        int permission = ContextCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.BLUETOOTH_SCAN);
        return permission == PackageManager.PERMISSION_GRANTED;
    }else{
        return true;
    }
}

And the Request permission method

    private void requestPermission() {
    ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.BLUETOOTH_SCAN}, REQUEST_CODE_BLUETOOTH_SCAN);
}

lastly Override the onRequestPermissionsResult

 @Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);

    if (requestCode == REQUEST_CODE_BLUETOOTH_SCAN) {
        if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            // The user has granted the permission.
            // Start scanning for Bluetooth devices.
        } else {
            // The user has denied the permission.
            // Display an error message.
        }
    }
}
Ambrosane answered 23/5, 2023 at 18:58 Comment(0)
U
-4

This was a platform bug. Google fixed the bug in the new Android 12 Beta version.

Unchaste answered 19/8, 2021 at 6:13 Comment(2)
Got a link to the bug?Augustusaugy
Issues is reproduced on 13Tier

© 2022 - 2024 — McMap. All rights reserved.