Android:自动重新连接 BLE 设备
Android: Auto-reconnect BLE devices
我的目标是让 Android 设备重新连接到它之前连接过的 BLE 设备 而无需用户干预经典的 BT 配对设备可以(甚至可以通过电源循环工作)。
BTLE 设备的想法之一是保存服务、绑定和启用状态,以便重新连接非常快并且在外围设备上消耗的电量非常少。
我所做的似乎有效,但效果不佳。
第一步是连接或配对并连接到新设备,将 'autoconnect' 参数设置为 'true'。
当设备断开连接时,不调用 gatt.close()。我到处都看到应该调用 gatt.close()。但是,如果我调用 gatt.close(),Android 中央应用程序永远不会重新连接。我已经测试过很多次了。
如果我没有调用 gatt.close() 并且没有重启 Android,通常会发生自动连接。有时可能需要很长时间,尤其是在 5.0 版本之后。然而,它是不可靠的,并且由于非常低负载的扫描周期和设备在扫描周期实际检测到广告之前退出广告而可能是不可靠的。我不确定,因为没有办法像有广告一样检测扫描操作!也有可能在一定时间后扫描停止,但没有相关文档。
所以我认为我需要做的是以某种方式将 Android 使用的背景扫描速率设置为更高的占空比(仅在 5.0 及更高版本中可能)当自动连接已设置但我不知道该怎么做。我不想开始自己的扫描,但以某种方式设置 Android 用于重新连接的后台扫描速率。有谁知道如何做到这一点?有谁真的知道自动连接和 gatt.close() 是如何工作的?
也许自动连接并不是我上面指出的那样重新连接?
经过多次试验和磨难,这就是我让 Android 自动连接的最佳方式,唯一的用户操作是首先 select 设备(如果使用设置菜单,然后首先配对).
您必须在 BroadcastReceiver 中捕获配对事件并执行 BluetoothDevice.connectGatt() 将自动连接设置为 true。然后当设备断开连接时,调用 gatt.connect().
更新:虽然上述方法一般有效,但有时速度慢得令人痛苦,这可能是因为挂起的连接使用了极其保守的扫描速率。另一个缺点是,对于每个你想要自动重新连接的设备,你必须保持一个 BluetoothGatt 对象执行挂起的连接。在嵌入式世界中,这是疯狂的。相反,人们所做的是通过检查其广告来不断扫描并连接到所需的设备。一个只保存关于设备的最少量数据(服务、配对状态和密钥等)。捕获广告后,您会看到它是否是您已知的设备之一,如果是则连接。
我在 Android 上尝试了等效的方法。一直扫描(低功率)并连接到感兴趣的广告,并维护一个 class 代表一个已知设备。这种方法有一些烦人的细节(比如在连接时关闭扫描并在连接后重新启动)但它基本上可以在没有维护连接开销的情况下工作。但是有一个例外我不明白。一台预配对设备的广告永远不会被扫描仪看到。但是,如果我调用与此设备的挂起连接,我会重新连接。我完全不明白这一点。在我的嵌入式平台上,它可以正常工作。
如果有人尝试过这种自动重新连接的方法,请分享您的经验!
我发现了 Android 看不到预配对设备的原因。 Android 仅在设备响应扫描请求时报告扫描结果。配对后,此设备仅发出广告并忽略扫描请求,因此 Android 系统不会在 ScanCallback 中传递其广告。因此,为了使用扫描方法工作,我必须对那些特定设备使用挂起连接方法。看来你赢不了了!
============= 2020 年更新
很多年过去了,我对后台扫描方法有了更多的经验。如果将支持的平台保持在 5 及更高版本,则可以仅使用最新的扫描器 API 并使用过滤器,从而无需自己解码原始广告。我还发现,如果您在连接时不关闭扫描,连接和重新连接会更快。我知道这违反了所有文档,但它有效并且在某些平台上允许发生连接,否则不会发生连接。此外,到目前为止,我只发现一个(健康)设备需要挂起连接。免责声明:我只用过健康设备。
我就是这样为我的申请做的。
我首先将设备的地址存储在 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();
});
}
}
这样做的目的是,如果您的设备断开连接,它将继续尝试连接,直到建立连接。
我的目标是让 Android 设备重新连接到它之前连接过的 BLE 设备 而无需用户干预经典的 BT 配对设备可以(甚至可以通过电源循环工作)。
BTLE 设备的想法之一是保存服务、绑定和启用状态,以便重新连接非常快并且在外围设备上消耗的电量非常少。
我所做的似乎有效,但效果不佳。
第一步是连接或配对并连接到新设备,将 'autoconnect' 参数设置为 'true'。 当设备断开连接时,不调用 gatt.close()。我到处都看到应该调用 gatt.close()。但是,如果我调用 gatt.close(),Android 中央应用程序永远不会重新连接。我已经测试过很多次了。
如果我没有调用 gatt.close() 并且没有重启 Android,通常会发生自动连接。有时可能需要很长时间,尤其是在 5.0 版本之后。然而,它是不可靠的,并且由于非常低负载的扫描周期和设备在扫描周期实际检测到广告之前退出广告而可能是不可靠的。我不确定,因为没有办法像有广告一样检测扫描操作!也有可能在一定时间后扫描停止,但没有相关文档。
所以我认为我需要做的是以某种方式将 Android 使用的背景扫描速率设置为更高的占空比(仅在 5.0 及更高版本中可能)当自动连接已设置但我不知道该怎么做。我不想开始自己的扫描,但以某种方式设置 Android 用于重新连接的后台扫描速率。有谁知道如何做到这一点?有谁真的知道自动连接和 gatt.close() 是如何工作的?
也许自动连接并不是我上面指出的那样重新连接?
经过多次试验和磨难,这就是我让 Android 自动连接的最佳方式,唯一的用户操作是首先 select 设备(如果使用设置菜单,然后首先配对).
您必须在 BroadcastReceiver 中捕获配对事件并执行 BluetoothDevice.connectGatt() 将自动连接设置为 true。然后当设备断开连接时,调用 gatt.connect().
更新:虽然上述方法一般有效,但有时速度慢得令人痛苦,这可能是因为挂起的连接使用了极其保守的扫描速率。另一个缺点是,对于每个你想要自动重新连接的设备,你必须保持一个 BluetoothGatt 对象执行挂起的连接。在嵌入式世界中,这是疯狂的。相反,人们所做的是通过检查其广告来不断扫描并连接到所需的设备。一个只保存关于设备的最少量数据(服务、配对状态和密钥等)。捕获广告后,您会看到它是否是您已知的设备之一,如果是则连接。 我在 Android 上尝试了等效的方法。一直扫描(低功率)并连接到感兴趣的广告,并维护一个 class 代表一个已知设备。这种方法有一些烦人的细节(比如在连接时关闭扫描并在连接后重新启动)但它基本上可以在没有维护连接开销的情况下工作。但是有一个例外我不明白。一台预配对设备的广告永远不会被扫描仪看到。但是,如果我调用与此设备的挂起连接,我会重新连接。我完全不明白这一点。在我的嵌入式平台上,它可以正常工作。 如果有人尝试过这种自动重新连接的方法,请分享您的经验!
我发现了 Android 看不到预配对设备的原因。 Android 仅在设备响应扫描请求时报告扫描结果。配对后,此设备仅发出广告并忽略扫描请求,因此 Android 系统不会在 ScanCallback 中传递其广告。因此,为了使用扫描方法工作,我必须对那些特定设备使用挂起连接方法。看来你赢不了了!
============= 2020 年更新
很多年过去了,我对后台扫描方法有了更多的经验。如果将支持的平台保持在 5 及更高版本,则可以仅使用最新的扫描器 API 并使用过滤器,从而无需自己解码原始广告。我还发现,如果您在连接时不关闭扫描,连接和重新连接会更快。我知道这违反了所有文档,但它有效并且在某些平台上允许发生连接,否则不会发生连接。此外,到目前为止,我只发现一个(健康)设备需要挂起连接。免责声明:我只用过健康设备。
我就是这样为我的申请做的。 我首先将设备的地址存储在 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();
});
}
}
这样做的目的是,如果您的设备断开连接,它将继续尝试连接,直到建立连接。