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

Android扫描BLE设备时onScanResult回调未触发问题求助

BLE扫描无回调的遗漏配置&逻辑修复点

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 19:24:03