Qt 6.x
The Qt SDK
Loading...
Searching...
No Matches
qnearfieldmanager_ios.mm
Go to the documentation of this file.
1// Copyright (C) 2020 Governikus GmbH & Co. KG
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
5
9
11
12#include <QDateTime>
13
14#include <memory>
15
16#import <CoreNFC/NFCReaderSession.h>
17#import <CoreNFC/NFCNDEFReaderSession.h>
18#import <CoreNFC/NFCTagReaderSession.h>
19
21
23{
24 auto notifier = std::make_unique<QNfcNdefNotifier>();
25
26 if (@available(iOS 13, *))
27 delegate = [[QT_MANGLE_NAMESPACE(QIosTagReaderDelegate) alloc] initWithListener:this];
28
30 this, &QNearFieldManagerPrivateImpl::onTagDiscovered,
33 this, &QNearFieldManagerPrivateImpl::onDidInvalidateWithError,
35
36 ndefDelegate = [[QIosNfcNdefSessionDelegate alloc] initWithNotifier:notifier.get()];
37 if (ndefDelegate) {
38 auto watchDog = notifier.release(); // Delegate took the ownership.
39
41 this, &QNearFieldManagerPrivateImpl::onTagDiscovered,
44 this, &QNearFieldManagerPrivateImpl::onDidInvalidateWithError,
46 } else {
47 qCWarning(QT_IOS_NFC, "Failed to allocate NDEF reading session's delegate");
48 }
49
50 sessionTimer.setInterval(2000);
51 sessionTimer.setSingleShot(true);
52 connect(&sessionTimer, &QTimer::timeout, this, &QNearFieldManagerPrivateImpl::onSessionTimer);
53}
54
56{
57 if (@available(iOS 13, *))
58 [delegate release];
59
60 if (!ndefDelegate)
61 return;
62
63 if (auto queue = qt_Nfc_Queue()) {
64 dispatch_sync(queue, ^{
65 [ndefDelegate abort];
66 });
67 }
68
69 [ndefDelegate release];
70}
71
73{
74 switch (accessMethod) {
77 return NFCNDEFReaderSession.readingAvailable;
79 if (@available(iOS 13, *))
80 return NFCTagReaderSession.readingAvailable;
83 return false;
84 }
85}
86
88{
89 if (detectionRunning)
90 return false;
91
92 activeAccessMethod = QNearFieldTarget::UnknownAccess;
93
94 switch (accessMethod) {
97 return false;
99 if (@available(iOS 13, *))
100 if (NFCTagReaderSession.readingAvailable) {
101 detectionRunning = scheduleSession(accessMethod);
102 if (detectionRunning)
103 activeAccessMethod = accessMethod;
104 return detectionRunning;
105 }
106 return false;
108 if (NFCNDEFReaderSession.readingAvailable) {
109 detectionRunning = scheduleSession(accessMethod);
110 if (detectionRunning)
111 activeAccessMethod = accessMethod;
112 return detectionRunning;
113 }
114 return false;
115 }
116
117 return false;
118}
119
121{
122 if (!detectionRunning)
123 return;
124
125 isSessionScheduled = false;
126
127 if (activeAccessMethod == QNearFieldTarget::TagTypeSpecificAccess) {
128 stopSession(errorMessage);
129 } else if (activeAccessMethod == QNearFieldTarget::NdefAccess) {
130 stopNdefSession(errorMessage);
131 } else {
132 qCWarning(QT_IOS_NFC, "Unknown access method, cannot stop target detection");
133 return;
134 }
135
136 detectionRunning = false;
138}
139
140bool QNearFieldManagerPrivateImpl::scheduleSession(QNearFieldTarget::AccessMethod accessMethod)
141{
142 if (sessionTimer.isActive()) {
143 isSessionScheduled = true;
144 return true;
145 }
146
147 if (accessMethod == QNearFieldTarget::TagTypeSpecificAccess) {
148 startSession();
149 return true;
150 } else if (accessMethod == QNearFieldTarget::NdefAccess) {
151 return startNdefSession();
152 }
153
154 return false;
155}
156
157void QNearFieldManagerPrivateImpl::startSession()
158{
159 if (@available(iOS 13, *)) {
160 [delegate startSession];
161 }
162}
163
164bool QNearFieldManagerPrivateImpl::startNdefSession()
165{
166 if (!ndefDelegate)
167 return false;
168
169 if (auto queue = qt_Nfc_Queue()) {
170 __block bool startSessionSucceded = false;
171 dispatch_sync(queue, ^{ startSessionSucceded = [ndefDelegate startSession]; });
172 return startSessionSucceded;
173 }
174
175 return false;
176}
177
178void QNearFieldManagerPrivateImpl::stopSession(const QString &error)
179{
181
182 clearTargets();
183
184 if (@available(iOS 13, *)) {
185 [delegate stopSession:error];
186 }
187}
188
189void QNearFieldManagerPrivateImpl::stopNdefSession(const QString &error)
190{
191 Q_ASSERT(activeAccessMethod == QNearFieldTarget::NdefAccess);
192
193 clearTargets();
194
195 if (auto queue = qt_Nfc_Queue()) {
196 dispatch_sync(queue, ^{
197 [ndefDelegate stopSession:error];
198 });
199 }
200}
201
202void QNearFieldManagerPrivateImpl::clearTargets()
203{
204 auto i = detectedTargets.begin();
205 while (i != detectedTargets.end()) {
206 (*i)->invalidate();
207 Q_EMIT targetLost((*i)->q_ptr);
208 i = detectedTargets.erase(i);
209 }
210}
211
212
214{
215 if (detectionRunning) {
216 // Too late!
217 qCWarning(QT_IOS_NFC, "User information must be set prior before the targer detection started");
218 return;
219 }
220
221 [delegate alertMessage:message];
222
223 if (auto queue = qt_Nfc_Queue()) {
224 dispatch_sync(queue, ^{
225 [ndefDelegate setAlertMessage:message];
226 });
227 }
228}
229
230void QNearFieldManagerPrivateImpl::onTagDiscovered(void *tag)
231{
233 if (activeAccessMethod == QNearFieldTarget::NdefAccess) {
234 [id(tag) retain];
235 target = new QNearFieldTargetPrivateImpl(ndefDelegate, tag);
236 } else {
238 }
239
240 detectedTargets += target;
241
243 this, &QNearFieldManagerPrivateImpl::onTargetLost);
245}
246
247void QNearFieldManagerPrivateImpl::onTargetLost(QNearFieldTargetPrivateImpl *target)
248{
249 detectedTargets.removeOne(target);
250 Q_EMIT targetLost(target->q_ptr);
251
252 if (detectionRunning && detectedTargets.isEmpty())
253 onDidInvalidateWithError(true);
254}
255
256void QNearFieldManagerPrivateImpl::onDidInvalidateWithError(bool doRestart)
257{
258 clearTargets();
259 sessionTimer.start();
260
261 if (detectionRunning && doRestart && scheduleSession(activeAccessMethod))
262 return;
263
264 detectionRunning = false;
266}
267
268void QNearFieldManagerPrivateImpl::onSessionTimer()
269{
270 if (isSessionScheduled && !scheduleSession(activeAccessMethod)) {
271 detectionRunning = false;
273 }
274}
275
DarwinBluetooth::LECBManagerNotifier * notifier
std::unique_ptr< QTimer > watchDog
iterator begin()
Returns an \l{STL-style iterators}{STL-style iterator} pointing to the first item in the hash.
Definition qhash.h:1202
iterator erase(const_iterator it)
Definition qhash.h:1223
iterator end() noexcept
Returns an \l{STL-style iterators}{STL-style iterator} pointing to the imaginary item after the last ...
Definition qhash.h:1206
bool isEmpty() const noexcept
Returns true if the hash contains no items; otherwise returns false.
Definition qhash.h:926
void didInvalidateWithError(bool doRestart)
bool isSupported(QNearFieldTarget::AccessMethod accessMethod) const override
void tagDiscovered(void *tag)
bool startTargetDetection(QNearFieldTarget::AccessMethod accessMethod) override
void setUserInformation(const QString &message) override
void stopTargetDetection(const QString &errorMessage) override
void targetDetected(QNearFieldTarget *target)
void targetLost(QNearFieldTarget *target)
void targetLost(QNearFieldTargetPrivateImpl *target)
The QNearFieldTarget class provides an interface for communicating with a target device.
AccessMethod
This enum describes the access methods a near field target supports.
void tagDetected(void *tag)
void invalidateWithError(bool restart)
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
Definition qobject.cpp:2823
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:127
void setSingleShot(bool singleShot)
Definition qtimer.cpp:580
void start(int msec)
Starts or restarts the timer with a timeout interval of msec milliseconds.
Definition qtimer.cpp:208
void setInterval(int msec)
Definition qtimer.cpp:607
bool isActive() const
Returns true if the timer is running (pending); otherwise returns false.
Definition qtimer.cpp:156
void timeout(QPrivateSignal)
This signal is emitted when the timer times out.
Combined button and popup list for selecting options.
@ QueuedConnection
#define Q_FALLTHROUGH()
AudioChannelLayoutTag tag
DBusConnection const char DBusError * error
QT_BEGIN_NAMESPACE dispatch_queue_t qt_Nfc_Queue()
QString alertMessage
#define qCWarning(category,...)
GLenum GLuint id
[7]
GLenum target
GLuint GLsizei const GLchar * message
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define QT_MANGLE_NAMESPACE(name)
#define Q_EMIT
static QString errorMessage(QUrlPrivate::ErrorCode errorCode, const QString &errorSource, qsizetype errorPosition)
Definition qurl.cpp:3503
sem release()
QQueue< int > queue
[0]