安卓:自动重新连接蓝牙设备

10

我的目标是让Android设备在没有任何用户干预的情况下,以经典蓝牙已配对设备的方式重新连接到之前连接过的BLE设备(即使在电源循环期间也能正常工作)。

BTLE设备的一个优点是可以保存服务、绑定和启用状态,从而使重新连接非常快速,并且在外设上消耗的电量很小。

我所做的事情似乎有效,但效果很差。

第一步是连接或配对并连接到新设备,将“autoconnect”参数设置为“true”。 当设备断开连接时,不要调用gatt.close()。 我到处查找都看到应该调用gatt.close(),但如果我调用gatt.close(),Android中央应用程序就永远无法重新连接。我已经测试了多次。

如果我没有调用gatt.close()也没有对Android进行电源循环,则自动连接通常会发生。有时可能需要很长时间,特别是在版本5.0之后。但这种方法不可靠,可能由于扫描周期非常低和设备在扫描周期实际检测到广告之前退出广告造成的。我不确定,因为没有办法像广告那样检测扫描操作!扫描也可能在一定时间后停止,但没有文档记录这一点。

因此,我认为需要做的是以某种方式将Android使用的后台扫描速率设置为更高的占空比(仅适用于5.0及更高版本),当已设置自动连接时。但我不知道该怎么做。我不想开始自己的扫描,而是希望以某种方式设置Android用于重新连接的后台扫描速率。 有人知道如何做到这一点吗? 有人真正了解autoconnect和gatt.close()的工作原理吗?

也许auto-connect并不是像我上面所说的那样重新连接的?


对于重新连接,您将始终需要进行广告或扫描。此外,您是否尝试在核心规范中找到此内容?您提出的许多问题都在其中,例如“将背景扫描速率设置为更高的占空比”,您可能指的是扫描窗口和间隔,这些参数通过设置扫描参数来处理。广告类型也很重要(无连接,可连接)。请提供处理主设备和外围设备上的扫描/广告的代码部分。 - Zimano
@Zimano我已经了解了核心规范。我编写过嵌入式BLE收集器,其中必须指定所有这些细节。然而,在Android平台上,人们通常拥有较少的控制权(通常会使生活更加轻松),并且通常不知道Android在幕后做了什么。我不知道的是,当我将autoconnect参数设置为true时,Android配置其扫描速率为多少。它可能是低占空比,并且随着外围设备的断开连接,它可能会发生变化。因此,我想知道如何将该扫描速率配置为更高的占空比。 - Brian Reinhold
@Zimano,我想了解一下扫描速率是多少(不用深入源代码)。我有很多医疗设备外围设备,它们都以不同的速率进行广告(很少有指定),但这些可以通过嗅探器轻松查看。 - Brian Reinhold
我不同意扫描参数是“微小细节”的说法,它们是基本的。较少的控制会导致问题,就像您所经历的那样。虽然我不是安卓蓝牙的粉丝><,但是您可以随时跟踪任何操作或者深入源代码进行调试。但是我离题了。我认为您正在寻找这个或这个。看看是否有帮助:)? - Zimano
@Zimano 好的,我所说的“细节”不是指那种小问题。我的意思是在大多数高级API中,应用程序编写者被屏蔽了所有这些细节(如Android),但我们必须指定它们。对于使用Windows系统的我们来说获取源码要困难得多,尽管我正在考虑这个头痛的问题。我听说可以使用Android Studio浏览AOSP。 - Brian Reinhold
2个回答

5

经过多次尝试和困难,以下是我最好的方式让Android自动连接,仅需用户首先选择设备(如果使用设置菜单,则需要首先配对)。

您需要在BroadcastReceiver中捕获已配对事件,并执行BluetoothDevice.connectGatt()将自动连接设置为true。然后,当设备断开连接时,调用gatt.connect()。

更新:虽然上述方法通常有效,但由于挂起连接使用非常保守的扫描速率,因此有时速度极慢。另一个缺点是,对于每个要自动重新连接的设备,您必须保留执行挂起连接的BluetoothGatt对象。在嵌入式世界中,这是不可行的。相反,人们会持续扫描并通过检查其广告来连接所需的设备。您只保存有关设备的最少量数据(服务、配对状态和密钥等)。捕获广告后,如果它是您已知的设备之一,则连接到该设备。 我在Android上试过了等效方法。全天候扫描(低功率率)并连接到感兴趣的广告,并维护表示已知设备的类。这种方法存在一些烦人的细节(例如在连接时关闭扫描并在连接后重新启动),但基本上可以在不需要维护连接负担的情况下正常工作。但是,有一个我不理解的例外。一个预配对设备的广告从未被扫描器看到过。然而,如果我调用挂起连接到该设备,我会重新连接。我完全不理解这一点。在我的嵌入式平台上,它按照应有的方式工作。 如果其他人尝试了这种自动重连方法,请分享您的经验!

我发现预配对设备没有被Android看到的原因。 Android仅在设备响应扫描请求时报告扫描结果。一旦配对,此设备仅发出广告并忽略扫描请求,因此Android系统不会在ScanCallback中传递其广告。因此,为了使用扫描方法工作,我必须对这些特定设备使用挂起连接方法。似乎你无法胜利!

============= 2020年更新

多年过去了,我对后台扫描方法有更多经验。如果保持支持的平台为5及以上,则可以仅使用最新的扫描器API和筛选器,消除了自己解码原始广告的需要。我还发现,如果您在连接时不关闭扫描,则连接和重新连接速度更快。我知道这与所有文档相违背,但它确实有效,并且在某些平台上允许发生否则不会发生的连接。此外,截至目前,我只发现了一个(健康)设备需要挂起连接。免责声明:我所使用的所有设备都是健康设备。


2
@Brian,能否提供一份示例代码呢?这对我们来说将是巨大的帮助。 - Shahid Sarwar
哦,天啊。为什么我没有收到这条评论的通知?它已经一年了! - Brian Reinhold
@BrianReinhold.. "然后当设备断开连接时,调用gatt.connect()"。你是不是想说"gatt.disconnect()"...? - elcuco
1
@Elcuco 在我的情况下,我正在与一个健康设备通信,该设备负责发送大约95%的断开连接。为了在没有用户干预的情况下重新连接,我需要启动一个挂起的连接。如果我不这样做,当设备重新上线(暴露广告)时,我将无法自动重新连接到该设备。 - Brian Reinhold
BluetoothGatt对象本身不占用特定数量的RAM。更有趣的是最大挂起连接数非常低(如10),而大多数控制器支持128。请注意,10只是Android源代码中的一个常量,可以将其设置得更高而不会出现任何问题。自动连接而不是扫描+连接的一个好处是可以在不需要唤醒主CPU处理每个广告数据包的情况下完成广告过滤和连接建立,从而节省电池电量。与嵌入式系统相比,其中所有内容都在同一CPU上运行。 - Emil
显示剩余7条评论

0
这是我在我的应用程序中实现它的方法。 我首先将设备的地址存储在SharedPreference中,然后在BluetoothLeService的gattClientCallback函数中使用它。
else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
            intentAction = ACTION_DISCONNECTED;


            DeviceActivity.runOnUI(() -> {

                sharedPreferences  = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());

             String  name_dev_1 = sharedPreferences.getString("Dev_1", null) ;

              connectToDevice(name_dev_1);

                disconnectGattServer();
            });
        }
    }

这个程序的作用是,如果您的设备断开连接,它会不断尝试重新连接,直到建立连接为止。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接