我的目标:
从我的Android应用程序中检测所有附近的蓝牙设备(手机,耳机等)。
这是developer.android.com的一个很好的例子,可以发现附近的蓝牙设备以及已经配对的设备列表。
我的情况:
我打开了两个蓝牙耳机,成功进行蓝牙扫描后没有检测到它们!所以我深入研究了这个问题,并发现蓝牙耳机需要切换到配对模式才能被android检测到。
要在配对模式下切换耳机,我必须在打开电源按钮的同时长按电源按钮。是的,最后,现在我的应用程序扫描检测到蓝牙耳机。
我的问题:
我希望我的耳机会自动检测,而不会在配对模式下切换它们。无法找到一种方法来检测所有打开的蓝牙设备。
答案 0 :(得分:13)
所以,这是我在阅读有关Android蓝牙发现的博客,主题,文档,SO答案等后发现的全部内容。认为这可能有助于在此发布我的发现。
因此,在有人开始阅读之前,我想澄清一下,我找不到任何方法来检测附近的蓝牙设备,该设备已打开但无法被发现。
我的主要目标是检测所有附近的蓝牙设备。为此,我们在Android中有一个BluetoothAdapter
类,它具有startDiscovery
功能,可以扫描附近的蓝牙设备。因此,这并不符合我的目的,因为需要通过Android的蓝牙扫描来检测蓝牙设备。我想要的是检测附近的所有蓝牙设备,而不强迫它们被发现。我开始寻找实现这一目标的解决方案。
我从研究Bluetooth protocols开始,发现了用于蓝牙检测,连接和配对的基础协议。对于Android,我发现没有API可以发现/检测已打开但未处于可发现模式的BT设备。
在不强制蓝牙设备进入可发现模式的情况下深入研究此检测问题会导致我们发现自己在宣传自己为class 0×00
时自动忽略的蓝牙设备,同时对附近的BT设备进行扫描。这个问题在几个地方都有说明。我在这里列出了一些。
我试图找到解决这个问题的方法,是的,我找到了一个,虽然文档和评论以及这个解决方案说,但它并不适用于所有类型的Android设备。无论如何,备用扫描与默认的BT扫描相同,但它会做一些额外的工作。它在BT扫描成功后读取Android日志,并检查是否有任何BT设备被跳过整个操作。这是一个简单的黑客描述here 。有一个谷歌小组正在讨论相同的解决方法here。
上面的解决办法也没有解决我的问题。需要发现蓝牙耳机才能被BT扫描检测到。 Android正在扫描附近的BT设备时不会跳过它们。他们根本找不到。
然而,我又开始寻找解决方案,并再次找到了一些有趣的东西!这是来自另一个Stackoverflow answer,它说,通过首先了解他的完整MAC地址,即使他处于不可发现的模式,也可以知道蓝牙设备是否存在 。我将再次引用他的回答以供将来参考,
该技术是尝试PAGE请求,发送组成所寻找的蓝牙主机MAC标识符的所有6个字节。 PAGE请求允许在知道他的BT ADDR时与蓝牙从属设备连接。处于不可发现模式的设备不响应查询扫描(设备发现意图),但它们确实响应页面扫描,该页面扫描由想要连接到另一个先前已知设备的设备使用。
我找到了希望并开始搜索,我们如何在Android中启动页面扫描但这次也失败了。无法找到任何类型的API来启动页面扫描。从BluetoothAdapter
类的Android文档中,我开始知道,当BT扫描开始时,
这通常涉及大约12秒的查询扫描,然后对每个新设备进行页面扫描以检索其蓝牙名称。
在Android文档中有一个页面扫描的迹象,但令人惊讶的是,在任何地方都没有关于页面扫描的其他文档。我提出Stackoverflow question进行查询。
不,我没有找到任何办法。我读到了Android的蓝牙配对是如何工作的。这是一个nice flow diagram along with detailed reading manual。我们试图使用Android的隐藏API,并可以使用一些使用Reflection的隐藏API。然后我们开始寻找可能用于实现目的的隐藏API。但是,遗憾的是,我们未能找到任何隐藏的API来以编程方式在Android已经配对的列表中添加BT设备。
以下是一些有用的链接,用于检查蓝牙配对,隐藏的API以及如何通过反射调用它们以供将来参考。
因此,我可以在BT设备处于可发现模式时将其配对,而不是在Android中的配对列表中。就我而言,我使用的是蓝牙耳机。它被打开并置于可发现模式。耳机的BT地址(MAC地址)是已知的。所以我使用反射从我的代码中调用了函数createBond
,它运行得很好。该设备已添加到已配对的" Android列表成功。在漫游周围寻找解决方案以达到我的目的时,我发现了一些有趣的东西......
我发现,即使我从已经配对的列表中删除它,android也会在其内存中保留以前配对的设备。让我们分享一个案例研究以及这里的调查结果,以便更好地理解。在我的情况下,耳机先前配对。
这是打印的日志以及之前配对但未配对的耳机的MAC地址。
PREV_BOND_STATE = 11 // BOND_BONDING (BluetoothDevice.java)
BOND_STATE = 10 // BOND_NONE
REASON = 4 // UNBOND_REASON_REMOTE_DEVICE_DOWN
然后,我又跑了同样的测试,但这次我们打开了蓝牙耳机(不可发现)。在这种情况下也找不到耳机,但有趣的是,这次打印了不同的日志。
PREV_BOND_STATE = 11 // BOND_BONDING (BluetoothDevice.java)
BOND_STATE = 10 // BOND_NONE
REASON = 2 // UNBOND_REASON_AUTH_CANCELLED
REASON
已更改,因此我可以理解Android尝试连接蓝牙耳机。耳机未处于可发现模式,但Android可以找到它并尝试连接它,因为它在配对列表之前。
在蓝牙扫描运行时打印此日志,并在ACTION_BOND_STATE_CHANGED
处添加intent.addAction
操作。
是的,但在这种情况下,Android也需要将自己宣传为BLE。这是Android中的新功能,并非所有设备都支持此功能。这是支持蓝牙LE广告功能的list of devices。但是,由于蓝牙LE广告具有非常低的功耗和高性能,我认为这将是Android的下一个重大事件。
以下是未来研究的一些有用链接。