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

Android同时开启BLE广播与GattServer时蓝牙状态自动重启问题

问题

我开发的应用需要同时开启BLE广播和GattServer,在三星M32(Android 12)设备上,多次点击按钮调用启停方法后,蓝牙状态会自动异常切换——系统自动重启蓝牙,触发STATE_OFF后又触发STATE_ON。

已注册蓝牙状态监听的广播接收器,代码如下:

private val mBluetoothAdapterPowerStateReceiver: BroadcastReceiver =
        object : BroadcastReceiver() {
            override fun onReceive(context: Context, intent: Intent) {
                val action = intent.action
                if (action == BluetoothAdapter.ACTION_STATE_CHANGED) {
                    val state = intent.getIntExtra(
                        BluetoothAdapter.EXTRA_STATE,
                        BluetoothAdapter.ERROR
                    )
                    when (state) {
                        BluetoothAdapter.STATE_OFF -> Log.d(TAG, "GantnerBLEAdapter: STATE_OFF")
                        BluetoothAdapter.STATE_TURNING_OFF -> Log.d(TAG, "GantnerBLEAdapter: STATE_TURNING_OFF")
                        BluetoothAdapter.STATE_ON -> Log.d(TAG, "GantnerBLEAdapter: STATE_ON")
                        BluetoothAdapter.STATE_TURNING_ON -> Log.d(TAG, "GantnerBLEAdapter: STATE_TURNING_ON")
                    }
                }
            }
        }

注册代码:

val filter = IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED)
 activity.registerReceiver(mBluetoothAdapterPowerStateReceiver, filter)

启停方法:

fun startAdvertisementAndServer(){
        gantnerGattServer.startAdvertising()
        gantnerGattServer.startServer()
    }

    fun stopAdvertisementAndServer(){
        gantnerGattServer.stopServer()
        gantnerGattServer.stopAdvertising()
    }

应用配置minSdk 21、targetSdk 33,已申请必要蓝牙权限:

<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />
<uses-permission android:name="com.google.android.gms.permission.AD_ID" />
<uses-permission
    android:name="android.permission.BLUETOOTH_SCAN"
    android:usesPermissionFlags="neverForLocation" />

怀疑问题源于扫描响应数据,相关代码:

val manufacturerDataKotlin = ByteArray(1)
        manufacturerDataKotlin[0] = 0x08

        manufacturerDataKotlin.plus(advInfo.toByteArray()).let {
            Log.d(TAG, "initializeAdvertiser: $it")
            mScanResponseData = AdvertiseData.Builder()
                .addManufacturerData(0x0403, it)
                .build()
        } 

启动广播代码:

mBluetoothLeAdvertiser!!.startAdvertising(
            mAdvertiseSettings,
            mAdvertiseData, mScanResponseData, mAdvertisingCallback

想明确三个问题:

  1. 该现象是否正常?
  2. 扫描响应数据是否会影响蓝牙状态?
  3. 是否需要额外编写代码避免?

回答

  1. 该现象完全不正常
    正常情况下,应用层启停BLE广播和GattServer仅操作蓝牙的BLE子模块,不会触发整个蓝牙模块的重启。出现系统自动重启蓝牙的情况,大概率是设备底层蓝牙栈触发了保护性重启,原因可能是你的启停逻辑存在未正确释放资源的问题,或者参数错误导致底层处理异常。

  2. 扫描响应数据本身不直接影响蓝牙状态,但格式/长度错误可能触发底层异常
    从你提供的代码看,扫描响应数据的拼接存在逻辑问题:ByteArray.plus()会返回新数组,原数组不会被修改,但更关键的是,如果拼接后的制造商数据总长度超出BLE规范限制(单个制造商数据最大247字节,且要考虑广播包整体长度上限),就可能导致蓝牙栈处理失败,甚至触发异常重启。

  3. 需要优化代码避免,同时排查资源释放逻辑

  • 修复扫描响应数据逻辑:确保使用正确拼接后的字节数组,严格控制制造商数据总长度(建议不超过20字节,避免超出单次广播包承载上限);
  • 规范GattServer和广播的启停流程:
    • 停止GattServer时必须调用close()释放所有连接和资源;
    • 停止广播时要确保stopAdvertising()执行完成,可通过回调确认状态后再进行下一次操作;
    • 添加状态标志(如isRunning),避免短时间内频繁重复调用启停方法;
  • 增加错误监听:在mAdvertisingCallback中实现onStartFailure(),捕获广播启动失败的错误码,排查参数或资源冲突问题;
  • 适配三星设备特性:部分三星设备蓝牙栈容错性较低,启动广播前先检查蓝牙适配器状态是否为STATE_ON,避免在状态不稳定时操作。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 10:52:07