You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用D11打印机蓝牙连接时遇BLUETOOTH_SCAN权限报错求助

解决Android蓝牙扫描报错:Need android.permission.BLUETOOTH_SCAN permission for AttributionSource

问题原因

你遇到的报错是因为Android 12(API 31)及以上版本对蓝牙权限做了更严格的拆分,即使在Manifest中添加了权限,也必须在运行时主动申请危险权限,且isDiscovering、cancelDiscovery、startDiscovery这些操作都需要持有BLUETOOTH_SCAN权限,仅靠@SuppressLint("MissingPermission")注解无法绕过系统的权限检查。

解决方案

1. 确认Manifest权限配置

在AndroidManifest.xml中添加对应API级别的权限:

<!-- Android 12+ 所需权限 -->
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<!-- 若无需通过蓝牙扫描关联位置,可添加此flag避免位置权限请求 -->
<uses-permission android:name="android.permission.BLUETOOTH_SCAN"
    android:usesPermissionFlags="neverForLocation" />

<!-- Android 11及以下 所需权限 -->
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

<!-- 声明蓝牙硬件需求 -->
<uses-feature android:name="android.hardware.bluetooth" android:required="true" />

2. 添加运行时权限申请逻辑

执行蓝牙扫描前,必须检查并申请对应权限:

// 根据系统版本定义需要申请的权限数组
private val requiredPermissions: Array<String>
    get() = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
        arrayOf(Manifest.permission.BLUETOOTH_SCAN, Manifest.permission.BLUETOOTH_CONNECT)
    } else {
        arrayOf(Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.BLUETOOTH_ADMIN)
    }

// 检查所有权限是否已授予
private fun hasBluetoothPermissions(): Boolean {
    return requiredPermissions.all {
        ContextCompat.checkSelfPermission(requireActivity(), it) == PackageManager.PERMISSION_GRANTED
    }
}

// 发起权限申请
private fun requestBluetoothPermissions() {
    registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { permissions ->
        val allGranted = permissions.values.all { it }
        if (allGranted) {
            searchForPrintersInternal()
        } else {
            AlertsUtil.showBaseOkWarningDialog(
                requireActivity(),
                getString(R.string.permission_required),
                getString(R.string.bluetooth_permission_denied)
            )
        }
    }.launch(requiredPermissions)
}

3. 修改扫描方法,先做权限校验

将原方法拆分为权限校验和实际扫描逻辑,移除无效的权限抑制注解:

// 对外调用的入口方法,先做权限检查
private fun searchForPrinters() {
    if (!hasBluetoothPermissions()) {
        requestBluetoothPermissions()
        return
    }
    searchForPrintersInternal()
}

// 实际执行蓝牙扫描的逻辑(确保权限已持有)
private fun searchForPrintersInternal() {
    val bluetoothManager =
        requireActivity().getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
    bluetoothAdapter = bluetoothManager.adapter
    if (bluetoothAdapter == null) {
        AlertsUtil.showBaseOkWarningDialog(
            requireActivity(),
            getString(R.string.bluetooth_not_available),
            ""
        )
        return
    } else if (!bluetoothAdapter!!.isEnabled) {
        askToEnableBluetooth()
        return
    }

    if (bluetoothAdapter?.isDiscovering == true) {
        Logger.log(TAG, "cancel start discovery")
        bluetoothAdapter?.cancelDiscovery()
    }

    initBluetoothScanBroadcastReceiver()
    bluetoothAdapter?.startDiscovery()
}

关键注意点

  • 不要依赖@SuppressLint("MissingPermission")跳过权限检查,该注解仅抑制编译器警告,系统运行时仍会校验权限。
  • Android 12+中BLUETOOTH_SCAN和BLUETOOTH_CONNECT是独立的危险权限,需分别申请。
  • 若无需通过蓝牙扫描获取位置信息,务必给BLUETOOTH_SCAN添加neverForLocation flag,避免不必要的位置权限请求。

内容的提问来源于stack exchange,提问作者LMB

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 14:45:50