如何使用Qt 5.6在NFC上运行NFC

Pat*_*Pat 56 c++ qt android nfc qt5.6

我正在尝试使用Qt的NFC模块在我的Android手机上阅读NFC标签.

根据这个页面,Qt将从5.6版开始支持Android上的NFC.此版本尚未发布,因此我按照此页面上的说明从源代码构建它,并将其安装在Qt创建器中.

第一步是让标签/卡检测工作,我就卡在那里.我的测试应用程序实例化a QNearFieldManager,检查NFC是否可用并将插槽连接到信号targetDetectedtargetLost.该QNearFieldManager::isAvailable方法报告NFC可用(Qt 5.5没有),但信号targetDetected/ targetLost从未被触发.

以下是我的测试应用程序的代码:

#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";
}
Run Code Online (Sandbox Code Playgroud)

我肯定错过了什么...

更新1

似乎需要修改AndroidManifest.xml文件.我尝试了不同的东西,但似乎都没有产生预期的效果.当清单定义像这样的intent-filter时,我只能获取targetDetectedtargetLost触发的事件:

<intent-filter>
    <action android:name="android.nfc.action.TAG_DISCOVERED"/>
    <category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
Run Code Online (Sandbox Code Playgroud)

但是,这也会导致每次扫描目标时启动应用程序,即使应用程序已在运行.我需要的是启动应用程序,然后等待扫描目标.我怎么能做到这一点?

更新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>
Run Code Online (Sandbox Code Playgroud)

小智 -3

您好,下面是答案,如果您只是在寻找这个,请告诉我。:) 首先把这个写在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() } };
Run Code Online (Sandbox Code Playgroud)

在 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());
            }

        }
    }
Run Code Online (Sandbox Code Playgroud)

您将在 strTagData 变量中获取 NFC 数据

清单中的权限

  • 对我来说看起来是实时的 java 代码,但我需要让它在 Qt (C++) 中工作 (2认同)