使用 QtDBus 捕获并响应 Connman 'RequestInput' 方法调用

Catching and responding to the Connman 'RequestInput' method call with QtDBus

我正在构建一个简单的基于 Qt 的应用程序,用于监控和连接到 WiFi 网络。我正在通过其 D-Bus API 与 Connman 进行交互,并且能够扫描可用网络,启用 on/off 技术并按预期注册代理。我目前无法在调用 Connman RequestInput 方法时提供请求的密码(当尝试连接到 protected/secure 网络时),因为我不确定如何将 RequestInput 方法与 Qt 中的函数绑定。

下面是一些概述该方法的指示性代码:

//Create a QDBusConnection systemBus() object
QDBusConnection connection = QDBusConnection::systemBus();

//Ensure the systemBus() connection is established
if (!connection.isConnected()) {
    qDebug() << "Connection error.";
}

//Create a Connman Manager D-Bus API interface object
QDBusInterface manager("net.connman", "/", "net.connman.Manager", connection);

//Register an agent with the Connman Manager API
manager.call("RegisterAgent", QVariant::fromValue(QDBusObjectPath("/test/agent")));

//Attempt to bind the mySlot() function with the net.connman.Agent RequestInput method
//This does not currently work
connection.connect("",
                   "/test/agent",
                   "net.connman.Agent",
                   "RequestInput",
                    this,
                    SLOT(mySlot(QDBusObjectPath, QVariantMap)));

//Create a Connman Service D-Bus API interface object (for a specific WiFi Service)
QDBusInterface service("net.connman",
                       "/net/connman/service/[WIFI SERVICE]",
                       "net.connman.Service",
                        connection);

//Attempt to connect to the secure WiFi network
//Note: this network has not previously been connected, so the RequestInput method is guaranteed to be called
service.call("Connect");

QVariantMap myClass::mySlot(const QDBusObjectPath &path, const QVariantMap &map)
{
    //Connman Agent RequestInput() method received
}

如上所述,尝试将 /test/agent 路径、net.connman.Agent 接口和 RequestInput 方法绑定到 mySlot() 函数不起作用;没有报告错误,但从未调用 mySlot() 函数。如果我使用 QDBUS_DEBUG 环境变量启用调试,我会收到以下信息:

QDBusConnectionPrivate(0xffff74003a00) got message (signal): QDBusMessage(type=MethodCall, service=":1.3", path="/test/agent", interface="net.connman.Agent", member="RequestInput", signature="oa{sv}", contents=([ObjectPath: /net/connman/service/[WIFI SERVICE]], [Argument: a{sv} {"Passphrase" = [Variant: [Argument: a{sv} {"Type" = [Variant(QString): "psk"], "Requirement" = [Variant(QString): "mandatory"]}]]}]) )

以上正是我所期望的;正在为具有 oa{sv} 签名的 net.connman.Agent 接口上的 /test/agent 路径调用 RequestInput 方法。

我的问题:

  1. 如何'connect'调用 RequestInput 方法,以便我的 mySlot() 函数可以解析 RequestInput 方法数据?
  2. 如何从 mySlot() 中 return 所需的 QVariantMap?

从调试输出看来,ConnMan 正在执行 MethodCall,但 QDBusConnection::connect() 用于处理 DBus 信号,这就是未调用您的插槽的原因。

您需要将一个实现了net.connman.Agent接口的对象注册到相应的路径上,以便ConnMan可以调用您的方法:

class ConnManAgent : public QObject {
    Q_OBJECT
    Q_CLASSINFO("D-Bus Interface", "net.connman.Agent")
public:
    ConnManAgent(QObject *parent = nullptr);

    Q_INVOKABLE QVariantMap RequestInput(const QDBusObjectPath &, const QVariantMap &);

   // ... Rest of the net.connman.Agent interface
};

然后在各自的路径上注册:

connection.registerObject(
    QStringLiteral("/test/agent"),
    new ConnManAgent(this), 
    QDBusConnection::ExportAllInvokables);

这会将所有标有 Q_INVOKABLE 的方法导出到 DBus。您也可以将它们标记为 Q_SLOTS 并使用 ExportAllSlots,这主要取决于您。