How to make NFC work on Android with Qt 5.6

I am trying to read NFC tags on my Android phone using the NFC Qt module.

According to this page, Qt will support NFC on Android starting from version 5.6. This version has not yet been released, so I built it from the source, following the instructions on this page and installed it in the creator of Qt.

The first step is to get work with the tag / card, and I'm stuck there. My test application instantiates a QNearFieldManager , checks to see if NFC is available, and connects the slots to the targetDetected and targetLost . The QNearFieldManager::isAvailable reports that NFC is available (it hasn’t done it since Qt 5.5), but the targetDetected / targetLost never fire.

Below is the code for my test application:

 #include <QLabel> #include <QVBoxLayout> #include <QNearFieldManager> #include <QNearFieldTarget> #include <QDebug> #include "window.h" Window::Window(QWidget *parent) : QWidget(parent) { nfcLabel_ = new QLabel(this); QVBoxLayout *mainLayout = new QVBoxLayout; mainLayout->addWidget(nfcLabel_, 1); setLayout(mainLayout); setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed)); setWindowTitle(tr("NFC Test")); nfc_ = new QNearFieldManager(this); if (nfc_->isAvailable()) { nfcLabel_->setText("NFC available"); } else { nfcLabel_->setText("NFC not available"); qWarning() << "NFC not available"; } nfc_->setTargetAccessModes(QNearFieldManager::NdefReadTargetAccess); // doesn't help nfc_->registerNdefMessageHandler(this, SLOT(handleNdefMessage(QNdefMessage,QNearFieldTarget*))); // doesn't help connect(nfc_, SIGNAL(targetDetected(QNearFieldTarget*)), this, SLOT(targetDetected(QNearFieldTarget*))); connect(nfc_, SIGNAL(targetLost(QNearFieldTarget*)), this, SLOT(targetLost(QNearFieldTarget*))); if (!nfc_->startTargetDetection()) { qWarning() << "NFC target detection could not be started"; } } Window::~Window() { nfc_->stopTargetDetection(); } void Window::targetDetected(QNearFieldTarget * /*target*/) { nfcLabel_->setText("Target detected"); } void Window::targetLost(QNearFieldTarget *target) { nfcLabel_->setText("Target lost"); target->deleteLater(); } void Window::handleNdefMessage(const QNdefMessage &/*message*/, QNearFieldTarget */*target*/) { qDebug() << "Ndef Message"; } 

Something is missing for me ...

UPDATE 1

It looks like the AndroidManifest.xml file needs to be changed. I tried different things, but nobody seems to produce the desired effect. I can only get targetDetected and targetLost events when the manifest defines the filter intent as follows:

 <intent-filter> <action android:name="android.nfc.action.TAG_DISCOVERED"/> <category android:name="android.intent.category.DEFAULT"/> </intent-filter> 

However, this also causes the application to launch each time the target is scanned, even if the application is already running. I need to run the application and then wait for the target to be verified. How can i do this?

UPDATE 2

