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
想明确三个问题:
- 该现象是否正常?
- 扫描响应数据是否会影响蓝牙状态?
- 是否需要额外编写代码避免?
回答
该现象完全不正常
正常情况下,应用层启停BLE广播和GattServer仅操作蓝牙的BLE子模块,不会触发整个蓝牙模块的重启。出现系统自动重启蓝牙的情况,大概率是设备底层蓝牙栈触发了保护性重启,原因可能是你的启停逻辑存在未正确释放资源的问题,或者参数错误导致底层处理异常。扫描响应数据本身不直接影响蓝牙状态,但格式/长度错误可能触发底层异常
从你提供的代码看,扫描响应数据的拼接存在逻辑问题:ByteArray.plus()会返回新数组,原数组不会被修改,但更关键的是,如果拼接后的制造商数据总长度超出BLE规范限制(单个制造商数据最大247字节,且要考虑广播包整体长度上限),就可能导致蓝牙栈处理失败,甚至触发异常重启。需要优化代码避免,同时排查资源释放逻辑
- 修复扫描响应数据逻辑:确保使用正确拼接后的字节数组,严格控制制造商数据总长度(建议不超过20字节,避免超出单次广播包承载上限);
- 规范GattServer和广播的启停流程:
- 停止GattServer时必须调用
close()释放所有连接和资源; - 停止广播时要确保
stopAdvertising()执行完成,可通过回调确认状态后再进行下一次操作; - 添加状态标志(如
isRunning),避免短时间内频繁重复调用启停方法;
- 停止GattServer时必须调用
- 增加错误监听:在
mAdvertisingCallback中实现onStartFailure(),捕获广播启动失败的错误码,排查参数或资源冲突问题; - 适配三星设备特性:部分三星设备蓝牙栈容错性较低,启动广播前先检查蓝牙适配器状态是否为
STATE_ON,避免在状态不稳定时操作。
内容的提问来源于stack exchange,提问作者Niral Bhavsar
相关产品推荐
相关产品推荐

