注释 URL

读取格式化的 NFC 数据交换格式 (NDEF) 消息。

注释 URL 示例使用 Qt NFC来显示从 NFC 标签读取的特定格式的 NFC 数据交换格式(NDEF)信息的内容。NDEF 信息应包含一个 URI 记录、一个可选的image/* MIME 记录和一个或多个本地化文本记录。

这是示例的初始状态:

如果触摸标签,就会显示其 NDEF 内容。下面是包含文本记录和 URI 记录的标签的用户界面:

点击屏幕后,URL 将在浏览器中打开。

注释 URL 类定义

AnnotatedUrl 类封装了提供 NFC 标签检测功能的QNearFieldManager 类。QNearFieldManager 会读取 NDEF 消息,并将其转发给AnnotatedUrl 类中的处理程序。解析 NDEF 消息后,该类会发出annotatedUrl() 信号。用户界面会对信号做出反应,显示 NDEF 消息的内容。

class AnnotatedUrl : public QObject
{
    Q_OBJECT

public:
    explicit AnnotatedUrl(QObject *parent = 0);
    ~AnnotatedUrl();

    void startDetection();

signals:
    void annotatedUrl(const QUrl &url, const QString &title, const QPixmap &pixmap);
    void nfcStateChanged(bool enabled);
    void tagError(const QString &error);

public slots:
    void targetDetected(QNearFieldTarget *target);
    void targetLost(QNearFieldTarget *target);
    void handleMessage(const QNdefMessage &message, QNearFieldTarget *target);
    void handlePolledNdefMessage(QNdefMessage message);
    void handleAdapterStateChange(QNearFieldManager::AdapterState state);

private:
    QNearFieldManager *manager;
    QNdefFilter messageFilter;
};

注: startDetection() 方法用于推迟实际的标签检测,直到用户界面和 NFC 相关逻辑之间的所有连接都已建立。这一点在触摸 NFC 标签后自动启动应用程序时非常重要。目前 Android 系统支持这种用例。

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow mainWindow;
    AnnotatedUrl annotatedUrl;

    QObject::connect(&annotatedUrl, &AnnotatedUrl::annotatedUrl,
                     &mainWindow, &MainWindow::displayAnnotatedUrl);
    QObject::connect(&annotatedUrl, &AnnotatedUrl::nfcStateChanged,
                     &mainWindow, &MainWindow::nfcStateChanged);
    QObject::connect(&annotatedUrl, &AnnotatedUrl::tagError,
                     &mainWindow, &MainWindow::showTagError);

    annotatedUrl.startDetection();
    mainWindow.show();

    return a.exec();
}

信息过滤

如上所述,应用程序支持特定格式的 NDEF 消息。正确的信息应包含以下字段:

  • 至少一条NDEF 文本记录,该记录将用作标题。
  • 一条NDEF URI 记录。
  • 一个可选的带图标的 MIME 记录。

记录的顺序没有严格规定。

QNdefFilter 实例用于验证 NDEF 报文。过滤器的填充方式如下:

    messageFilter.setOrderMatch(false);
    messageFilter.appendRecord<QNdefNfcTextRecord>(1, 100);
    messageFilter.appendRecord<QNdefNfcUriRecord>(1, 1);
    messageFilter.appendRecord(QNdefRecord::Mime, "", 0, 1);

如果输入的报文与过滤器不匹配,则会显示错误信息:

注: NDEF 编辑器示例应用程序可用于创建具有正确或不正确信息结构的标记。

注释链接处理程序的实现

QNearFieldManager 读取的 NFC 报文被转发到AnnotatedUrl::handleMessage

void AnnotatedUrl::handleMessage(const QNdefMessage &message, QNearFieldTarget *target)
{

首先使用QNdefFilter::match() 方法对报文进行验证:

    if (!messageFilter.match(message)) {
        emit tagError("Invalid message format");
        return;
    }

如果报文格式正确,则继续进行解析。

由于 NFC 报文由多条 NDEF 记录组成,通过循环浏览所有记录,可以提取出要在用户界面中显示的 3 个参数:Uri、标题和像素图:

    for (const QNdefRecord &record : message) {
        if (record.isRecordType<QNdefNfcTextRecord>()) {
            QNdefNfcTextRecord textRecord(record);

            title = textRecord.text();
            QLocale locale(textRecord.locale());
        } else if (record.isRecordType<QNdefNfcUriRecord>()) {
            QNdefNfcUriRecord uriRecord(record);

            url = uriRecord.uri();
        } else if (record.typeNameFormat() == QNdefRecord::Mime &&
                   record.type().startsWith("image/")) {
            pixmap = QPixmap::fromImage(QImage::fromData(record.payload()));
        }

最后,在提取出 NFC 信息的参数后,就会发出相应的信号,以便用户界面能对其进行处理。

    }

    emit annotatedUrl(url, title, pixmap);
}

适配器状态处理

在安卓系统中,适配器状态变化可通过连接QNearFieldManager::adapterStateChanged() 信号进行检测。这样就可以在 NFC 适配器禁用时停止检测,并在适配器再次启用时重新启动检测。这种方法在AnnotatedUrl::handleAdapterStateChange 插槽中实现。

void AnnotatedUrl::handleAdapterStateChange(QNearFieldManager::AdapterState state)
{
    if (state == QNearFieldManager::AdapterState::Online) {
        startDetection();
    } else if (state == QNearFieldManager::AdapterState::Offline) {
        manager->stopTargetDetection();
        emit nfcStateChanged(false);
    }
}

自动启动应用程序

Android 支持在触摸 NDEF 标签时自动启动应用程序。有关 Android 清单文件所需的更改,请参见Qt NFC onAndroid。

引入自定义 AndroidManifest.xml 需要在构建系统方面采取特殊步骤。

使用 qmake 构建

使用 qmake 时,需要在.pro 文件中添加以下内容:

android {
    ANDROID_PACKAGE_SOURCE_DIR = $$PWD/android

    DISTFILES += \
        android/AndroidManifest.xml
}
使用 CMake 构建

使用 CMake 时,需要将以下内容添加到CMakeLists.txt

if(ANDROID)
    set_property(TARGET annotatedurl
        APPEND PROPERTY QT_ANDROID_PACKAGE_SOURCE_DIR
        ${CMAKE_CURRENT_SOURCE_DIR}/android
    )
endif()

运行示例

要从 Qt Creator,打开Welcome 模式,并从Examples 中选择示例。更多信息,请参阅Qt Creator: 教程:构建并运行

示例项目 @ code.qt.io

另请参见 Qt NFC.

© 2025 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.