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

Kotlin开发Android BLE应用:重复申请权限问题求助

解决方案:一次性申请BLE相关权限完成所有操作

核心问题分析

你遇到的问题源于Android不同版本对BLE操作的权限要求存在差异,且当前代码分散检查权限、未等待权限回调就执行操作,导致每个函数都触发权限提示。另外你写的stopBleScan里误用了startScan,这是需要先修正的错误。

步骤1:明确各版本所需权限

先统一整理不同Android版本下BLE扫描、获取设备名称需要的权限:

  • Android 12+(API 31+):BLUETOOTH_SCAN(扫描权限)、BLUETOOTH_CONNECT(获取设备名称、连接设备权限)
  • Android 10-11(API 29-30):ACCESS_FINE_LOCATION(BLE扫描依赖位置权限)
  • Android 6-9(API 23-28):ACCESS_COARSE_LOCATION 或 ACCESS_FINE_LOCATION

步骤2:统一权限申请逻辑

先在AndroidManifest.xml中声明所有必要权限:

<!-- Android 12+ 权限 -->
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" android:usesPermissionFlags="neverForLocation" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />

<!-- Android 10-11 权限 -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

<!-- Android 6-9 权限 -->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />

<!-- 低版本基础BLE权限(无需动态申请) -->
<uses-permission android:name="android.permission.BLUETOOTH" android:maxSdkVersion="30" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" android:maxSdkVersion="30" />

<!-- 声明设备支持BLE -->
<uses-feature android:name="android.hardware.bluetooth_le" android:required="true" />

然后在Activity中实现统一的权限检查和申请:

private const val REQUEST_CODE_BLE_PERMISSIONS = 1001

// 根据系统版本返回需要的权限数组
private val requiredPermissions: Array<String>
    get() = when {
        Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
            arrayOf(
                Manifest.permission.BLUETOOTH_SCAN,
                Manifest.permission.BLUETOOTH_CONNECT
            )
        }
        Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q -> {
            arrayOf(Manifest.permission.ACCESS_FINE_LOCATION)
        }
        else -> {
            arrayOf(Manifest.permission.ACCESS_COARSE_LOCATION)
        }
    }

// 检查权限,缺失则申请
private fun checkAndRequestPermissions(): Boolean {
    val missingPermissions = requiredPermissions.filter {
        ActivityCompat.checkSelfPermission(this, it) != PackageManager.PERMISSION_GRANTED
    }
    return if (missingPermissions.isNotEmpty()) {
        ActivityCompat.requestPermissions(this, missingPermissions.toTypedArray(), REQUEST_CODE_BLE_PERMISSIONS)
        false
    } else {
        true
    }
}

// 处理权限申请结果
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults)
    if (requestCode == REQUEST_CODE_BLE_PERMISSIONS) {
        val allGranted = grantResults.all { it == PackageManager.PERMISSION_GRANTED }
        if (allGranted) {
            // 权限全部授予,执行扫描操作
            startBleScanSafely()
        } else {
            Toast.makeText(this, "需要BLE相关权限才能正常扫描", Toast.LENGTH_SHORT).show()
        }
    }
}

步骤3:修正BLE操作代码

启动扫描

把权限检查放在操作入口(比如按钮点击事件),只有权限通过后才执行扫描:

// 外部触发扫描的入口(比如按钮点击时调用)
fun onStartScanButtonClicked() {
    if (checkAndRequestPermissions()) {
        startBleScanSafely()
    }
}

// 内部真正执行扫描的函数,确保此时权限已全部授予
private fun startBleScanSafely() {
    bleScanner.startScan(scanFilters, scanSettings, scanCallback)
}

停止扫描

修正代码中的错误(startScan改为stopScan),因为只有权限授予后才会启动扫描,所以这里无需重复检查权限:

private fun stopBleScan() {
    bleScanner.stopScan(scanCallback)
}

获取设备名称

只要申请了对应权限(Android 12+的BLUETOOTH_CONNECT,低版本的位置权限),就可以正常获取设备名称,IDE不会再提示权限问题:

private val scanCallback = object : ScanCallback() {
    override fun onScanResult(callbackType: Int, result: ScanResult) {
        with(result.device) {
            Log.i("ScanCallback", "设备名称:$name") // 现在可以正常运行
            foundDevice = true
        }
    }
}

关键注意点

  1. 所有BLE相关操作(扫描、停止扫描、获取设备信息)必须在权限全部授予后执行,避免分散检查权限
  2. 注意Android版本适配,不同版本的权限要求差异较大
  3. 确保Manifest中声明了所有必要权限,否则动态申请会失败

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 08:05:26