Below is the full AndroidManifest.xml file that I tried.

 <?xml version="1.0"?> <manifest package="org.qtproject.example" xmlns:android="http://schemas.android.com/apk/res/android" android:versionName="1.0" android:versionCode="1" android:installLocation="auto"> <application android:hardwareAccelerated="true" android:name="org.qtproject.qt5.android.bindings.QtApplication" android:label="-- %%INSERT_APP_NAME%% --" android:theme="@android:style/Theme.Holo"> <activity android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|layoutDirection|locale|fontScale|keyboard|keyboardHidden|navigation" android:name="org.qtproject.qt5.android.bindings.QtActivity" android:label="-- %%INSERT_APP_NAME%% --" android:screenOrientation="unspecified" android:launchMode="singleTop"> <intent-filter> <action android:name="android.intent.action.MAIN"/> <category android:name="android.intent.category.LAUNCHER"/> </intent-filter> <!-- Without this, the targetDetected/targetLost signals aren't fired --> <intent-filter> <action android:name="android.nfc.action.TAG_DISCOVERED"/> <category android:name="android.intent.category.DEFAULT"/> </intent-filter> <meta-data android:name="android.app.lib_name" android:value="-- %%INSERT_APP_LIB_NAME%% --"/> <meta-data android:name="android.app.qt_sources_resource_id" android:resource="@array/qt_sources"/> <meta-data android:name="android.app.repository" android:value="default"/> <meta-data android:name="android.app.qt_libs_resource_id" android:resource="@array/qt_libs"/> <meta-data android:name="android.app.bundled_libs_resource_id" android:resource="@array/bundled_libs"/> <!-- Deploy Qt libs as part of package --> <meta-data android:name="android.app.bundle_local_qt_libs" android:value="-- %%BUNDLE_LOCAL_QT_LIBS%% --"/> <meta-data android:name="android.app.bundled_in_lib_resource_id" android:resource="@array/bundled_in_lib"/> <meta-data android:name="android.app.bundled_in_assets_resource_id" android:resource="@array/bundled_in_assets"/> <!-- Run with local libs --> <meta-data android:name="android.app.use_local_qt_libs" android:value="-- %%USE_LOCAL_QT_LIBS%% --"/> <meta-data android:name="android.app.libs_prefix" android:value="/data/local/tmp/qt/"/> <meta-data android:name="android.app.load_local_libs" android:value="-- %%INSERT_LOCAL_LIBS%% --"/> <meta-data android:name="android.app.load_local_jars" android:value="-- %%INSERT_LOCAL_JARS%% --"/> <meta-data android:name="android.app.static_init_classes" android:value="-- %%INSERT_INIT_CLASSES%% --"/> <!-- Messages maps --> <meta-data android:value="@string/ministro_not_found_msg" android:name="android.app.ministro_not_found_msg"/> <meta-data android:value="@string/ministro_needed_msg" android:name="android.app.ministro_needed_msg"/> <meta-data android:value="@string/fatal_error_msg" android:name="android.app.fatal_error_msg"/> <!-- Messages maps --> <!-- Splash screen --> <!-- <meta-data android:name="android.app.splash_screen_drawable" android:resource="@drawable/logo"/> --> <!-- Splash screen --> <!-- Background running --> <!-- Warning: changing this value to true may cause unexpected crashes if the application still try to draw after "applicationStateChanged(Qt::ApplicationSuspended)" signal is sent! --> <meta-data android:name="android.app.background_running" android:value="false"/> <!-- Background running --> </activity> </application> <uses-sdk android:minSdkVersion="10" android:targetSdkVersion="14"/> <supports-screens android:largeScreens="true" android:normalScreens="true" android:anyDensity="true" android:smallScreens="true"/> <uses-feature android:name="android.hardware.nfc" android:required="true"/> <uses-permission android:name="android.permission.NFC"/> </manifest> 
+56
c ++ android qt nfc
26 Oct '15 at 12:58
source share
4 answers

If you use the NFC tag for a specific manufacturer, then the same should be present in mobile NFC, then only it will be correctly paired, since NFC does not support globally. E.g. if NFC is present in the Sony device, it will support its production as much as possible, and in most cases it will not be able to connect to other devices, such as a nexus. Therefore, try to find your manufacturer and connect it. Hope this helps you.

+1
Nov 08 '16 at 5:02
source share

I do not believe that you want those intent filters in your manifest. By adding these files, it tells the operating system to launch your application when a tag is detected (which is why it does this). It looks like you are correctly registering in your code for NFC events, so perhaps the problem is the brand of the NFC chip in your phone in combination with the tag that you use for testing. If your phone is equipped with a Broadcom NFC chip and you are trying to use the NXP Mifare Classic tag, you will run into problems. Using a handle or NTAG tag can help.

+1
Dec 07 '16 at 23:57
source share

I decided this one.

The reason is that in QtNfc.java , where qt handles NFC, it only handles NDEF by filtering ACTION_NDEF_DISCOVERED (and ACTION_TECH_DISCOVERED actions for NDEF tags that will be reported as technical) without a simple ACTION_TAG_DISCOVERED (despite the fact that it works with getStentIntent fuction).

