Android扫描BLE设备时onScanResult回调未触发问题求助
1. 缺失Android 12(API 31+)专属蓝牙权限
当前的权限声明仅适配Android 11及以下版本,API 31以上系统新增了蓝牙相关的危险权限,必须在AndroidManifest.xml中补充声明:
<!-- Android 12+ 蓝牙扫描权限 --> <uses-permission android:name="android.permission.BLUETOOTH_SCAN" android:usesPermissionFlags="neverForLocation" /> <!-- Android 12+ 蓝牙连接权限 --> <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
如果应用有基于蓝牙获取位置的需求,可以去掉android:usesPermissionFlags="neverForLocation"属性。
2. 未实现危险权限动态申请逻辑
Android 6.0(API 23)以上,位置权限、Android12+的蓝牙扫描权限都属于危险权限,仅在Manifest声明无效,必须在运行时主动向用户申请授权,未授权的情况下扫描会直接静默失败,无回调返回。需要在启动扫描前增加权限校验和申请逻辑,示例代码:
// 权限申请请求码 private val REQUEST_BLE_PERMISSIONS = 1001 private fun checkBlePermissions(): Boolean { val requiredPermissions = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { arrayOf( Manifest.permission.BLUETOOTH_SCAN, Manifest.permission.BLUETOOTH_CONNECT, Manifest.permission.ACCESS_FINE_LOCATION ) } else { arrayOf( Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.BLUETOOTH, Manifest.permission.BLUETOOTH_ADMIN ) } // 检查权限是否已全部授予 val allGranted = requiredPermissions.all { ContextCompat.checkSelfPermission(this, it) == PackageManager.PERMISSION_GRANTED } return if (!allGranted) { // 未授予则申请权限 ActivityCompat.requestPermissions(this, requiredPermissions, REQUEST_BLE_PERMISSIONS) false } else { true } } // 处理权限申请结果 override fun onRequestPermissionsResult( requestCode: Int, permissions: Array<out String>, grantResults: IntArray ) { super.onRequestPermissionsResult(requestCode, permissions, grantResults) if (requestCode == REQUEST_BLE_PERMISSIONS) { val allGranted = grantResults.all { it == PackageManager.PERMISSION_GRANTED } if (allGranted) { // 权限通过后再启动扫描 startBleScan() } } }
3. Activity onCreate重载错误
当前重写的是双参数的onCreate(savedInstanceState: Bundle?, persistentState: PersistableBundle?),这个重载需要在Manifest中给对应Activity配置android:persistableMode="persistAcrossReboots"才会被触发,正常启动场景下不会走该方法,页面初始化逻辑完全没有执行。需要替换为单参数的标准onCreate:
override fun onCreate(savedInstanceState: Bundle?) { Log.d("DeviceListActivity", "onCreate()") super.onCreate(savedInstanceState) setContentView(R.layout.activity_device_list) }
4. 位置开关状态未做异常处理
当前的enableLocation方法仅返回了位置开关是否开启的状态,但没有处理「位置开关未开启」的场景,也没有引导用户跳转系统设置开启位置,Android 11及以下版本BLE扫描强制要求位置开关开启,否则不会返回扫描结果。需要在该方法返回false时弹窗引导用户开启位置。
5. 未显式指定扫描配置(适配兼容性问题)
部分国产ROM对BLE扫描做了限制,默认无参数的startScan可能会被限流或者静默拦截,建议显式传入扫描过滤器和扫描设置,指定高优先级扫描模式:
private fun startBleScan() { val scanner = bluetoothLeScanner // 扫描设置:低延迟模式,适合前台主动扫描 val scanSettings = ScanSettings.Builder() .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY) .build() // 可自定义过滤器,无特殊需求传空列表即可扫描所有BLE设备 scanner.startScan(emptyList(), scanSettings, bleScanner) }
将onStart中的bluetoothLeScanner.startScan(bleScanner)替换为调用上述startBleScan方法即可。
6. 未做蓝牙适配器有效性校验
如果设备不支持蓝牙、或者蓝牙未开启,bluetoothLeScanner可能返回null,直接调用扫描方法会抛出异常,建议在启动扫描前先判断蓝牙适配器是否可用,以及蓝牙是否已开启,未开启的话引导用户开启蓝牙。
内容的提问来源于stack exchange,提问作者user16627306

