如何使用Qt 5.6在Android上运行NFC
我试图使用Qt的NFC模块在我的Android手机上阅读NFC标签。
根据这个页面 ,Qt将从5.6版本开始支持Android。 这个版本还没有发布,所以我从源码开始构build,遵循这个页面上的说明,并安装在Qt创build器中。
第一步是让标签/卡检测工作,我卡在那里。 我的testing应用程序实例化一个QNearFieldManager
,检查NFC是否可用,并将插槽连接到信号targetLost
和targetLost
。 QNearFieldManager::isAvailable
方法报告NFC是可用的(Qt 5.5没有),但是targetLost
/ targetLost
信号永远不会被触发。
以下是我的testing应用程序的代码:
#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"; }
我肯定错过了什么…
更新1
看起来AndroidManifest.xml文件需要修改。 我尝试了不同的东西,但似乎没有产生预期的效果。 我只能得到targetLost
和targetLost
事件,当清单定义一个intent-filter这样的filter时:
<intent-filter> <action android:name="android.nfc.action.TAG_DISCOVERED"/> <category android:name="android.intent.category.DEFAULT"/> </intent-filter>
但是,这也会导致应用程序在每次扫描目标时启动,即使应用程序已经在运行。 我需要的是启动应用程序,然后等待目标被扫描。 我怎样才能做到这一点?
更新2
下面是我试过的完整的AndroidManifest.xml文件。
<?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>
如果您使用的是某个制造商的NFC标签,则移动NFC中也应该存在相同的NFC标签,那么现在NFC将不会全球支持。 例如。 如果Sony设备内部的NFC存在将仅支持其制造,并且在大多数情况下不能连接到其他设备,如连接点。 所以试着find你的制造商并连接它。 希望它可以帮助你..
我不相信你需要清单中的那些意图filter。 添加这些,告诉操作系统在检测到标签时启动您的应用程序(这就是为什么它是这样做的)。 这看起来好像是在代码中正确注册NFC事件,所以也许问题在于手机中的NFC芯片的品牌,以及您正在使用的testing标签。 如果您的手机配备了Broadcom NFC芯片,而您尝试使用恩智浦的Mifare Classic标签,则会遇到问题。 使用Desfire或NTAG标签可能会有所帮助。
我已经解决了这个问题。
原因在于,在QtNfc.java中 ,qt处理NFC意图的时候,通过过滤ACTION_NDEF_DISCOVERED动作( 和ACTION_TECH_DISCOVERED作为NDEF标签,将报告为技术 ), 而不用简单的ACTION_TAG_DISCOVERED( 尽pipe它在getStartIntentfunction中处理它),它只处理 NDEF标签 。
但是我想你只是想扫描一个简单的标签来阅读uid,就像我一样。 所以你需要在QtNfc.java start()函数中添加ACTION_TAG_DISCOVERED来过滤列表:
IntentFilter[] filters = new IntentFilter[3]; filters[0] = new IntentFilter(); filters[0].addAction(NfcAdapter.ACTION_TAG_DISCOVERED); filters[0].addCategory(Intent.CATEGORY_DEFAULT); ...
我认为在setContext中将filter修改为ACTION_TAG_DISCOVERED会更正确。 最快的方法是打开qt creator qtconnectivity .pro为相应的分支,正确的QtNfc.java,build立它,并replaceandroid_armv7 \ lib中的libQt5Nfc.so qt文件夹(QtNfc.jar和QtNfc-bundled.jar在android_armv7 \ jar文件夹将在构build期间更新)。
那是。 无需在工作应用程序中修改清单。
顺便说一下这个:
<uses-permission android:name="android.permission.NFC"/>
qt添加到.pro模块nfc时自动添加
这个
<uses-feature android:name="android.hardware.nfc" android:required="true"/>
没有必要我想。 它没有它的工作。
但是如果你想告诉android在Anansi提到的标签被检测到的时候启动你的应用,你可以添加这个intent-filter。 但我真的推荐在应用程序活动(如这里 )中添加android:alwaysRetainTaskState =“true”android:launchMode =“singleInstance”。
我用android 4.4.4 tablet和ndefeditor的例子testing了这一切。 它发射targetDetected / targetLost完美。 系统中可以有另一个默认的应用程序(例如NFC阅读器 ),并在每个标签检测时打开,但不是ndefeditor正在等待标签(button检索)的时间。 当然对于非NDEF标签,qt示例显示为“NDEF读取错误”,但它检测到它们并读取uid。 正是我所需要的。
我将这个build议添加到Qt Jira并提交补丁 。
唯一我不明白的 – 为什么ndefeditor曾经在android 4.2的平板电脑上工作过。 也许这是一个硬件方面和另一台平板电脑上的android总是intent ACTION_NDEF_DISCOVERED?
你好,下面是答案,让我知道,如果你只是在寻找这个。 :)首先写在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() } };
在onCreate()外面写这个onNewIntent
@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()); } } }
您将在strTagDatavariables中获得NFC数据
清单中的许可
- Android工作室错误“检测到不支持的模块:以下模块不支持编译”
- 如何防止广告拦截器阻止应用上的广告
- PreferenceActivity Android 4.0及更早版本
- 错误:在Android Studio中找不到名称为“default”的configuration
- FileProvider crash – npe尝试调用空string上的XmlResourceParser
- Android构buildgradle太慢(依赖分辨率)
- 内部类中访问variables。 需要被宣布为最终
- :app:dexDebug ExecException用非零的退出值2结束
- 将一个库/ JAR添加到Eclipse Android项目中