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

Android使用BluetoothLeAdvertiser基于BLE 2M PHY广播数据,扫描无结果排查

BLE 2M PHY扫描无结果问题排查

我正在开发一款基于低功耗蓝牙(BLE)广播的聊天应用,参考Android官方BLE广播教程实现客户端,但我的BluetoothLeScanner无法获取任何BLE 2M PHY的扫描结果。使用nRF Connect应用可正常实现预期效果,因此基本排除硬件问题。以下是我的广告端实现代码:

class BluetoothAdvertiser(private var bluetoothAdapter: BluetoothAdapter) {
    private val TAG: String = BluetoothAdvertiser::class.java.simpleName
    private var advertiseUUID: ParcelUuid =
        ParcelUuid(UUID.fromString("e889813c-5d19-49e2-8bc4-d4596b4f5250"))
    private var advertiser: BluetoothLeAdvertiser = bluetoothAdapter.bluetoothLeAdvertiser
    private var maxDataLength: Int = 0
    private lateinit var currentAdvertisingData: AdvertiseData
    private lateinit var currentAdvertisingSet: AdvertisingSet

    fun init(): Boolean {
        Log.d(TAG, "init: ")
        if (!this.checkDeviceHardware()) {
            return false
        }
        this.initAdvertiser("123")
        return true
    }


    private fun checkDeviceHardware(): Boolean {
        if (!this.bluetoothAdapter.isLe2MPhySupported) {
            Log.e(TAG, "init: 2M PHY not supported")
            return false
        }
        if (!this.bluetoothAdapter.isLeExtendedAdvertisingSupported) {
            Log.e(TAG, "init: LE Extended Advertising not supported")
            return false
        }
        this.maxDataLength = this.bluetoothAdapter.leMaximumAdvertisingDataLength
        Log.d(TAG, "init: leMaximumAdvertisingDataLength: " + this.maxDataLength)
        return true
    }

    private fun initAdvertiser(message: String): Boolean {
        val setParameters: AdvertisingSetParameters = AdvertisingSetParameters.Builder()
            .setLegacyMode(false)
            .setInterval(AdvertisingSetParameters.INTERVAL_HIGH)
            .setTxPowerLevel(AdvertisingSetParameters.TX_POWER_MEDIUM)
            .setPrimaryPhy(BluetoothDevice.PHY_LE_CODED)
            .setSecondaryPhy(BluetoothDevice.PHY_LE_2M)
            .build()
        val advertiseData: AdvertiseData = AdvertiseData.Builder()
            .setIncludeDeviceName(true)
            .addServiceUuid(advertiseUUID)
            .addServiceData(advertiseUUID, message.encodeToByteArray())
            .build()
        val periodicParameters: PeriodicAdvertisingParameters = PeriodicAdvertisingParameters.Builder()
            .setInterval(800)
            .build()
        return try {
            this.advertiser.startAdvertisingSet(
                setParameters,
                advertiseData,
                advertiseData,
                periodicParameters,
                advertiseData,
                this.advertisingSetCallback
            )
            true
        } catch (e: SecurityException) {
            Log.w(TAG, "initAdvertiser: ",e)
            false
        }
    }

     fun changeAdvertisingData(message: String){
        try{
            Log.d(TAG, "changeAdvertisingData: message: $message" )
            this.currentAdvertisingSet.setAdvertisingData(AdvertiseData.Builder().addServiceData(this.advertiseUUID,message.encodeToByteArray()).build())
        } catch (e: SecurityException) {
            Log.w(TAG, "initAdvertiser: ",e)
        }
    }

    private var advertisingSetCallback: AdvertisingSetCallback = object : AdvertisingSetCallback() {
        override fun onAdvertisingSetStarted(
            advertisingSet: AdvertisingSet,
            txPower: Int,
            status: Int
        ) {
            Log.i(
                TAG, "onAdvertisingSetStarted(): txPower:  $txPower  , status: $status "
            )
            currentAdvertisingSet = advertisingSet
        }

        override fun onAdvertisingSetStopped(advertisingSet: AdvertisingSet) {
            Log.i(TAG, "onAdvertisingSetStopped():")
        }
    }
}

问题分析与解决方案

核心问题点

  1. 广告端主PHY配置:当前代码将主PHY设为PHY_LE_CODED,如果扫描端未配置支持该PHY,将无法接收广告包。
  2. 扫描端PHY配置缺失:未提供扫描端代码,但大概率是扫描时未指定支持2M和CODED PHY,导致无法匹配广告端的PHY设置。

具体修复步骤

1. 广告端验证与调整

  • 检查onAdvertisingSetStarted回调中的status值:若status为0则广告启动成功,非0需对应排查错误码(如ADVERTISE_FAILED_DATA_TOO_LARGE表示数据超限)。
  • 可尝试将主PHY改为PHY_LE_2M测试:
    val setParameters: AdvertisingSetParameters = AdvertisingSetParameters.Builder()
        // ...其他配置
        .setPrimaryPhy(BluetoothDevice.PHY_LE_2M)
        .setSecondaryPhy(BluetoothDevice.PHY_LE_2M)
        .build()
    

2. 扫描端关键配置补充

确保扫描时配置支持所有所需PHY:

// 构建扫描设置
val scanSettings = ScanSettings.Builder()
    .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY) // 根据需求选择扫描模式
    .setPhy(ScanSettings.PHY_LE_ALL) // 覆盖所有支持的PHY,或明确指定PHY_LE_2M | PHY_LE_CODED
    .build()

// 启动扫描
bluetoothAdapter.bluetoothLeScanner.startScan(null, scanSettings, object : ScanCallback() {
    override fun onScanResult(callbackType: Int, result: ScanResult?) {
        super.onScanResult(callbackType, result)
        // 处理扫描结果
        result?.let {
            Log.d("Scan", "Found device: ${it.device.name}, PHY: ${it.phy}")
        }
    }
})

3. 权限与系统配置检查

  • Android 12及以上版本需申请BLUETOOTH_SCAN权限(在Manifest中声明,并动态申请)。
  • 部分设备需开启位置权限才能正常扫描BLE设备。

内容的提问来源于stack exchange,提问作者Internetus

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 16:25:19