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

Android BLE后台连接疑问:电子锁场景下WorkManager适配问题

问题求助:基于BLE的电子锁自动解锁应用开发

背景

核心需求是开发一款电子锁,将手机通过BLE连接作为解锁钥匙,实现手机靠近时自动解锁。

需求

需要开发一款能在手机靠近BLE设备时自动连接的应用,该应用需在后台运行。作为Android/Kotlin新手,查阅官方文档后考虑使用WorkManager。

遇到的问题

  • 不清楚应用被用户关闭时,BLE与WorkManager的交互表现;
  • Worker的doWork()方法中仅设置BLE回调(通过BluetoothDevice.connectGatt()),无耗时操作,导致该方法执行极快;
  • 当BLE设备已连接时,若用户关闭应用,设备会自动断开连接。

BLE连接情况

BLE连接本身无问题,使用BluetoothDevice.connectGatt()并将autoConnect参数设为true,BluetoothGattCallback.onConnectionStateChange()回调能正常触发连接或断开事件。

WorkManager表现测试

为了解WorkManager的行为,在Worker的doWork()方法中添加了1分钟延迟Thread.sleep(60000),观察到以下现象:

  1. 当Worker运行时调用WorkManager.cancelAllWorkByTag():
    • Worker的onStopped()会被调用,但Worker仍继续运行;
  2. 当Worker运行且BLE设备已连接,用户关闭应用时:
    • Worker被停止;
    • BLE设备断开连接;
    • 一分钟后Worker恢复运行,BLE回调(连接/断开)恢复正常,甚至在Worker运行结束后仍能工作。

未优化的Worker代码

class BleWorker(
    appContext: Context,
    workerParams: WorkerParameters
) : Worker(appContext, workerParams) {

    private val bluetoothManager: BluetoothManager = applicationContext.getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
    private var bleDevice: BluetoothDevice? = null
    private var bluetoothGatt: BluetoothGatt? = null


    private val SERV_UUID = UUID.fromString("44707b20-3459-11ee-aea4-0800200c9a66")
    private val CHAR_UUID_UNLOCK = UUID.fromString("44707b21-3459-11ee-aea4-0800200c9a66")
    private val CHAR_UUID_STATE = UUID.fromString("44707b22-3459-11ee-aea4-0800200c9a66")

    private var service: BluetoothGattService? = null
    private var charUnlock: BluetoothGattCharacteristic? = null
    private var charState: BluetoothGattCharacteristic? = null

    init {
        Log.i("learnBle","BleWorker ($id:$tags) init" )
    }

    protected fun finalize() {
        Log.i("learnBle","BleWorker ($id) finalize" )
    }

    override fun onStopped() {
        Log.i("learnBle","BleWorker ($id) onStopped" )
        super.onStopped()
    }


    override fun doWork(): Result {
        var result: Result
        try {
            Log.i("learnBle","BleWorker ($id) doWork started" )

            bleDevice = bluetoothManager.adapter.bondedDevices.find {
                it.address == BLE_ADD
            }

            if (bleDevice != null)
            {
                bluetoothGatt = bleDevice!!.connectGatt(
                    applicationContext,
                    true,
                    gattCallback_auto2)
            }
            else
            {
                Log.i("learnBle","BleWorker ($id) doWork no device bonded !" )
                Result.failure()
            }

            Thread.sleep(60000)
            Log.i("learnBle","BleWorker ($id) doWork ended" )
            result = Result.success()
        } catch (e: Exception)
        {
            Log.i("learnBle","BleWorker ($id) doWork ended with FAILURE" )
            result = Result.failure()
        }

        return result
    }


    private val gattCallback_auto2: BluetoothGattCallback = object : BluetoothGattCallback() {
        override fun onConnectionStateChange(gatt: BluetoothGatt?, status: Int, newState: Int) {
            super.onConnectionStateChange(gatt, status, newState)

            if (    status == BluetoothGatt.GATT_SUCCESS
                &&  newState == BluetoothGatt.STATE_CONNECTED) {

                val ret = gatt!!.discoverServices()
                Log.i("learnBle","BleWorker:Callback ($id) auto discover services starting:$ret" )
            }
            else {
                Log.i("learnBle","BleWorker:Callback ($id) auto Connexion failed !" )
            }
        }

        override fun onServicesDiscovered(gatt: BluetoothGatt?, status: Int) {
            super.onServicesDiscovered(gatt, status)

            // Note: Here gatt == bluetoothGatt
            val services = gatt?.services

            service = gatt?.getService(SERV_UUID)
            charUnlock = service?.getCharacteristic(CHAR_UUID_UNLOCK)
            charState = service?.getCharacteristic(CHAR_UUID_STATE)

            // Unlock
            if (charUnlock != null) {
                val value = byteArrayOf(0x01)
                gatt?.writeCharacteristic(
                    charUnlock!!,
                    value,
                    BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT)

                Log.i("learnBle","BleWorker:Callback ($id) unloked !" )
            }
        }
    }
}

求助问题

  1. WorkManager是否适合我的需求场景?
  2. 为了让Worker在应用关闭后仍能在后台运行,我是否需要用无限等待替代Thread.sleep(60000)?有没有更合理的实现方式?
  3. 如何避免用户关闭应用时BLE设备自动断开连接?

感谢您的帮助!


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 20:52:13