当前位置: 首页 > 知识库问答 >
问题:

Android上的BLE(低功耗蓝牙),创建并重新连接到并不总是存在的设备

柳宾实
2023-03-14

我想用BLE连接一个OBD2加密狗,它根据汽车状态打开/关闭。按照目前的计划,Android设备本身将一直运行。

我有两种重新连接的选择:

a) 将connectGatt“autoconnect”参数设置为“true”

b)定期扫描设备,直到“我的”MAC出现,然后连接到此设备

我的问题:

>

是否有更好的方法(例如,当出现新的BLE设备时,系统广播等)来减少扫描并立即打开设备,或者至少开始扫描?

此外

对于这样的任务,哪个版本的Android足够可靠?我读到BLE实现一开始并不可靠;)

共有2个答案

公孙和怡
2023-03-14

这个问题更适合超级用户网络,因为这不是编程问题。

回答您的问题:

“自动连接”有多可靠?

如果你知道如何使用自动连接,它是可靠的。要让它作为程序员工作,需要付出相当大的努力才能使其适用于当今大多数Android。你通常应该使用Android7和更高版本来让它工作。有些人可能会认为Android6已经足够了。我不这么认为。有一个已知的种族条件和解决方法(来自Polidea guys),但你永远不知道补丁是否已经应用(如果你不是自己编程的话)。

自动连接仅适用于缓存或绑定设备!否则没有机会。它现在通常有效。

为什么人们认为这很难,甚至不工作?如果你想使用/编程它,前面还有一些障碍需要解决。

  • 谷歌的文档非常简单,通常缺乏细节甚至关键信息

是否有更好的方法(例如,当出现新的BLE设备时,系统广播等)来减少扫描并立即打开设备,或者至少开始扫描?

您有两种选择:

>

自动连接设置为true-所需时间比1长。因为Android使用低能量设置进行扫描。autoconnect连接所需的时间因供应商而异。基于使用的低能耗设置(和实施)

自动连接的一大优势是它可以一次发出多个连接。如果自动连接是false,您可以一次发出一个连接。

使用的材料:主要来自Martijn van Welie的博客让Android BLE工作-第1部分和让Android BLE工作-第2部分(我建议阅读这些以了解编程细节!)

韦业
2023-03-14

“自动连接”和扫描“直接连接”之间有一些区别。理想情况下,“自动连接”是我们想要的,因为这只需要一个广告包来设置连接,而不是两个。

自动连接、直接连接和扫描在收听广告时都使用不同的扫描参数。您使用的模式和广告间隔严重影响连接设置时间。

