Wie verwende ich NFC in einer Qt/QML-Anwendung?

Qt QML-Entwicklung
2021-03-09
10 Minuten
NFC in Qt/QML-Anwendung

Haben Sie sich schon einmal gefragt, wie Sie NFC in Qt/QML-Anwendungen verwenden können? Dieser Blogbeitrag gibt Ihnen einen umfassenden Überblick über das Konzept der Near Field Communication-Technologie mit Beispielen ihrer Verwendung im wirklichen Leben. Anschließend erfahren Sie, wie Sie NFC-Lesen und -Schreiben in Qt QML-Anwendungen implementieren. Wenn Sie Hilfe zu diesem Thema benötigen, können Sie sich unsere Mobile Entwicklungsdienste ansehen.

 

Was ist NFC?

NFC steht für Near Field Communication und bietet eine Möglichkeit, Daten drahtlos zu übertragen. Es entwickelte sich aus der RFID-Technologie, die elektromagnetische Induktion zur Datenübertragung nutzte. Sie haben vielleicht einen RFID-Chip in der Hand und wussten wahrscheinlich nicht einmal davon, da sie oft in Form eines Anhängers verwendet werden, der beispielsweise den Zugang zu Büroräumen ermöglicht.

NFC nutzt, genau wie andere drahtlose Übertragungstechnologien (Bluetooth, Wi-Fi), Funkwellen. Der Hauptvorteil von NFC ist jedoch die Tatsache, dass passive Geräte keine zusätzliche Stromversorgung benötigen. Wenn sich ein passives Gerät in Reichweite eines aktiven Geräts befindet, versorgt das von aktiven NFC-Geräten erzeugte elektromagnetische Feld das passive Gerät mit Strom. Im Gegensatz zu Bluetooth muss bei der Near Field Communication auch nicht zuerst eine Kopplung mit einem anderen Gerät erfolgen.

Wie der Name schon sagt, ermöglicht NFC die Datenübertragung im Nahbereich von etwa 10 Zentimetern (etwa 4 Zoll). Dieser Nahbereich wird aus Sicherheitsgründen oft als Vorteil dargestellt.

Die meisten heutigen Smartphones sind mit NFC-Antennen ausgestattet und sind aktive NFC-Geräte. Was bedeutet das? Aktive Geräte ermöglichen uns das Senden und Empfangen von Daten, indem sie miteinander oder mit passiven Geräten kommunizieren. Passive Geräte hingegen können weder mit aktiven noch mit passiven Geräten eine Verbindung herstellen. Diese Art von Geräten wird normalerweise als interaktive Tags verwendet, um bestimmte Daten zu speichern.

 

3 Anwendungsbeispiele für NFC

Schauen Sie sich an, wie NFC-Technologie im Alltag eingesetzt wird. Lassen Sie sich inspirieren, wie Sie von der Verwendung von NFC in Ihrer App profitieren können.

 

Mobile Zahlungen mit NFC

Sowohl Android- als auch iPhone-Geräte verwenden NFC, um sichere, drahtlose Zahlungen durchzuführen, die in vielen Ländern der Welt zu einer gängigen Zahlungsmethode für Waren geworden sind. Mit NFC können Sie Ihr Telefon dank einer integrierten NFC-Antenne wie eine drahtlose Kreditkarte verwenden.

Viele digitale Geldbörsenplattformen wie Google Pay, Apple Pay oder Samsung Pay nutzen NFC, sodass Sie sie zusammen mit dieser Technologie verwenden können.

 

 

Teilen zwischen zwei aktiven Geräten mit NFC

Unter Android haben Sie die Möglichkeit, Daten von einem Smartphone auf ein anderes zu übertragen, indem Sie einfach beide Geräte Rücken an Rücken berühren. Nach der Bestätigung werden die Daten schnell gesendet.

 

NFC-Tags

Wie bereits erwähnt, benötigen passive NFC-Geräte keine eigene Stromquelle und können so programmiert werden, dass sie eine Vielzahl von Aufgaben ausführen und verschiedene Arten von Daten speichern. Eine beliebte und dennoch einfache Verwendung von NFC-Tags besteht darin, einen neben das Bett zu legen und ihn so zu programmieren, dass er automatisch den Lautlosmodus aktiviert, wenn er mit dem Telefon berührt wird.

