An example showing reading from formatted NFC Data Exchange Format (NDEF) messages.
The Annotated URL example displays the contents of specifically formatted NFC Data Exchange Format (NDEF) messages read from an NFC Tag. The NDEF message should contain a URI record, an optional
image/*
MIME record, and one or more localized Text records.
这是范例的初始状态:
In this example the NFC Tag used contains a text record and an URI record. The UI gets updated accordingly to:
When the screen is tapped, the URL will be opened in the browser.
AnnotatedUrl
类包裹
QNearFieldManager
, the class providing the NFC Tag detection functionality. NDEF messages are read by
QNearFieldManager
and forwarded to a handler contained in the
AnnotatedUrl
class. After parsing the NDEF message the class emits the
annotatedUrl()
signal. The UI reacts to the signal displaying the contents of the NDEF message.
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()
method is used to defer the actual tag detection until all the connections between the UI and NFC-related logic are established. This is important when the application is automatically started once an NFC tag is touched. Such usecase is currently supported on 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(); }
As it is mentioned above, the application supports the NDEF messages of a specific format. A correct message should contain the following fields:
The order of the records is not strictly specified.
实例化的 QNdefFilter is used to validate the NDEF message. The filter is populated as follows:
messageFilter.setOrderMatch(false); messageFilter.appendRecord<QNdefNfcTextRecord>(1, 100); messageFilter.appendRecord<QNdefNfcUriRecord>(1, 1); messageFilter.appendRecord(QNdefRecord::Mime, "", 0, 1);
If the incoming message does not match the filter, an error message is shown:
注意: NDEF (NFC 数据交换格式) 编辑器 example application can be used to create the tags with correct or incorrect message structure.
NFC messages read by the
QNearFieldManager
are forwarded to
AnnotatedUrl::handleMessage
.
void AnnotatedUrl::handleMessage(const QNdefMessage &message, QNearFieldTarget *target) {
At first the messages are validated using the QNdefFilter::match () method:
if (!messageFilter.match(message)) { emit tagError("Invalid message format"); return; }
If the messages have the correct format, the parsing continues.
Because NFC messages are composed of several NDEF records, looping through all of the records allows the extraction of the 3 parameters to be displayed in the UI: the Uri, the Title and the Pixmap:
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())); }
Finally after having extracted the parameters of the NFC message the corresponding signal is emitted so that the UI can handle it.
} emit annotatedUrl(url, title, pixmap); }
On Android the adapter state changes can be detected by connecting to the
QNearFieldManager::adapterStateChanged
() signal. This allows stopping the detection when the NFC adapter is disabled, and restarting it when the adapter is enabled again. This approach is implemented in the
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 supports automatic application startup when the NDEF tag is touched. See Qt NFC on Android for the required changes to the Android manifest file.
Introduction of a custom AndroidManifest.xml requires special steps on the build system side.
When using qmake, the following needs to be added to the
.pro
文件:
android { ANDROID_PACKAGE_SOURCE_DIR = $$PWD/android DISTFILES += \ android/AndroidManifest.xml }
When using CMake, the following needs to be added to the
CMakeLists.txt
:
if(ANDROID) set_property(TARGET annotatedurl APPEND PROPERTY QT_ANDROID_PACKAGE_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/android ) endif()
要运行范例从 Qt Creator ,打开 欢迎 模式,然后选择范例从 范例 。更多信息,拜访 构建和运行范例 .
另请参阅 Qt NFC .