Как заставить NFC работать на Android с помощью Qt 5.6

Я пытаюсь прочитать теги NFC на своем телефоне Android с помощью модуля NFC Qt.

Согласно этому страница, Qt будет поддерживать NFC на Android начиная с версии 5.6. Эта версия еще не была выпущена, поэтому я собрал ее из исходного кода, следуя инструкциям на этом страница, и установил его в Qt создатель.

Первый шаг — заставить работать определение тега / карты, и я застрял там. Мое тестовое приложение создает экземпляр QNearFieldManagerпроверяет наличие NFC и соединяет слоты с сигналами targetDetected а также targetLost,
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";
}

Я должен что-то упустить …

ОБНОВЛЕНИЕ 1

Похоже, что файл AndroidManifest.xml необходимо изменить. Я пробовал разные вещи, но ни одна из них не дала желаемого эффекта. Я могу только получить targetDetected а также targetLost события, которые запускаются, когда манифест определяет фильтр намерений, например так:

<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>

56

Решение

Если вы используете метку NFC определенного производителя, то же самое должно присутствовать и в мобильной NFC, и только тогда она будет правильно соединяться, поскольку на данный момент NFC не поддерживается глобально. Например, если NFC, присутствующий внутри устройства Sony, будет максимально поддерживать только его производство, и в большинстве случаев он не сможет подключиться к другим устройствам, таким как Nexus. Поэтому постарайтесь найти своего производителя и подключить его. Надеюсь, это поможет вам ..

1

Другие решения

Я не верю, что вы хотите эти фильтры намерений в вашем манифесте. Добавление этих параметров указывает операционной системе на запуск приложения при обнаружении тега (именно поэтому он делает это). Похоже, вы правильно регистрируетесь в своем коде для событий NFC, поэтому, возможно, проблема заключается в марке чипа NFC в вашем телефоне в сочетании с тегом, который вы используете для тестирования. Если ваш телефон оснащен чипом Broadcom NFC и вы пытаетесь использовать тег NXP Mifare Classic, у вас возникнут проблемы. Использование Desfire или тега NTAG может помочь.

1

Я решил это.

Причина в том, что в QtNfc.java где Qt обрабатывает NFC намеренно обрабатывает только ЦНК теги путем фильтрации действий ACTION_NDEF_DISCOVERED (и ACTION_TECH_DISCOVERED для тегов NDEF, которые будут сообщаться как технические) без простой ACTION_TAG_DISCOVERED (несмотря на то, что он обрабатывает его в функции getStartIntent).

Но я предположил, что вы просто хотите отсканировать простой тег для чтения uid, как и я. Поэтому вам нужно добавить ACTION_TAG_DISCOVERED в список фильтров в функции start () QtNfc.java:

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

Я думаю, что было бы правильнее изменить фильтр на ACTION_TAG_DISCOVERED в setContext тоже.
Самый быстрый способ — открыть в Qt Creator. qtconnectivity .pro для соответствующей ветки, исправьте QtNfc.java, соберите его и замените libQt5Nfc.so в папке android_armv7 \ lib qt (QtNfc.jar и QtNfc-bundled.jar в папке android_armv7 \ jar будут обновлены во время сборки).

То есть. Нет необходимости изменять манифест в рабочем приложении.

Кстати этот:

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

qt добавляется автоматически при добавлении модуля nfc в .pro

Вот этот

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

не нужно, я полагаю. Это работает без этого.

Но вы можете добавить этот намеренный фильтр, если хотите, чтобы Android запустил ваше приложение при обнаружении тега, как упомянул Ананси выше. Но я очень рекомендую добавить
android: alwaysRetainTaskState = «true» android: launchMode = «singleInstance» в активности приложения (например, Вот).

Я тестирую все это на планшете android 4.4.4 и на примере ndefeditor. Он прекрасно запускает targetDetected / targetLost. В системе может быть другое приложение по умолчанию для тегов (например, NFC Reader) и он открывается при каждом обнаружении тега, но не во время, когда ndefeditor ожидает тег (кнопка получения). И, конечно, пример qt говорит «Ошибка чтения NDEF» для не-NDEF тегов, но он обнаруживает их и читает uid. Именно то, что мне было нужно.

Я добавляю предложение Qt Jira и представить пластырь.

Единственное, чего я не понял — почему ndefeditor работал на другом планшете с android 4.2. Может быть, это аппаратный аспект и андроид на другом планшете всегда был намерен ACTION_NDEF_DISCOVERED?

1

Привет ниже ответ, дайте мне знать, если вы ищете только это. 🙂
Сначала напишите это в 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() } };

Напишите это на NewIntent снаружи 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());
}

}
}

Вы получите данные NFC в переменной strTagData

Разрешение в Манифесте

-3
По вопросам рекламы [email protected]