如何使用 Qt 在 D-Bus 上创建/实例化配对代理

How to create / instantiate pairing agent on D-Bus with Qt

我正在尝试构建用于在 Linux 设备上配对/连接蓝牙设备的 Qt 应用程序。我正在使用 BlueZ API (https://git.kernel.org/pub/scm/bluetooth/bluez.git/tree/doc) over D-Bus as descibed in the BlueZ official site (http://www.bluez.org/page/8/).

这里描述了一般过程: https://www.kynetics.com/docs/2018/pairing_agents_bluez/

目前,我可以毫无问题地将 API 用于 pairing/connecting 设备。

但我不知道如何使用配对代理。

我正在尝试按照此处指出的方向进行操作: How can i set the bluetooth pin number in linux C/C++

QDBusAbstractAdaptor object does not export implemented dbus interface

我在网上搜索了很多,有很多代码:

https://github.com/sdemario/qt-bluez-demos

https://github.com/KDE/bluez-qt

https://android.googlesource.com/platform/external/bluetooth/bluez/+/froyo-release/test/agent.c

https://github.com/pauloborges/bluez/blob/master/client/agent.c

https://www.linumiz.com/bluetooth-connectdevice-without-scanning/

但是,我仍然无法理解这是如何工作的。 python 中也有很多脚本,但我正在使用 C++。

我的(伪)代码如下:

agentManager = new QDBusInterface("org.bluez","/org/bluez","org.bluez.AgentManager1",QDBusConnection::systemBus(),this);
agent = new QDBusInterface("org.bluez","/org/bluez/agent","org.bluez.Agent1",QDBusConnection::systemBus(),this);


QDBusReply<void> reply;

reply = agentManager->call("RegisterAgent", QVariant::fromValue(QDBusObjectPath(path)), capability);
if (!reply.isValid()) {
    qDebug() << reply.error().message() << reply.error().name();
}

reply = agentManager->call("RequestDefaultAgent", QVariant::fromValue(QDBusObjectPath(path)));
if (!reply.isValid()) {
    qDebug() << reply.error().message() << reply.error().name();
}

QDBusReply<QString> reply_str = agent->call("RequestPinCode", QVariant::fromValue(QDBusObjectPath(path)));
if (reply_str.isValid()) {
    pincode = reply_str.value();
} else {
    qDebug() << reply_str.error().message() << reply.error().name();
}

"RegisterAgent" 和 "RequestDefaultAgent" 调用给出了有效回复,而 "RequestPinCode" 给出了错误:

“在接口 "org.bluez.Agent1" 上带有签名 "o" 的方法 "RequestPinCode" 不存在 " "org.freedesktop.DBus.Error.UnknownObject"

为什么?我做错了什么?

谢谢

编辑

我在 D-Bus 上实现了一个全新的服务,它实现了 org.bluez.Agent1 接口(至少是它的一部分)。现在,代码如下所示:

MyObject* myObject = new MyObject();
MyAdaptor* myAdaptor = new MyQDusAdaptor(myObject);

if (QDBusConnection::systemBus().registerService("org.test")) {
    qDebug() << "registerService was Succesfull!";
} else {
    qDebug() << "registerService was not Succesfull!";
}

if(QDBusConnection::systemBus().registerObject("/pairing/agent",myObject)){
    qDebug() << "registerObject was Succesfull!";
} else {
    qDebug() << "registerObject was not Succesfull!";
}

agentManager->RegisterAgent(QDBusObjectPath("/pairing/agent"),"NoInputNoOutput");
agentManager->RequestDefaultAgent(QDBusObjectPath("/pairing/agent"));


MyObject 所在的位置


class MyObject : public QObject
{
    Q_OBJECT

public:
    MyObject();

public Q_SLOTS:
    QString RequestPinCode(const QDBusObjectPath &in0);
};


MyObject::MyObject() {

}
QString MyObject::RequestPinCode(const QDBusObjectPath& in0)
{
    qDebug() << "MyObject" << in0.path();


    QString str = "2974";
    return str;
}


适配器是


class MyQDusAdaptor: public QDBusAbstractAdaptor
{

    Q_OBJECT
    Q_CLASSINFO("D-Bus Interface", "org.bluez.Agent1")
    Q_CLASSINFO("D-Bus Introspection", ""
                                                                         "  <interface name=\"org.bluez.Agent1\">\n"
                                                                         "    <method name=\"RequestPinCode\">\n"
                                                                         "      <arg direction=\"in\" type=\"o\"/>\n"
                                                                         "      <arg direction=\"out\" type=\"s\"/>\n"
                                                                         "    </method>\n"
                                                                         "  </interface>\n"
                                                                         "")

public:
        MyQDusAdaptor(QObject *parent);
        virtual ~MyQDusAdaptor();

public: // PROPERTIES
public Q_SLOTS: // METHODS
        QString RequestPinCode(const QDBusObjectPath &in0);
};


MyQDusAdaptor::MyQDusAdaptor(QObject* parent) : QDBusAbstractAdaptor(parent) {

    setAutoRelaySignals(true);
}

MyQDusAdaptor::~MyQDusAdaptor() {

}

QString MyQDusAdaptor::RequestPinCode(const QDBusObjectPath& in0)
{
    qDebug() << "MyQDusAdaptor" << in0.path();

    QString out0;
         QMetaObject::invokeMethod(parent(), "RequestPinCode", Q_RETURN_ARG(QString, out0), Q_ARG(QDBusObjectPath, in0));
         return out0;
}

当我尝试配对智能手机时,应用程序冻结约 30 秒,我收到以下错误消息:

"Did not receive a reply. Possible causes include: the remote application did not send a reply, the message bus security policy blocked the reply, the reply timeout expired, or the network connection was broken." "org.freedesktop.DBus.Error.NoReply"

只有在那之后,智能手机才会要求输入 PIN。

我认为必须异步完成。有小费吗?

好的,现在可以了。 QDBusAbstractAdaptor object does not export implemented dbus interface

中解释了如何做到这一点

实施细节在这个问题的最后编辑。最后要做的是使用 callWithCallback:

在 Device1 接口上异步实现 "Pair" 方法
void cBluetoothDevice::Pair() {

    QList<QVariant> args;
    args.clear();

    device->callWithCallback("Pair",args, this, SLOT(PairSlot(QDBusMessage)));
}

其中设备是一个 QDBusInterface*