BLE扫描报错代码2,添加BLUETOOTH_SCAN权限仍无法解决
BLE扫描失败错误代码2的修复方案
一、核心问题定位
错误代码2对应BluetoothAdapter.ERROR_PERMISSION_DENIED,本质是权限未正确配置或授予;Manifest中BLUETOOTH_SCAN的警告是因为targetSdkVersion未与compileSdkVersion同步为34导致的API版本兼容性提示。
二、分步修复
1. 同步build.gradle的SDK版本
确保Module级build.gradle中compileSdk和targetSdk都设置为34,消除权限声明警告:
android { compileSdk 34 defaultConfig { // 其他配置不变 targetSdk 34 // 必须与compileSdk版本一致 ... } }
2. 修正AndroidManifest.xml权限声明
针对API31+(Android 12及以上)的BLE扫描需求,添加正确的权限组合:
<!-- 旧版本(API30及以下)兼容权限 --> <uses-permission android:name="android.permission.BLUETOOTH" android:maxSdkVersion="30" /> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" android:maxSdkVersion="30" /> <!-- API31+ 扫描权限:如果需要获取iBeacon的UUID/Major/Minor,不要加neverForLocation标志 --> <uses-permission android:name="android.permission.BLUETOOTH_SCAN" /> <!-- 仅扫描基础设备信息时可添加:android:usesPermissionFlags="neverForLocation" --> <!-- 获取BLE广播完整数据(如UUID)必须的位置权限 --> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <!-- 后台扫描需求(可选):API29-32需声明,API33+需配合后台服务 --> <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" android:maxSdkVersion="32" /> <!-- 声明App依赖BLE硬件 --> <uses-feature android:name="android.hardware.bluetooth_le" android:required="true" />
3. 动态申请危险权限
BLUETOOTH_SCAN和ACCESS_FINE_LOCATION都是危险权限,必须在运行时申请,用户授权后才能启动扫描:
// 示例:Kotlin权限申请逻辑 private val requestPermissionsLauncher = registerForActivityResult( ActivityResultContracts.RequestMultiplePermissions() ) { permissions -> val allGranted = permissions.all { it.value } if (allGranted) { // 权限全部授予,启动BLE扫描 startBleScan() } else { // 提示用户开启权限 Toast.makeText(this, "需授予权限才能扫描BLE设备", Toast.LENGTH_SHORT).show() } } // 触发权限检查与申请 fun checkPermissions() { val requiredPermissions = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { arrayOf( Manifest.permission.BLUETOOTH_SCAN, Manifest.permission.ACCESS_FINE_LOCATION ) } else { arrayOf( Manifest.permission.BLUETOOTH_ADMIN, Manifest.permission.ACCESS_FINE_LOCATION ) } val needRequest = requiredPermissions.any { ContextCompat.checkSelfPermission(this, it) != PackageManager.PERMISSION_GRANTED } if (needRequest) { requestPermissionsLauncher.launch(requiredPermissions) } else { startBleScan() } }
4. 确保蓝牙与位置服务开启
- 扫描前检查蓝牙状态,未开启则引导用户打开:
val bluetoothAdapter = BluetoothAdapter.getDefaultAdapter() if (bluetoothAdapter == null || !bluetoothAdapter.isEnabled) { val enableBtIntent = Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE) startActivityForResult(enableBtIntent, 1001) }
- 开启位置服务:即使设备不需要GPS定位,Android 10+也要求开启位置服务才能获取BLE设备的完整广播数据(如UUID、Major/Minor)。
5. 修正扫描回调的解析逻辑
如果权限配置正确但仍返回空值,检查ScanCallback中广播数据的解析逻辑是否正确,示例iBeacon数据解析:
@Override public void onScanResult(int callbackType, ScanResult result) { super.onScanResult(callbackType, result); ScanRecord record = result.getScanRecord(); if (record == null) return; byte[] scanBytes = record.getBytes(); // 验证iBeacon广播格式(前缀0x02 0x15) if (scanBytes.length >= 25 && scanBytes[0] == 0x02 && scanBytes[1] == 0x15) { // 提取UUID byte[] uuidBytes = Arrays.copyOfRange(scanBytes, 2, 18); String uuid = bytesToUuid(uuidBytes); // 提取Major/Minor int major = ((scanBytes[18] & 0xFF) << 8) | (scanBytes[19] & 0xFF); int minor = ((scanBytes[20] & 0xFF) << 8) | (scanBytes[21] & 0xFF); // 提取RSSI、TxPower int rssi = result.getRssi(); int txPower = scanBytes[22]; long timestamp = System.currentTimeMillis(); // 组装JSON数据 Map<String, Object> bleData = new HashMap<>(); bleData.put("uuid", uuid); bleData.put("major", major); bleData.put("minor", minor); bleData.put("rssi", rssi); bleData.put("txPower", txPower); bleData.put("timestamp", timestamp); // 添加到结果列表 } } private String bytesToUuid(byte[] bytes) { StringBuilder sb = new StringBuilder(); for (int i = 0; i < bytes.length; i++) { sb.append(String.format("%02X", bytes[i])); if (i == 3 || i == 5 || i == 7 || i == 9) sb.append("-"); } return sb.toString().toLowerCase(); }
三、验证步骤
- 确认build.gradle的
compileSdk和targetSdk均为34 - 检查Manifest权限声明符合上述要求
- 运行App,确认权限申请弹窗出现并授权
- 开启蓝牙和位置服务
- 启动扫描,检查JSON数据是否包含有效UUID、RSSI等信息
内容的提问来源于stack exchange,提问作者CUCOOPE
相关产品推荐
相关产品推荐

