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 } } }
关键注意点
- 所有BLE相关操作(扫描、停止扫描、获取设备信息)必须在权限全部授予后执行,避免分散检查权限
- 注意Android版本适配,不同版本的权限要求差异较大
- 确保Manifest中声明了所有必要权限,否则动态申请会失败
内容的提问来源于stack exchange,提问作者Harvey Xie
相关产品推荐
相关产品推荐

