Android 4.4: 蓝牙低功耗;不通过扫描BLE设备即可连接

10

我的应用程序将连接到一个蓝牙低功耗设备。通常使用 mBluetoothAdapter.startLeScan(mLeScanCallback); 进行设备扫描,回调提供有关可用设备的信息。

如果您想连接到特定设备,可以执行以下操作:

BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);

然后

mBluetoothGatt = device.connectGatt(this, false, mGattCallback);
对我来说,似乎唯一需要连接到BLE设备的是要知道其BLE地址,然后使用上述两个步骤连接。因此,如果我已经知道一个BLE地址(例如,它写在BLE设备的标签上),我就不需要执行BLE扫描。
但是我遇到的问题是,如果我有一个从未通过BLE扫描找到过的BLE设备,则无法直接使用其BLE地址进行连接。我必须通过我的Android手机进行至少一次扫描才能找到它。之后,我再也不需要扫描,只需使用其BLE地址即可连接到BLE设备。
这是否应该是这样的,还是我错过了什么?
非常感谢, Stefan

在连接之前,是否需要进行配对和/或绑定 - JimmyB
据我所了解,BLE并不需要这样做。即使我执行扫描,也不需要进行配对或绑定,它也可以正常工作。问题在于如何直接连接到设备,而无需进行BLE扫描。 - Stefan
3个回答

5
Hoa Do的回答并不完全正确。由于Android的BLE API存在一些可怕的设计缺陷,因此无法告诉它您指定的地址是公共地址还是随机地址。(您可以在https://devzone.nordicsemi.com/question/43670/how-to-distinguish-between-random-and-public-gap-addresses/上了解有关不同地址类型的更多信息)。getRemoteDevice方法应该带有一个额外的参数“随机地址/公共地址”,但它没有。如果没有正确的地址类型,蓝牙控制器将无法连接到设备。
Android的BLE栈有一些内部启发式算法来“猜测”地址是公开还是随机的,但不幸的是这在不同的Android版本和使用autoConnect=true或false时是不同的。然而,如果你已经将设备配对(https://developer.android.com/reference/android/bluetooth/BluetoothDevice.html#createBond()),那么它将存储在其内部数据库中给定地址是公开的还是随机的。如果你想连接的外围设备使用随机可解析地址,如果使用配对,它也可以处理。因此,我强烈建议使用配对。
如果你不使用配对,则需要在连接设备之前进行扫描,因为当你开始扫描并检测到设备时,Android的BLE栈将暂时记住地址的地址类型(直到下次重新启动蓝牙)。如果你在连接之前没有扫描设备,它仍会尝试连接,但有可能尝试使用错误的地址类型,从而导致失败。

4
设备地址仅是蓝牙设备的唯一标识符,不包含连接信息。扫描是必要的,以检索蓝牙设备广播信号中的信息,从而建立连接。扫描完成后,信息将保存在设备上并与设备地址绑定。
我认为,如果尝试检索蓝牙地址的值,在扫描一次之前会返回null。

你有证实这个的来源吗? - Andrew Gallasch
1
它并没有明确说明这一点,虽然我不是蓝牙协议的专家,但我的推断是,虽然设备地址可以用来识别设备,但它并没有指定要在哪个通道上进行通信。该协议为从设备和主设备指定了一个查询通道,以了解彼此并提供连接的进一步指令。一旦检索到该信息,那么主设备就可以保存该信息,并在下次直接执行连接,因为它已经有了指令。 - Hoa Do
请注意,对于未绑定的BLE设备也是如此。这意味着一旦扫描完成并发现服务后,Android将缓存这些服务,调用BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address); 将在不到1秒的时间内建立连接。 - benchuk

-1

很多年过去了,自从这个问题第一次被提出来,我已经能够让以下内容正常工作。我的设备没有随机地址,所以如果你知道你的设备没有随机地址,那么以下内容应该可以正常工作。

// perform scan, get device and store address somewhere 
// like in shared preferences
String bleAddress = bluetoothDevice.getAddress();
this.getSharedPreferences("myPrefs", MODE_PRIVATE).edit().putString("BLE_ADDRESS",bleAddress .apply();


// next time no need to scan, just get the remote device
// from the bluetoothAdapter and connect.
String address = this.getSharedPreferences("myPrefs", MODE_PRIVATE).getString("BLE_ADDRESS",null);
if (address != null) {
    BluetoothDevice device = bluetoothAdapter.getRemoteDevice(ble_address)
    device.connectGatt(context, false, this, BluetoothDevice.TRANSPORT_LE);
}

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