如何进行蓝牙LE后台连接?

问题描述 投票:0回答:1

抱歉我的英语不好。

背景

我的主要目标是构建一个电子锁,钥匙是通过 BLE 连接的手机。手机靠近必须解锁。

我想做的事

当手机靠近时,该应用程序会自动连接到 BLE 设备。 因此,应用程序需要在后台运行。但我是 android/Kotlin 的初学者。我看了google的官方培训,正在考虑使用WorkManager。

存在的问题

  • 我不明白当用户关闭应用程序时 BLE 与 WorkManager 的行为。
  • 在 Worker 的
    doWork()
    函数中,我没有放置任何需要 CPU 时间的东西。只需设置一个回调 BLE(使用
    BluetoothDevice.connectGatt()
    )。所以,
    doWork()
    执行得很快。
  • 如果有设备连接并且用户关闭应用程序,该设备将自动断开连接。

BLE 连接

我对 BLE 连接没有任何问题。为此,我使用

BluetoothDevice.connectGatt()
(view doc) 以及
autoConnect
参数为 true。当设备连接或连接丢失时正确调用回调
BluetoothGattCallback.onConnectionStateChange()
(查看文档)

WorkManager 行为

为了尝试了解 WorkManager 的行为,我在

Thread.sleep(60000)
doWork()
函数中添加了 1 分钟延迟
Worker
。这是我注意到的:

  1. Worker
    运行时(在我的例子中是最后一分钟)并且
    WorkManager.cancelAllWorkByTag()
    被调用:
    • onStopped()
      Worker
      被调用,但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 !" )
            }
        }
    }
}

你能帮我吗?

  • WorkManager
    这是解决我的问题的好方法吗?
  • 要在后台运行
    Worker
    (关闭应用程序后),我应该将
    Thread.sleep(60000)
    替换为等待无限时间的东西。真奇怪。否则怎么办?
  • 如何避免用户关闭应用程序时与BLE设备断开连接?

谢谢您的帮助。

android kotlin android-workmanager android-background android-ble
1个回答
0
投票

Android和iOS可以在系统检测到BLE广告时触发应用程序功能。检查 android 库:Android Beacon Library

是的,您不需要使用后台服务或类似的东西😎

© www.soinside.com 2019 - 2024. All rights reserved.