Android 12 新的蓝牙权限

87

蓝牙是我们应用程序的主要依赖项。因此,我们已经尝试实施新的Android 12蓝牙权限。我们唯一的资源是Android开发者在Android 12中新增的蓝牙权限。它只说需要添加以下权限:

"android.permission.BLUETOOTH_CONNECT"

"android.permission.BLUETOOTH_SCAN"

我添加了这些权限,并获取了运行时权限,当然还有位置(与 Android 12 之前版本一样)。我的代码库中没有其他更改。这是否应该?我不知道。所以,问题是我的应用程序找不到BLE设备。我找不到原因。

你有任何建议或资源吗?


无法在Android 12或之前的版本上找到BLE设备? - Dinkar Kumar
我正在尝试添加这些权限,但它们在Android Studio中不存在...我只看到旧的(BLUETOOTH、BLUETOOTH_ADMIN、BLUETOOTH_ADMIN_PRIVILEGED)。我将我的targetSdkVersion设置为“S”,compileSdkVersion设置为“android-S”,buildToolsVersion设置为“3.0.0-rc5”。有什么想法吗? - or_dvir
我能看到。我的设置如下:compileSdkVersion“android-S” buildToolsVersion“30.0.3” targetSdkVersion 31 - Mustafa Kuloğlu
13个回答

63

100%工作解决方案:无需任何第三方插件

清单代码:

<!--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 代码: // 检查 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)
                            requestBluetooth.launch(enableBtIntent)
                        }
....................................................

private var requestBluetooth = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
                if (result.resultCode == RESULT_OK) {
                    //granted
                }else{
                    //deny
                }
 }

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

了解更多信息: https://developer.android.com/guide/topics/connectivity/bluetooth/permissions

enter image description here


2
工作正常。但为什么会显示Nearbyshare权限? - RaJ
1
对我来说并不完全有效,我使用的是Android 10。我没有看到任何弹出窗口要求权限,我立即获得了授予权限的部分。 - ocramot
2
@RaJ 需要这个标志 <uses-permission android:name="android.permission.BLUETOOTH_SCAN" android:usesPermissionFlags="neverForLocation" /> - RonaldPaguay
1
如果您第一次不允许权限,应用程序将崩溃。之后无法再获取权限对话框,并且每次都会崩溃。 - Bhoomika Chauhan
使用了您提供的相同代码,只是在以下代码块后添加了:val enableBtIntent = Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE) requestBluetooth.launch(enableBtIntent)permissions.entries.forEach { Log.d("test006", "${it.key} = ${it.value}") } - Bhoomika Chauhan
显示剩余2条评论

19

这对我有用,

在清单文件中添加以下权限:

<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" />

在执行蓝牙功能之前,请检查权限:

//--------------------------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
                   }
               }

举个例子,

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();

这在 Kotlin 中应该怎么做? - IgorGanapolsky
为什么要添加BLUETOOTH_ADVERTISE? - Deepak Ganachari

10

我刚刚添加到清单中:

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

接着我像其他应用一样从主要活动中请求了这些权限。

为了请求权限,我正在使用库。

implementation 'pub.devrel:easypermissions:3.0.0'

那么你只需要调用这个函数

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);
            }
        }

并重写 onRequestPermissionResult

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

Jetpack Compose更新说明

如果您正在使用Jetpack Compose,您可以按照以下方式处理:

在rememberMultiplePermissionState函数内创建一个权限列表。

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

然后观察生命周期事件,并在恢复时启动权限请求。

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)
        }
    })

观察权限状态

permissionsState.permissions.forEach { permissionState ->
            when(permissionState.permission) {
                Manifest.permission.ACCESS_FINE_LOCATION -> {
                    when {
                        permissionState.hasPermission -> {}
                    }
                }
            }
        }
    }

为什么要使用easypermissions而不是Android SDK? - IgorGanapolsky
没有特别的原因,我们在旧的Java项目中使用它。自从我们迁移到Kotlin和Compose后,我们就停止使用它了。 - Pesa
为什么使用ON_START而不是ON_RESUME - the_prole
这取决于你的实施方式 :) - undefined

8

这个问题出现在Android 12和Android 13中。在我的情况下,添加新的权限不能解决问题:我已经为蓝牙和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" />

手动解决方案(添加了屏幕截图):进入应用程序的设置,单击权限。您将看到允许和拒绝(不允许)权限。在“不允许”权限列表中将会有一个“附近设备”的权限。允许该权限,该应用程序将在Android 12和Android 13上无问题运行。 enter image description here

1
这是2022年的答案! - Hairy Ass

1
如果你想让你的应用程序启动设备发现或操作蓝牙设置,除了BLUETOOTH权限外,你必须声明BLUETOOTH_ADMIN权限。大多数应用程序仅需要此权限以发现本地蓝牙设备。除非应用程序是一个“电源管理器”,可以在用户请求时修改蓝牙设置,否则不要使用此权限授予的其他功能。在你的应用程序清单文件中声明Bluetooth权限。来自developer android
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />

在您的清单文件中,但您没有将其添加到发现其他设备,我认为这是您问题的资源。

1
感谢您的回答,巴尼。很抱歉之前没有提到,但是BLUETOOTH_ADMIN已经添加了。即使加了这个权限也无法正常工作。 - Mustafa Kuloğlu

1
在 Android 12 中,添加以下代码后,我成功解决了问题。
<uses-permission android:name="android.permission.BLUETOOTH_SCAN"
        android:usesPermissionFlags="neverForLocation"
        tools:targetApi="s"/>

1
我在切换到Android 12时遇到了一个关于android清单中缺少BLUETOOTH_ADVERTISING的错误。基本上,我只是在调用startAdvertising时,在我的条件中添加了checkSelfPermission(Manifest.permission.BLUETOOTH) == PackageManager.PERMISSION_GRANTED

1
在Android 13上,我按照最受欢迎的答案解决了我的“蓝牙扫描”请求问题。然而,我遇到了一个新的“蓝牙连接”错误。经过一些时间的研究,我发现在Android 13中,他们将蓝牙连接设置为运行时请求,因此仅在清单文件中拥有它是不够的。我必须覆盖我的MainActivity.cs文件中的OnCreate,以便它可以在运行时获取权限。
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);
    }
}

我添加了运行时权限后,它开始在 Android 13 上工作。


0

我不确定他们是否宣布了有关蓝牙更改的任何内容,但如果没有其他帮助,他们最近引入了这个功能,可能会在您的用例中有所帮助,除非您做更复杂的事情。

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

在较新的版本中,如果您所需的所有功能都可以完成,则不再需要位置权限。
关于示例:您可以不包括这两行:
.setNamePattern(Pattern.compile("My device"))
.addServiceUuid(ParcelUuid(UUID(0x123abcL, -1L)), null)

我用它来搜索设备没有任何问题,连接方式类似


0

以下方法对我有效:

[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++; 
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接