Natürlich sind dies nur einige Beispiele für die Verwendung der NFC-Technologie. Die Anzahl der möglichen Verwendungen von NFC-Tags ist unendlich. Lesen Sie weiter, um einen Blick auf die Verwendungsimplementierung von NFC-Chips in Qt QML/Anwendung zu werfen.

 

Wie implementieren Sie NFC in Ihrer Qt/QML-Anwendung?

Zu den vielen Funktionen des funktionsreichen Qt-Frameworks gehört ein Qt NFC-Modul, das die Kommunikation über NFC mit aktiven und passiven Geräten ermöglicht. Derzeit unterstützt das Modul Linux mit Neard und Android. Sehen wir uns an, wie Sie NFC in Ihrer Qt QML-Anwendung implementieren.

Beginnen wir zunächst mit einer Idee für eine mobile Anwendung, die NFC-Tags nutzt. Ich möchte eine Anwendung haben, die meinem Koch das Leben erleichtert. Sie ermöglicht es Benutzern, den Namen eines Gerichts auf einem NFC-Tag zu platzieren, zusammen mit der Zeitangabe, wie lange das Kochen oder Backen dauert. Wenn ein solcher Tag berührt wird, startet die Anwendung einen Timer, der von dieser Zeit an herunterzählt, und löst dann einen akustischen Alarm aus. Auf diese Weise verbrennen Sie nie Ihr Geschirr.

Die präsentierte Demo ist einfach, aber gut genug, um die tatsächliche Einführung von NFC in der Qt-App zu zeigen, einschließlich:

  • Erkennung von NFC-Tags;

  • Schreiben von NFC-Tags;

  • Lesen von NFC-Tags;

  • Offenlegen von C++-Objekten und -Klassen für QML;

In diesem Blogbeitrag wird nicht der in QML erstellte UI-Teil behandelt. Sie können sich daher gerne den vollständigen Quellcode ansehen, der im Github-Profil von Scythe Studio zu finden ist.

 

NFC-Tag-Erkennung

Beginnen wir mit dem wichtigsten Teil der NFC-Implementierung – der Erkennung. Wir haben die Klasse NFCManager erstellt, die für alle NFC-Aktionen wie Erkennen, Lesen und Schreiben verantwortlich sein soll. Sie wird QML auf einfache Weise zugänglich gemacht dank des Makros QML_ELEMENT, das in Qt 5.15 eingeführt wurde.

Neben anderen Mitgliedern und Methoden gibt es den Zeiger QNearFieldManager, der für die Steuerung der NFC-Zielerkennung entscheidend ist.

 

// directives, forward declarations
// Record struct declaration

class NFCManager : public QObject
{
    Q_OBJECT
    Q_PROPERTY(bool hasTagInRange READ hasTagInRange NOTIFY hasTagInRangeChanged)
    Q_PROPERTY(ActionType actionType READ actionType WRITE setActionType NOTIFY actionTypeChanged)
    Q_PROPERTY(Record record READ record NOTIFY recordChanged)
    QML_ELEMENT

public:
    explicit NFCManager(QObject *parent = nullptr);

    enum ActionType
    {
        None = 0,
        Reading,
        Writing
    };
    Q_ENUM(ActionType)

    bool hasTagInRange() const;
    ActionType actionType() const;
    Record record() const;

 

public slots:
    void startReading();
    void stopDetecting();
    void saveRecord(const QString &dishName, int seconds);

signals:
    void hasTagInRangeChanged(bool hasTagInRange);
    void actionTypeChanged(ActionType actionType);
    void recordChanged(const Record &record);

    void wroteSuccessfully();
    void nfcError(const QString &error);

private slots:
    void setActionType(ActionType actionType);
    void setHasTagInRange(bool hasTagInRange);

    void onTargetDetected(QNearFieldTarget *target);
    void onTargetLost(QNearFieldTarget *target);

