如何在Android中扫描使用Extended Advertisement和Coded PHY的BLE设备?
解决Android应用扫描Extended Advertisement+Coded PHY BLE设备的问题
针对你的情况,nRF Connect能扫到目标外设但自定义应用不行,核心问题出在ScanSettings配置缺失和权限验证环节,以下是具体修复步骤:
1. 修正ScanSettings配置
Android默认仅扫描传统BLE广播(Legacy模式),你的当前配置未开启Extended Advertisement支持。需在ScanSettings.Builder中添加setLegacy(false):
private val scanSettings = ScanSettings.Builder() .setScanMode(ScanSettings.SCAN_MODE_BALANCED) .setPhy(ScanSettings.PHY_LE_ALL_SUPPORTED) .setLegacy(false) // 关键:禁用传统模式,开启Extended Advertisement扫描 .build()
PHY_LE_ALL_SUPPORTED已包含Coded PHY(LE_CODED),无需额外修改,但必须显式关闭Legacy模式才能接收Extended广播包。
2. 确保权限配置正确
Android 12+对BLE扫描有严格权限要求,检查Manifest文件:
<!-- 声明BLE硬件依赖 --> <uses-feature android:name="android.hardware.bluetooth_le" android:required="true" /> <!-- BLE核心权限 --> <uses-permission android:name="android.permission.BLUETOOTH" android:maxSdkVersion="30" /> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" android:maxSdkVersion="30" /> <uses-permission android:name="android.permission.BLUETOOTH_SCAN" android:usesPermissionFlags="neverForLocation" />
同时必须动态申请BLUETOOTH_SCAN权限(危险权限),启动扫描前需确保权限已授予:
// 示例:用ActivityResultLauncher发起权限请求 private val requestScanPermissionLauncher = registerForActivityResult( ActivityResultContracts.RequestPermission() ) { isGranted -> if (isGranted) { // 权限通过,启动扫描 startBleScan() } else { Log.e("BLE", "扫描权限未授予") } } // 调用权限请求 if (ContextCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH_SCAN) != PackageManager.PERMISSION_GRANTED) { requestScanPermissionLauncher.launch(Manifest.permission.BLUETOOTH_SCAN) }
3. 完善ScanCallback排查问题
添加onScanFailed方法,快速定位扫描失败原因(如权限不足、硬件不支持等):
private val scanCallback = object : ScanCallback() { @SuppressLint("MissingPermission") override fun onScanResult(callbackType: Int, result: ScanResult?) { result?.let { val isExtended = it.isAdvertisementExtended val phyType = when(it.phy) { ScanSettings.PHY_LE_1M -> "1M" ScanSettings.PHY_LE_2M -> "2M" ScanSettings.PHY_LE_CODED -> "Coded" else -> "Unknown" } Log.d("BLE", "发现设备:${it.device.address} | 扩展广播:$isExtended | PHY:$phyType") } } override fun onScanFailed(errorCode: Int) { val errorMsg = when(errorCode) { SCAN_FAILED_ALREADY_STARTED -> "扫描已启动" SCAN_FAILED_APPLICATION_REGISTRATION_FAILED -> "应用注册失败" SCAN_FAILED_FEATURE_UNSUPPORTED -> "硬件不支持该特性" SCAN_FAILED_INTERNAL_ERROR -> "内部错误" else -> "未知错误:$errorCode" } Log.e("BLE", "扫描失败:$errorMsg") } }
4. 额外验证项
- 确认Android设备蓝牙已完全启用(可通过
BluetoothAdapter.isEnabled()检查) - 避免后台扫描被系统限制:若需后台扫描,需添加
ACCESS_BACKGROUND_LOCATION权限(若应用依赖位置),或确保扫描处于前台生命周期内
内容的提问来源于stack exchange,提问作者Jonas
相关产品推荐
相关产品推荐