But I suggested that you just want to scan a simple tag to read uid, just like me. Therefore, you need to add ACTION_TAG_DISCOVERED for the filter list in the QtNfc.java start () function:

 IntentFilter[] filters = new IntentFilter[3]; filters[0] = new IntentFilter(); filters[0].addAction(NfcAdapter.ACTION_TAG_DISCOVERED); filters[0].addCategory(Intent.CATEGORY_DEFAULT); ... 

I think it would be better to modify the filter in ACTION_TAG_DISCOVERED in setContext. The quickest way is to open qtconnectivity .pro in qt creator for the corresponding branch, fix QtNfc.java, build it and replace libQt5Nfc.so in the android_armv7 \ lib qt folder (QtNfc.jar and QtNfc-bundled.jar in the android_armv7 \ jar folder will be updated during assembly).

I.e. There is no need to change the manifest in the working application.

By the way, this one:

 <uses-permission android:name="android.permission.NFC"/> 

qt is automatically added when adding the nfc module to .pro

This

 <uses-feature android:name="android.hardware.nfc" android:required="true"/> 

not necessary. He works without him.

But you can add this intent filter if you want to tell the android to start your application when the tag is detected as Anansi mentioned above. But I really recommend adding android: alwaysRetainTaskState = "true" android: launchMode = "singleInstance" in the application (for example, here ).

I am testing all of this with the Android android 4.4.4 example and ndefeditor. It does a great job with targetDetected / targetLost. The system may have another default application for tags (for example, NFC Reader ), and it opens at each tag discovery, but not for the time being ndefeditor is a pending tag (retrieve button). And of course, the qt example says "Error reading NDEF" for tags other than NDEF, but detects them and reads uid. Exactly what I need.

I add the sentence to Qt Jira and submit the patch.

The only thing I did not understand was why ndefeditor was working on another tablet with Android 4.0. Maybe this is a hardware aspect, and the android on the other tablet has always been aimed at ACTION_NDEF_DISCOVERED?

+1
Mar 13 '17 at 19:00
source share

Hi, below is the answer, let me know if you are looking for this only. :) First write this in onCreate ()

 //Code in onCreate mNfcAdapter = NfcAdapter.getDefaultAdapter(this); mPendingIntent = PendingIntent.getActivity(this, 0, new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0); // set an intent filter for all MIME data IntentFilter ndefIntent = new IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED); try { ndefIntent.addDataType("*/*"); mIntentFilters = new IntentFilter[] { ndefIntent }; } catch (Exception e) { Log.fnLogToFile(strFunctionName + "-" + e.getMessage(), ErrorType.ERROR); Log.createCrashReport(); } mNFCTechLists = new String[][] { new String[] { NfcF.class.getName() } }; 

Write this onNewIntent outside onCreate ()

 @Override public void onNewIntent(Intent intent) { StackTraceElement[] arrFunctionName = Thread.currentThread().getStackTrace() ; String strFunctionName = arrFunctionName[arrFunctionName.length-1].getMethodName(); Log.fnLogToFile(strFunctionName + "Entered", ErrorType.INFO); tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG); String strTagData = ""; // parse through all NDEF messages and their records and pick text type only Parcelable[] data = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES); if (data != null) { try { for (int i = 0; i < data.length; i++) { NdefRecord [] recs = ((NdefMessage)data[i]).getRecords(); for (int j = 0; j < recs.length; j++) { if (recs[j].getTnf() == NdefRecord.TNF_WELL_KNOWN && Arrays.equals(recs[j].getType(), NdefRecord.RTD_TEXT)) { byte[] payload = recs[j].getPayload(); String textEncoding = ((payload[0] & 0200) == 0) ? "UTF-8" : "UTF-16"; int langCodeLen = payload[0] & 0077; //tag data is saved in strTagData strTagData += ("\n" + new String(payload, langCodeLen + 1, payload.length - langCodeLen - 1, textEncoding)); } } } } catch (Exception e) { Log.fnLogToFile(strFunctionName + "-" + e.getMessage(), ErrorType.ERROR); Log.createCrashReport(); Log.e("TagDispatch", e.toString()); } } } 

You will get NFC data in strTagData variable p>

Manifest permission

-3
Jan 20 '16 at 7:09
source share



All Articles