    void onNdefMessageRead(const QNdefMessage &message);
    void onNdefMessageWritten();
    void handleTargetError(QNearFieldTarget::Error error, const QNearFieldTarget::RequestId &id);

private:
    bool m_hasTagInRange = false;
    ActionType m_actionType = ActionType::None;

    Record m_record;
    QNearFieldManager *m_manager;
    QNearFieldTarget::RequestId m_request;

};

Im Klassenkonstruktor müssen Sie die QNearFieldManager-Instanz initialisieren und entsprechende Signale verbinden, um NFC-Ereignisse verarbeiten zu können. Die Signale, die uns interessieren, sind `QNearFieldManager::targetDetected` und `QNearFieldManager::targetLost`. Wie die Namen schon andeuten, werden sie gesendet, wenn das Zielgerät (aktiv oder passiv) den Erkennungsbereich betritt oder verlässt.

 

NFCManager::NFCManager(QObject *parent)
    : QObject(parent)
    , m_manager(new QNearFieldManager(this)
{
    connect(m_manager, &QNearFieldManager::targetDetected,
            this, &NFCManager::onTargetDetected);

    connect(m_manager, &QNearFieldManager::targetLost,
            this, &NFCManager::onTargetLost);
}<span class="EOP"> </span>

Signale werden nicht gesendet, es sei denn, wir fordern die QNearFieldManager-Instanz auf, die Erkennung zu starten. Dazu müssen Sie die Methode `QNearFieldManager::startTargetDetection` für die Objektinstanz aufrufen. Stellen Sie vor dem Starten der Erkennung den Zielzugriffsmodus ein, um QNearFieldManager mitzuteilen, was Sie mit dem Zielgerät tun möchten – entweder lesen oder schreiben. Zum Lesen müssen Sie den Zielzugriffsmodus auf `QNearFieldManager::NdefReadTargetAccess` einstellen und zum Schreiben `QNearFieldManager::NdefWriteTargetAccess` verwenden.

 

void NFCManager::startReading()
{
    setActionType(ActionType::Reading);
    m_manager->setTargetAccessModes(QNearFieldManager::NdefReadTargetAccess);
    m_manager->startTargetDetection();
}

void NFCManager::stopDetecting()
{
    setActionType(ActionType::None);
    m_manager->setTargetAccessModes(QNearFieldManager::NoTargetAccess);
    m_manager->stopTargetDetection();
}

Der obige Codeausschnitt zeigt Ihnen, wie Sie die Erkennung zum Lesen starten und wie Sie die Erkennung unabhängig vom aktuellen Zugriffsmodus stoppen. Es wird auch die Methode `NFCManager::setActionType()` verwendet, aber sie ist nicht Teil der Qt NFC API. Sie wird in dieser Demo verwendet, um anzugeben, welche Aktion (Lesen, Schreiben, Keine) gerade ausgeführt wird.

 

NFC-Tags schreiben

Nachdem der Erkennungsteil abgeschlossen ist, müssen wir das NFCManager-Verhalten implementieren, wenn das Tag den Bereich betritt und verlässt. Lassen Sie uns zunächst das Verhalten zum Schreiben von Tags implementieren, um einige Daten darauf zu platzieren. Für diese Demo habe ich NFC-Tag-Aufkleber verwendet.

 

Möglicherweise fällt Ihnen auf, dass der NFCManager ein `Record m_record`-Element hat. Diese Variable wird verwendet, um Daten zu speichern, die auf das Tag geschrieben oder von einem Tag gelesen werden sollen. `Record` ist eine Struktur, also schauen wir uns ihre Deklaration an.

 

struct Record {
    Q_GADGET
    Q_PROPERTY(int seconds MEMBER seconds)
    Q_PROPERTY(QString dishName MEMBER dishName)

public:
    int seconds = 0;
    QString dishName = "";
    bool parseNdefMessage(const QNdefNfcTextRecord &record);
    QNdefMessage generateNdefMessage() const;
};
Q_DECLARE_METATYPE(Record)

Die Struktur hat zwei Felder, die für die Speicherung des Gerichtsnamens und der Kochzeit in Sekunden zuständig sind. Um Ndef-Nachrichten auf das Zielgerät zu schreiben, müssen Sie QNdefMessage mithilfe der in einer Struktur gespeicherten Daten generieren. QNdefMessage ist eine Sammlung von QNdefRecords, die einzelne Teile einer Nachricht sind. Die beste Möglichkeit, NFC in einer Qt/QML-Anwendung zu implementieren, besteht darin, eine abgeleitete Klasse basierend auf QNdefRecord zu erstellen. Um diese Demo einfach zu halten, nehmen wir an, dass wir nur eine Nachricht mit einem Datensatz auf einem Tag speichern und der Inhalt des Tags eine JSON-Zeichenfolge ist.

 

QNdefMessage Record::generateNdefMessage() const
{
    if (dishName.isEmpty() || seconds <= 0) {
        return QNdefMessage();
    }

    QNdefMessage message; 

    QVariantMap recordMap{};
    recordMap[DISHNAME] = dishName;
    recordMap[SECONDS] = seconds;

    const QJsonDocument &doc = QJsonDocument::fromVariant(recordMap); 

    QNdefNfcTextRecord record;
    record.setEncoding(QNdefNfcTextRecord::Utf8);
    record.setText(doc.toJson());
    message.append(record);

    return message;
}

So könnten Sie eine Methode zum Generieren von QNdefMessage aus Ihrer eigenen Struktur implementieren. Zuerst wird ein JSON-Dokument erstellt und dann als Text für die Variable QNdefNfcTextRecord festgelegt. Dieser Datensatz wird dann in QNdefMessage eingefügt.

 

void NFCManager::saveRecord(const QString &dishName, int seconds)
{
    m_record.dishName = dishName;
    m_record.seconds = seconds;

    setActionType(ActionType::Writing);
    m_manager->setTargetAccessModes(QNearFieldManager::NdefWriteTargetAccess);
    m_manager->startTargetDetection();
}

Als nächsten Schritt werden wir uns die Implementierung von `NFCManager::saveRecord` ansehen, die der Methode `NFCManager::startReading` ziemlich ähnlich ist, aber zwei zusätzliche Parameter hat, um den Namen des Gerichts und die Kochzeit in m_record zu speichern. Außerdem hat sie einen anderen Zielzugriffsmodus. Diese Methode wird vom QML-Teil mit Parametern aufgerufen, die aus der Benutzereingabe abgerufen werden.

 

Es ist Zeit, ein tatsächliches Verhalten bei der Zielerkennung zu implementieren. Zu diesem Zweck verwenden wir das interne Element m_actionType, um zu entscheiden, was in einer bestimmten Situation zu tun ist, da das Signal `QNearFieldManager::targetDetected` unabhängig vom tatsächlichen Zielzugriffsmodus ausgegeben wird.

 

void NFCManager::onTargetDetected(QNearFieldTarget *target)
{
    setHasTagInRange(true);

    switch (m_actionType) {
    case None:
        break;
    case Reading:
        // reading ...
        break;
    case Writing:
        connect(target, &QNearFieldTarget::ndefMessagesWritten, this, &NFCManager::onNdefMessageWritten);
        connect(target, &QNearFieldTarget::error, this, &NFCManager::handleTargetError);

        m_request = target->writeNdefMessages(QList<QNdefMessage>() << m_record.generateNdefMessage());

        if (!m_request.isValid()) {
            handleTargetError(QNearFieldTarget::NdefWriteError, m_request);
        }
        break;
    }
}

An diesem Punkt können Sie sehen, dass es überhaupt nicht kompliziert ist. Sie müssen lediglich `QNearFieldTarget::writeNdefMessages` auf dem erkannten Ziel mit einer Liste der auf das Ziel zu schreibenden Nachrichten als Parameter aufrufen. Für diese Demo hat die Liste nur ein einziges Element, nämlich eine aus der Datensatzstruktur generierte Nachricht.

Um stille Fehler zu vermeiden, sollten Sie das Ergebnis des Aufrufs der im Klassenmitglied m_request gespeicherten Methode validieren und es mit `QNearFieldTarget::error` verbinden.

 

void NFCManager::onNdefMessageWritten()
{
    stopDetecting();
    m_request = QNearFieldTarget::RequestId();

    emit wroteSuccessfully();
}

Denken Sie jedoch daran, eine Verbindung zum `QNearFieldTarget::ndefMessagesWritten`-Signal des Ziels herzustellen, um das erfolgreiche Schreiben von Nachrichten zu gewährleisten. Bei einer solchen Methode können Sie die Erkennung beenden, m_request leeren und ein Signal senden, das anzeigt, dass alles wie vorgesehen funktioniert hat.

Das ist alles zum Schreiben auf NFC-Tags in der Qt-App. Rufen Sie nun die Methode `NFCManager::saveRecord` auf der NFCManager-Instanz auf, die QML ausgesetzt ist, und berühren Sie ein Tag mit Ihrem Telefon. Der Name des Gerichts und die Kochzeit sollten erfolgreich auf ein Tag geschrieben werden.

 

 

NFC-Tags lesen

Wir haben bereits einige Daten zum Tag – jetzt ist es Zeit zum Lesen. Rufen Sie in der Definition von `NFCManager::onTargetDetected` im richtigen Switch-Case (zuvor kommentiert) `QNearFieldTarget::readNdefMessages()` für das erkannte Ziel auf und speichern Sie das Ergebnis im Klassenmitglied m_request. Stellen Sie jedoch vorher eine Verbindung zu `QNearFieldTarget::ndefMessageRead` her, um den Inhalt des Tags abzurufen. Denken Sie an die Behandlung von Fehlerfällen.

Beim Lesen von NFC-Tags spielt `NFCManager::onNdefMessageRead` die erste Geige. Es wird mit QNdefMessage als Parameter geliefert, daher müssen wir zuerst die Datensätze in dieser Nachricht durchlaufen und nach Datensätzen vom Typ QNdefNfcTextRecord suchen. Da Sie diesen Typ zum Schreiben der Nachricht verwendet haben, ist dies der einzige Typ, der uns interessiert. Wenn ein Datensatz dieses Typs erfolgreich von der Methode `Record::parseNdefMessage` analysiert wurde, beenden wir die Iteration, stoppen die Erkennung und senden ein Signal aus, das anzeigt, dass sich der Datensatz geändert hat. Dann können Sie dieses Signal in QML verarbeiten.

Das ist alles, was Sie wissen müssen. Um dieses Tutorial formal abzuschließen, schauen wir uns an, wie Sie `Record::parseNdefMessage` implementieren könnten.

 

bool Record::parseNdefMessage(const QNdefNfcTextRecord &record)
{
    const QJsonDocument &doc = QJsonDocument::fromJson(record.text().toUtf8());
    const QJsonObject &recordObject = doc.object();
 
    if (!recordObject.contains(DISHNAME) || !recordObject.contains(DISHNAME)) {
        return false;
    }

    dishName = recordObject[DISHNAME].toString();
    seconds = recordObject[SECONDS].toInt();

    return true;
}

Wie Sie sehen, gibt es hier nichts besonders Schwieriges. Und der Parameter fNfcTextRecord hat eine Textmethode, die die gespeicherte Zeichenfolge zurückgibt. Von diesem Punkt aus können Sie es wie üblich als JSON analysieren.

 

 

So verwenden Sie NFC in Qt/QML-Anwendungen – Zusammenfassung

Vielen Dank, dass Sie sich mit uns mit NFC in Qt vertraut gemacht haben. Dank dieses Blogbeitrags sollten Sie:

  • verstehen, was Near Field Communication-Technologie ist;

  • wissen, wofür NFC verwendet wird und wie Sie davon profitieren können;

  • wissen, wie das Erkennen, Schreiben und Lesen von NFC-Zielen in Qt/QML-Anwendungen implementiert wird;

 

Scythe-Studio - Chief Executive Officer

Łukasz Kosiński Chief Executive Officer

Brauchen Sie Qt QML-Entwicklungsdienste?

service partner

Kommen wir zur Sache: Es ist eine Herausforderung, Top-Qt-QML-Entwickler zu finden. Helfen Sie sich selbst und starten Sie die Zusammenarbeit mit Scythe Studio – echten Experten im Qt C++ Framework.

Entdecken Sie unsere Fähigkeiten!

Neueste Artikel

[ 156 ]