我需要通过蓝牙将我的 Android 手机连接到 Linux PC。电话需要能够通过 PC MAC 和服务的 UUID(或仅 UUID)完全自动地创建连接。手机应该是连接发起者。
我使用了这个示例:蓝牙编程简介并遇到了问题,这些问题很可能是因为我的示例已被弃用而发生的。有人建议我使用新的 DBus 库,但我无法真正理解如何将手机上的程序(应该用 Java/Kotlin/Flutter 编写)连接到 DBus 架构。
我找到了这个例子:使用低级 API 的 DBus 教程,这一行最让我困惑:
With DBUS, before applications can communicate each other, they must be connected to the same BUS.
这是否意味着如果我在我的服务器(Linux、C++)上使用 DBus,我必须使用我的手机上也有 DBus 吗?
如果是这样,我还能用什么来完成我的任务?
在深入编码之前,尝试通过 D-Bus API 与 BlueZ
bluetoothd
进行交互可能会很有用。这可以使用各种命令行工具来完成。我假设您将在 C 代码中使用 gdbus 库,因此这似乎是在命令行上进行实验的不错选择。
用于 Linux 蓝牙适配器的 BlueZ D-Bus API 可能是最容易上手的。
此 API 的文档位于:
https://git.kernel.org/pub/scm/bluetooth/bluez.git/tree/doc/adapter-api.txt
顶部说明了 D-Bus 服务和接口是什么。并且对象路径可以是可变的。
Service org.bluez
Interface org.bluez.Adapter1
bluetoothd
正在 D-Bus System
总线上进行通信。
D-Bus 有一个
GetManagedObjects
方法,我们可以用它来报告 BlueZ 知道的所有事情,以便列出有关 BlueZ 使用的所有信息:
$ gdbus call --system --dest org.bluez --object-path / --method org.freedesktop.DBus.ObjectManager.GetManagedObjects
这是很多信息,所以让我们使用 grep 来查找适配器的对象路径:
$ gdbus call --system --dest org.bluez --object-path / --method org.freedesktop.DBus.ObjectManager.GetManagedObjects | grep -Pio "/org/bluez/hci.*Adapter1"
/org/bluez/hci0': {'org.freedesktop.DBus.Introspectable': {}, 'org.bluez.Adapter1
所以我们现在可以看到(对我来说)D-Bus 对象路径是
/org/bluez/hci0
。我现在可以反省一下:
$ gdbus introspect --system --dest org.bluez --object-path /org/bluez/hci0
现在我有了服务、接口和对象路径,我可以调用 BlueZ 记录的方法。例如,查找可以提供给 SetDiscoveryFilter 的可用过滤器:
$ gdbus call --system --dest org.bluez --object-path /org/bluez/hci0 --method org.bluez.Adapter1.GetDiscoveryFilters
(['UUIDs', 'RSSI', 'Pathloss', 'Transport', 'DuplicateData'],)
要获取适配器上的所有属性,我们可以使用
GetAll
接口上的 org.freedesktop.DBus.Properties
方法(我们可以从内省中看到)。调用示例:
$ gdbus call --system --dest org.bluez --object-path /org/bluez/hci0 --method org.freedesktop.DBus.Properties.GetAll "org.bluez.Adapter1"
要获取一个属性的值,我们使用
Get
:
$ gdbus call --system --dest org.bluez --object-path /org/bluez/hci0 --method org.freedesktop.DBus.Properties.Get "org.bluez.Adapter1" "Powered"
要设置属性的值,我们使用
Set
:
$ gdbus call --system --dest org.bluez --object-path /org/bluez/hci0 --method org.freedesktop.DBus.Properties.Set "org.bluez.Adapter1" "Powered" "<boolean true>"
以下看起来像是在 C 中执行此操作的有用介绍:
我的系统有
dbus-send
而不是 gdbus
所以上面的例子是:
反省:
dbus-send --system --print-reply --dest=org.bluez /org/bluez/hci0 org.freedesktop.DBus.Introspectable.Introspect
可以向 SetDiscoveryFilter 提供哪些可用的过滤器:
dbus-send --system --print-reply --dest=org.bluez /org/bluez/hci0 org.bluez.Adapter1.GetDiscoveryFilters
要获取适配器上的所有属性,我们使用
GetAll
:
dbus-send --system --print-reply --dest=org.bluez /org/bluez/hci0 org.freedesktop.DBus.Properties.GetAll string:org.bluez.Adapter1
要获取一个属性的值,我们使用
Get
:
dbus-send --system --print-reply --dest=org.bluez /org/bluez/hci0 org.freedesktop.DBus.Properties.Get string:org.bluez.Adapter1 string:Powered
要设置属性的值,我们使用
Set
:
dbus-send --system --dest=org.bluez --print-reply /org/bluez/hci0 org.freedesktop.DBus.Properties.Set string:org.bluez.Adapter1 string:Powered variant:boolean:true