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

Android 13 BLE扫描异常:权限弹窗未弹出且BluetoothLeScanner为空

问题分析与解决方案

一、权限请求弹窗不出现的原因

  • 重复请求码导致请求被覆盖:你当前在getPermission方法中重复使用相同的requestCode=2发起权限请求,Android系统同一时间仅能处理一个权限请求,后续请求会被直接忽略,最终仅会弹出第一个权限(BLUETOOTH_SCAN)的弹窗,其余权限请求根本不会触发。
  • 权限请求方式错误:应将所有需要动态申请的危险权限打包成一个数组,一次性发起请求,而非逐个调用。
  • Android 12+ BLE权限适配缺失:BLUETOOTH_SCAN和BLUETOOTH_CONNECT是API 31(Android 12)新增的权限,需在清单文件补充配置:
    • 若扫描无需关联位置信息,必须给BLUETOOTH_SCAN加上android:usesPermissionFlags="neverForLocation",否则系统会强制要求位置权限,且可能打乱权限请求逻辑。
    • 若targetSdkVersion < 31,新权限不生效,需使用旧版BLUETOOTH和BLUETOOTH_ADMIN权限(这两个在API 31前属于普通权限,无需动态请求)。
  • 位置权限适配问题:若targetSdkVersion >= 29(Android 10),ACCESS_COARSE_LOCATION属于危险权限,但如果已在系统设置中授权过,再次请求不会弹出弹窗;Android 12+若配置了neverForLocation,则无需请求位置权限。

二、缺失权限是否会导致BluetoothLeScanner为空?

不会。BluetoothLeScanner为空的常见原因:

  • 设备本身不支持BLE功能(部分老旧设备无BLE模块);
  • 蓝牙未开启(bluetoothManager.adapter会为空,或蓝牙处于关闭状态);
  • 系统蓝牙服务异常(极少数情况)。

权限缺失只会导致扫描操作失败(触发onScanFailed回调,错误码通常为SCAN_FAILED_PERMISSION_DENIED),但不会导致BluetoothLeScanner实例为空。

修正后的代码示例

1. 清单文件补充配置(适配Android 12+)

<uses-permission android:name="android.permission.BLUETOOTH_SCAN"
    android:usesPermissionFlags="neverForLocation" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<!-- 仅当需要关联位置的BLE扫描时保留,否则可移除 -->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

<!-- 声明应用依赖BLE功能,过滤不支持的设备 -->
<uses-feature android:name="android.hardware.bluetooth_le" android:required="true" />

2. 修正后的Activity代码

class MainActivity : AppCompatActivity() {
    private val REQUEST_PERMISSIONS_CODE = 1001
    private val ENABLE_BLUETOOTH_CODE = 1002
    
    // 根据Android版本动态选择需要请求的权限
    private val REQUIRED_PERMISSIONS = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
        arrayOf(Manifest.permission.BLUETOOTH_SCAN, Manifest.permission.BLUETOOTH_CONNECT)
    } else {
        arrayOf(Manifest.permission.BLUETOOTH_ADMIN, Manifest.permission.ACCESS_COARSE_LOCATION)
    }

    private var bluetoothLeScanner: BluetoothLeScanner? = null
    private val bleScanner = object : ScanCallback() {
        override fun onScanResult(callbackType: Int, result: ScanResult?) {
            super.onScanResult(callbackType, result)
            result?.let {
                Log.d("MainActivity", "设备地址:${it.device.address},名称:${it.device.name ?: "未知"}")
            }
        }

        override fun onScanFailed(errorCode: Int) {
            super.onScanFailed(errorCode)
            Log.e("MainActivity", "扫描失败,错误码:$errorCode")
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val fab: View = findViewById(R.id.fab)
        fab.setOnClickListener {
            bluetoothLeScanner?.startScan(bleScanner) ?: Log.e("MainActivity", "BLE扫描器未初始化,请检查蓝牙状态")
        }
    }

    override fun onStart() {
        super.onStart()
        initBluetoothLeScanner()
        requestRequiredPermissions()
    }

    override fun onStop() {
        bluetoothLeScanner?.stopScan(bleScanner)
        super.onStop()
    }

    private fun initBluetoothLeScanner() {
        val bluetoothManager = getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
        val bluetoothAdapter = bluetoothManager.adapter ?: run {
            Log.e("MainActivity", "设备不支持蓝牙")
            return
        }

        // 检查蓝牙是否开启,未开启则跳转至设置页面
        if (!bluetoothAdapter.isEnabled) {
            startActivityForResult(Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE), ENABLE_BLUETOOTH_CODE)
            return
        }

        bluetoothLeScanner = bluetoothAdapter.bluetoothLeScanner
    }

    private fun requestRequiredPermissions() {
        val permissionsToRequest = mutableListOf<String>()
        REQUIRED_PERMISSIONS.forEach { perm ->
            if (ActivityCompat.checkSelfPermission(this, perm) != PackageManager.PERMISSION_GRANTED) {
                permissionsToRequest.add(perm)
            }
        }
        if (permissionsToRequest.isNotEmpty()) {
            ActivityCompat.requestPermissions(this, permissionsToRequest.toTypedArray(), REQUEST_PERMISSIONS_CODE)
        }
    }

    override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)
        if (requestCode == REQUEST_PERMISSIONS_CODE) {
            val allGranted = grantResults.all { it == PackageManager.PERMISSION_GRANTED }
            if (!allGranted) {
                Log.w("MainActivity", "部分权限未授权,可能无法正常扫描BLE设备")
            }
        }
    }

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        if (requestCode == ENABLE_BLUETOOTH_CODE) {
            if (resultCode == RESULT_OK) {
                initBluetoothLeScanner()
            } else {
                Log.e("MainActivity", "蓝牙未开启,无法扫描BLE设备")
            }
        }
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 12:19:57