9#import <CoreNFC/NFCNDEFReaderSession.h>
10#import <CoreNFC/NFCReaderSession.h>
11#import <CoreNFC/NFCTagReaderSession.h>
12#import <CoreNFC/NFCISO7816Tag.h>
13#import <CoreNFC/NFCTag.h>
15#include <QtCore/qapplicationstatic.h>
16#include <QtCore/qloggingcategory.h>
28 id some =
static_cast<id>(
obj);
30 if ([some conformsToProtocol:
@protocol(NFCNDEFTag)])
31 [
static_cast<id<NFCNDEFTag>
>(some)
release];
32 else if ([some conformsToProtocol:
@protocol(NFCTag)])
33 [
static_cast<id<NFCTag>
>(some)
release];
55 Q_ASSERT([
id(
tag) conformsToProtocol:
@protocol(NFCNDEFTag)]);
58 notifier = [qtDelegate ndefNotifier];
79 ndefOperations.clear();
89 sessionDelegate = nil;
100 if (!nfcTag || isNdefTag())
103 if (@available(
iOS 13, *)) {
104 id<NFCTag>
tag =
static_cast<id<NFCTag>
>(nfcTag.get());
105 id<NFCISO7816Tag> iso7816Tag =
tag.asNFCISO7816Tag;
107 return QByteArray::fromNSData(iso7816Tag.identifier);
115 if (!nfcTag || isNdefTag())
118 if (@available(
iOS 13, *)) {
119 id<NFCTag>
tag =
static_cast<id<NFCTag>
>(nfcTag.get());
120 id<NFCISO7816Tag> iso7816Tag =
tag.asNFCISO7816Tag;
122 if (
tag.type != NFCTagTypeISO7816Compatible || iso7816Tag == nil)
125 if (iso7816Tag.historicalBytes != nil && iso7816Tag.applicationData == nil)
128 if (iso7816Tag.historicalBytes == nil && iso7816Tag.applicationData != nil)
142 if (@available(
iOS 13, *)) {
143 id<NFCTag>
tag =
static_cast<id<NFCTag>
>(nfcTag.get());
144 if (
tag && [
tag conformsToProtocol:@protocol(NFCISO7816Tag)])
182 return hasNDEFMessage;
187 hasNDEFMessage =
false;
192 qCWarning(QT_IOS_NFC,
"Target does not allow to read NDEF messages, "
193 "was not detected as NDEF tag by the reader session?");
202 ndefOperations.push_back(op);
213 qCWarning(QT_IOS_NFC,
"Target does not allow to write NDEF messages, "
214 "was not detected as NDEF tag by the reader session?");
219 if (messages.size() != 1) {
224 qCWarning(QT_IOS_NFC,
"Only one NDEF message per request ID can be written");
233 ndefOperations.push_back(op);
241 if (requestInProgress.
isValid())
244 const auto tagIsAvailable = [
this](
auto tag) {
245 return tag && (!connected ||
tag.available);
249 return tagIsAvailable(
static_cast<id<NFCNDEFTag>
>(nfcTag.get()));
251 if (@available(
iOS 13, *))
252 return tagIsAvailable(
static_cast<id<NFCTag>
>(nfcTag.get()));
259 if (connected || requestInProgress.
isValid())
263 return connected =
true;
268 if (@available(
iOS 13, *)) {
269 requestInProgress = queue.
head().first;
270 id<NFCTag>
tag =
static_cast<id<NFCTag>
>(nfcTag.get());
271 NFCTagReaderSession* session =
tag.session;
272 [session connectToTag:
tag completionHandler: ^(NSError*
error){
273 const bool success =
error == nil;
292bool QNearFieldTargetPrivateImpl::isNdefTag()
const
294 const id tag =
static_cast<id>(nfcTag.get());
295 if ([
tag conformsToProtocol:@protocol(NFCMiFareTag)])
297 if ([
tag conformsToProtocol:@protocol(NFCFeliCaTag)])
299 if ([
tag conformsToProtocol:@protocol(NFCISO15693Tag)])
301 if ([
tag conformsToProtocol:@protocol(NFCISO7816Tag)])
303 return [
tag conformsToProtocol:
@protocol(NFCNDEFTag)];
306void QNearFieldTargetPrivateImpl::onTargetCheck()
322QNdefMessage ndefToQtNdefMessage(NFCNDEFMessage *nativeMessage)
327 QList<QNdefRecord> ndefRecords;
328 for (NFCNDEFPayload *ndefRecord
in nativeMessage.records) {
330 if (ndefRecord.typeNameFormat != NFCTypeNameFormatUnchanged)
332 if (ndefRecord.identifier)
333 qtNdefRecord.setId(QByteArray::fromNSData(ndefRecord.identifier));
335 qtNdefRecord.setType(QByteArray::fromNSData(ndefRecord.type));
336 if (ndefRecord.payload)
337 qtNdefRecord.setPayload(QByteArray::fromNSData(ndefRecord.payload));
338 ndefRecords.push_back(qtNdefRecord);
346void QNearFieldTargetPrivateImpl::onExecuteRequest()
348 if (!nfcTag || requestInProgress.
isValid())
352 if (ndefOperations.empty())
360 const auto op = ndefOperations.front();
361 ndefOperations.pop_front();
365 id<NFCNDEFTag> ndefTag =
static_cast<id<NFCNDEFTag>
>(nfcTag.get());
368 auto *cbNotifier = guard.get();
375 this, &QNearFieldTargetPrivateImpl::messageRead,
379 [ndefTag readNDEFWithCompletionHandler:^(NFCNDEFMessage * _Nullable msg, NSError * _Nullable err) {
380 const std::unique_ptr<QNfcNdefNotifier> notifierGuard(cbNotifier);
382 NSLog(
@"Reading NDEF messaged ended with error: %@", err);
387 const QNdefMessage ndefMessage(ndefToQtNdefMessage(msg));
392 this, &QNearFieldTargetPrivateImpl::messageWritten,
398 NFCNDEFMessage *ndefMessage = [NFCNDEFMessage ndefMessageWithData:ndefData];
401 [ndefTag writeNDEF:ndefMessage completionHandler:^(NSError *err) {
402 const std::unique_ptr<QNfcNdefNotifier> notifierGuard(cbNotifier);
404 NSLog(
@"Writing NDEF messaged ended with error: %@", err);
416 if (@available(
iOS 13, *)) {
420 requestInProgress =
request.first;
421 const auto tag =
static_cast<id<NFCISO7816Tag>
>(nfcTag.get());
422 auto *apdu = [[[NFCISO7816APDU alloc] initWithData:
request.second.toNSData()] autorelease];
423 [
tag sendCommandAPDU: apdu completionHandler: ^(NSData* responseData, uint8_t sw1, uint8_t sw2, NSError*
error){
424 QByteArray recvBuffer = QByteArray::fromNSData(responseData);
425 recvBuffer +=
static_cast<char>(sw1);
426 recvBuffer +=
static_cast<char>(sw2);
427 const bool success =
error == nil;
428 responseProvider->provideResponse(
request.first, success, recvBuffer);
450 hasNDEFMessage =
message.size() != 0;
453 requestInProgress = {};
461 requestInProgress = {};
bool isEmpty() const noexcept
The QNdefMessage class provides an NFC NDEF message.
Q_NFC_EXPORT QByteArray toByteArray() const
Returns the NDEF message as a byte array.
The QNdefRecord class provides an NFC NDEF record.
TypeNameFormat
This enum describes the type name format of an NDEF record.
void setTypeNameFormat(TypeNameFormat typeNameFormat)
Sets the type name format of the NDEF record to typeNameFormat.
void targetLost(QNearFieldTargetPrivateImpl *target)
QNearFieldTarget::RequestId writeNdefMessages(const QList< QNdefMessage > &messages) override
int maxCommandLength() const override
QNearFieldTarget::RequestId readNdefMessages() override
~QNearFieldTargetPrivateImpl() override
QNearFieldTargetPrivateImpl(QJniObject intent, const QByteArray uid, QObject *parent=nullptr)
void ndefMessageRead(const QNdefMessage &message, const QNearFieldTarget::RequestId &id)
QNearFieldTarget::Type type() const override
QNearFieldTarget::RequestId sendCommand(const QByteArray &command) override
QNearFieldTarget::AccessMethods accessMethods() const override
bool hasNdefMessage() override
QTimer * targetCheckTimer
QByteArray uid() const override
void error(QNearFieldTarget::Error error, const QNearFieldTarget::RequestId &id)
virtual void setResponseForRequest(const QNearFieldTarget::RequestId &id, const QVariant &response, bool emitRequestCompleted=true)
void requestCompleted(const QNearFieldTarget::RequestId &id)
void reportError(QNearFieldTarget::Error error, const QNearFieldTarget::RequestId &id)
\inmodule QtNfc \inheaderfile QNearFieldTarget
bool isValid() const
Returns true if this is a valid request id; otherwise returns false.
The QNearFieldTarget class provides an interface for communicating with a target device.
Type
This enum describes the type of tag the target is detected as.
Error
This enum describes the error codes that a near field target reports.
void tagError(QNearFieldTarget::Error code, QNearFieldTarget::RequestId request)
void ndefMessageRead(const QNdefMessage &message, QNearFieldTarget::RequestId request)
void ndefMessageWritten(QNearFieldTarget::RequestId request)
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
static bool disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *member)
\threadsafe
void enqueue(const T &t)
Adds value t to the tail of the queue.
T & head()
Returns a reference to the queue's head item.
T dequeue()
Removes the head item in the queue and returns it.
void start(int msec)
Starts or restarts the timer with a timeout interval of msec milliseconds.
void stop()
Stops the timer.
void timeout(QPrivateSignal)
This signal is emitted when the timer times out.
void responseReceived(QNearFieldTarget::RequestId requestId, bool success, QByteArray recvBuffer)
Combined button and popup list for selecting options.
#define Q_APPLICATION_STATIC(TYPE, NAME,...)
AudioChannelLayoutTag tag
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter int const void return DBusMessageIter DBusMessageIter return DBusMessageIter void DBusMessageIter void int return DBusMessage DBusMessageIter return DBusMessageIter return DBusMessageIter DBusMessageIter const char const char const char const char return DBusMessage return DBusMessage const char return DBusMessage dbus_bool_t return DBusMessage dbus_uint32_t return DBusMessage void
DBusConnection const char DBusError * error
QNearFieldTarget::RequestId requestId
QT_BEGIN_NAMESPACE dispatch_queue_t qt_Nfc_Queue()
#define qCWarning(category,...)
GLuint GLsizei const GLchar * message
QNetworkRequest request(url)
QNearFieldTarget::RequestId requestId
enum NdefOperation::Type type
void operator()(void *tag)