>

  • 据我所知,在所有非古代Android版本中,自动连接每1280毫秒使用一个48毫秒的窗口,所有供应商都在使用。当广告设备有一个很短的广告间隔时,这非常有效,例如20毫秒。我想象当汽车启动时,你的汽车可以爆发出这个短的广告间隔,如果一段时间没有建立连接,可能会增加间隔。当使用20毫秒的广告间隔时,应在1280毫秒内建立连接,因为在Android设备打开收音机的48毫秒内至少应捕获一个数据包。但是,如果以1秒的间隔进行广告,则连接可能需要很长时间,因为广告必须在1280毫秒的48毫秒时间范围内准确发送。

    Direct connect使用大约每60毫秒30毫秒的窗口来建立快速连接。然而,直接连接在30秒后超时,并在回调中发送错误状态。因此,此模式只能在用户按下“连接”按钮的GUI中使用,或者在运行某些扫描后,您希望连接到扫描期间找到的设备。

    正常扫描操作使用完全不同的扫描窗口和扫描间隔。过去,1秒扫描窗口和5秒扫描间隔用于“低功耗”,5秒扫描窗口和5秒扫描间隔用于“低延迟”。在后来的Android版本中,这种情况变得更糟,比如扫描间隔为15秒或45秒,而窗口没有增加。

    随着时间的推移,后台扫描对Android的限制越来越大,你需要小心你的扫描设置、扫描过滤器、扫描频率和扫描时间,以确保Android设备真正扫描你的BLE设备。幸运的是,Android 8中添加了使用待定意图的新API,允许系统扫描您的设备,即使您的应用程序已被系统杀死以节省内存。你应该阅读http://www.davidgyoungtech.com/2017/08/07/beacon-detection-with-android-8比较了一系列扫描选项。然而,当你有一个前台服务(需要在通知栏中有一个图标指示用户你的应用正在运行)时,这篇文章似乎没有提到这种情况,这大大降低了所有限制。

    然而,多年来根本没有添加对“自动连接”的限制。我所知道的唯一“限制”是您的应用程序进程中应该有一个前台服务,以避免应用程序被杀死,从而失去您的连接尝试。

    当然,Android的蓝牙堆栈中存在许多错误,其中一些已经修复,一些仍然存在。还有一些预期的行为会导致不稳定——例如当Android认为您扫描太多时停止扫描。

    无论使用哪种方法,如果希望在用户关闭和打开蓝牙(或者蓝牙堆栈崩溃并重新启动)后保持连接,则需要有一个侦听BluetoothAdapter的BroadcastReceiver。ACTION\u STATE\u已更改,重新启动所有挂起的连接/扫描。你可能还想设置一个BroadcastReceiver,在系统启动或你的应用程序更新时监听,在这些场景中启动你的应用程序,这样你就可以启动挂起的连接。

    也许它对您的情况没有那么重要,但无论您使用哪种连接方法,您都应该注意Android对最大连接、BlueoothGatt对象、L2CAP链接和可能导致您的通信以意想不到的方式失败的东西有限制。有时通过onConnectionStateChange回调中的错误,有时没有回调来达到限制。

    对于“自动连接”,如果你知道你有运行Android6或更低版本的设备,你真的应该实现像https://github.com/Polidea/RxAndroidBle/blob/7663a1ab96605dc26eba378a9e51747ad254b229/rxandroidble/src/main/java/com/polidea/rxandroidble2/internal/util/BleConnectionCompat.java这样的东西,因为https://issuetracker.google.com/issues/36995652这会导致选择“直接连接”而不是“自动连接”。

    对于“自动连接”,我写了一个重要的补丁https://android.googlesource.com/platform/system/bt/ /8451ad010e26562d4a4c7d0d135c70c4325ee6b5在Android 8.1中被接受,它早些时候导致蓝牙堆栈挂起,直到设备超时时重新启动,然后在Android设备超时前重新启动广告。

    当您的代码在最近的设备上运行到足以支持将TRANSPORT_LE传递给ConnectGatt时,请使用该方法,否则Android有时会尝试使用蓝牙经典进行连接。

    由于一个可怕的设计缺陷,无法通过完整地址(地址类型随机/公共地址)告诉蓝牙堆栈进行连接。当您想要获取BluetoothDevice对象(然后您使用它来连接)时,您只能提供48位地址。通过挖掘Android蓝牙堆栈的源代码,蓝牙设备由48位地址而不是49位标识的问题在任何地方都是一样的。他们的“快速解决方案”是在设备信息中添加一个属性,指示设备是否具有公共或随机地址。应用程序无法设置此位,但仅在扫描期间设置。当使用ConnectGatt连接并且地址类型未知时,它会尝试使用公共地址类型建立(Android 7的一些子版本在使用“自动连接”时根据48位地址中的某些位对地址类型进行了一些愚蠢的猜测)。如果您的BLE设备具有静态随机地址,则它不会连接。通过执行扫描并检测到您的设备,它会将设备的地址和地址类型存储在RAM中的表中,因此如果您稍后使用ConnectGatt连接到它,它将成功,因为现在使用了正确的地址类型。当蓝牙重新启动时,此表将被清除。请注意,如果您执行绑定,则设备信息将写入磁盘,包括地址类型,因此即使重新启动蓝牙,连接到绑定设备也应始终正常工作。

    尽管存在上述所有问题,“自动连接”通常运行完美且非常稳定,只要您遵循上述指南,假设您的外围设备有很短的广告间隔,这将为您提供快速的连接设置时间。在Android 8.1及更高版本中,大多数关键错误都已修复。

    您的第二个选择可能是使用挂起意图扫描选项,当您的设备被检测到时,您会从系统获得广播(即使这可能需要相当长的时间才能检测到您的设备)。为了安全起见,您当然也可以使用这两种方法...

  •  类似资料:
    • ap.connectBLEDevice(OPTION | deviceId, CALLBACK) 连接低功耗蓝牙设备。可直接传入一个字符串作为 OPTION.deviceId。 OPTION 参数说明 名称 类型 必填 描述 deviceId String 是 蓝牙设备 id 错误码说明 error 描述 12 链接失败 代码示例 <script src="https://gw.alipayobj

    • 我的应用程序应连接到蓝牙LE设备。通常使用mBluetoothAdapter执行设备扫描。Stratescan(mLeScanCallback) 。回调为您提供有关可用设备的信息。 如果要连接到专用设备,请执行以下操作 然后 在我看来,连接到BLE设备的唯一需要是知道BLE地址,然后通过以上两个步骤连接到它。因此,如果我已经知道一个BLE地址(例如,它写在BLE设备的标签上),我就不需要执行BLE

    • 我正在尝试制作一个应用程序,它使用Android的新蓝牙低能耗API。为此,我从API Level18附带的BLE示例开始。 当我读到Android不能充当外围设备时,我将Android手机置于中央模式,扫描周围的BLE设备。为此,我用一个模拟心脏传感器的北欧平台做了一些测试。一切都以完美的方式运作! 多谢了。 编辑:经过一些艰苦的测试,我在AOSP页面上提出了一个问题。这里可以查

    • ap.disconnectBLEDevice(OPTION | deviceId, CALLBACK) 断开与低功耗蓝牙设备的连接。可直接传入一个字符串作为 OPTION.deviceId。 OPTION 参数说明 名称 类型 必填 描述 deviceId String 是 蓝牙设备 id 错误码说明 error 描述 12 断开失败 代码示例 <script src="https://gw.al

    • jd.readBLECharacteristicValue(Object object) 读取低功耗蓝牙设备的特征值的二进制数据值。注意:必须设备的特征值支持 read 才可以成功调用。 参数名 类型 默认值 必填 说明 deviceId string 是 蓝牙设备 id serviceId string 是 蓝牙特征值对应服务的 uuid characteristicId string 是 蓝牙

    • 我们正在制造具有BLE接口的物联网设备,该设备使用托管芯片CC2541(http://www.ti.com/product/CC2541)的HM-11(http://www.seeedstudio.com/wiki/Bluetooth_V4.0_HM-11_BLE_Module)分线板。 身份验证方法设置为:使用PIN进行身份验证 数据表中显示可用认证模式的剪辑如下: <代码>63。查询/设置模块