@exxili/capacitor-nfc 0.0.11 → 0.0.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +274 -103
- package/android/src/main/kotlin/com/exxili/capacitornfc/NFCPlugin.kt +157 -42
- package/dist/esm/definitions.d.ts +81 -8
- package/dist/esm/definitions.js.map +1 -1
- package/dist/esm/index.d.ts +2 -2
- package/dist/esm/index.js +225 -44
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/web.d.ts +5 -8
- package/dist/esm/web.js +10 -22
- package/dist/esm/web.js.map +1 -1
- package/dist/plugin.cjs.js +234 -65
- package/dist/plugin.cjs.js.map +1 -1
- package/dist/plugin.js +234 -65
- package/dist/plugin.js.map +1 -1
- package/ios/Sources/NFCPlugin/NFCPlugin.swift +71 -18
- package/ios/Sources/NFCPlugin/NFCReader.swift +456 -46
- package/ios/Sources/NFCPlugin/NFCWriter.swift +9 -16
- package/package.json +13 -4
|
@@ -1,42 +1,307 @@
|
|
|
1
1
|
import Foundation
|
|
2
2
|
import CoreNFC
|
|
3
|
+
// swiftlint:disable:next type_body_length
|
|
4
|
+
@objc public class NFCReader: NSObject, NFCTagReaderSessionDelegate, NFCNDEFReaderSessionDelegate {
|
|
5
|
+
public func tagReaderSessionDidBecomeActive(_ session: NFCTagReaderSession) {
|
|
6
|
+
// Intentionally left blank; no special handling needed when tag session becomes active.
|
|
7
|
+
}
|
|
8
|
+
private enum ReaderMode {
|
|
9
|
+
case fullTag
|
|
10
|
+
case limitedTag
|
|
11
|
+
case ndefFallback
|
|
12
|
+
|
|
13
|
+
var alertSuffix: String {
|
|
14
|
+
switch self {
|
|
15
|
+
case .fullTag:
|
|
16
|
+
return "."
|
|
17
|
+
case .limitedTag:
|
|
18
|
+
return " (compatibility mode)."
|
|
19
|
+
case .ndefFallback:
|
|
20
|
+
return " (NDEF mode)."
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
var metadataValue: String {
|
|
25
|
+
switch self {
|
|
26
|
+
case .fullTag:
|
|
27
|
+
return "full"
|
|
28
|
+
case .limitedTag:
|
|
29
|
+
return "compat"
|
|
30
|
+
case .ndefFallback:
|
|
31
|
+
return "ndef"
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
3
35
|
|
|
4
|
-
|
|
5
|
-
private var
|
|
36
|
+
private var readerSession: NFCTagReaderSession?
|
|
37
|
+
private var ndefReaderSession: NFCNDEFReaderSession?
|
|
38
|
+
private var readerMode: ReaderMode = .fullTag
|
|
39
|
+
private var autoRestartWorkItem: DispatchWorkItem?
|
|
40
|
+
private var entitlementFailureDetected = false
|
|
41
|
+
private var lastFallbackSignature: (mode: ReaderMode, reason: String?)?
|
|
6
42
|
|
|
7
|
-
public var onNDEFMessageReceived: (([NFCNDEFMessage]) -> Void)?
|
|
43
|
+
public var onNDEFMessageReceived: (([NFCNDEFMessage], [String: Any]?) -> Void)?
|
|
8
44
|
public var onError: ((Error) -> Void)?
|
|
9
45
|
|
|
46
|
+
@objc public func setPreferredReaderMode(_ rawMode: String?) {
|
|
47
|
+
guard let rawMode = rawMode?.lowercased() else { return }
|
|
48
|
+
switch rawMode {
|
|
49
|
+
case "full", "advanced", "forcefull":
|
|
50
|
+
readerMode = .fullTag
|
|
51
|
+
entitlementFailureDetected = false
|
|
52
|
+
lastFallbackSignature = nil
|
|
53
|
+
case "compat", "compatibility", "limited":
|
|
54
|
+
readerMode = .limitedTag
|
|
55
|
+
lastFallbackSignature = nil
|
|
56
|
+
case "ndef":
|
|
57
|
+
readerMode = .ndefFallback
|
|
58
|
+
lastFallbackSignature = nil
|
|
59
|
+
case "auto":
|
|
60
|
+
if entitlementFailureDetected {
|
|
61
|
+
if readerMode == .fullTag {
|
|
62
|
+
readerMode = .limitedTag
|
|
63
|
+
}
|
|
64
|
+
} else {
|
|
65
|
+
readerMode = .fullTag
|
|
66
|
+
lastFallbackSignature = nil
|
|
67
|
+
}
|
|
68
|
+
default:
|
|
69
|
+
break
|
|
70
|
+
}
|
|
71
|
+
if readerMode == .fullTag {
|
|
72
|
+
lastFallbackSignature = nil
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
10
76
|
@objc public func startScanning() {
|
|
11
77
|
print("NFCReader startScanning called")
|
|
12
|
-
|
|
13
78
|
guard NFCNDEFReaderSession.readingAvailable else {
|
|
14
79
|
print("NFC scanning not supported on this device")
|
|
15
80
|
return
|
|
16
81
|
}
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
82
|
+
if readerMode != .fullTag {
|
|
83
|
+
let reason = entitlementFailureDetected ? "missing-entitlement" : nil
|
|
84
|
+
emitFallbackMetadata(for: readerMode, reason: reason)
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
autoRestartWorkItem?.cancel()
|
|
88
|
+
startCurrentModeSession()
|
|
20
89
|
}
|
|
21
90
|
|
|
22
|
-
|
|
23
|
-
|
|
91
|
+
@objc public func cancelScanning() {
|
|
92
|
+
autoRestartWorkItem?.cancel()
|
|
93
|
+
autoRestartWorkItem = nil
|
|
94
|
+
if let session = readerSession { session.invalidate() }
|
|
95
|
+
if let ndef = ndefReaderSession { ndef.invalidate() }
|
|
96
|
+
readerSession = nil
|
|
97
|
+
ndefReaderSession = nil
|
|
98
|
+
lastFallbackSignature = nil
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
public func tagReaderSession(_ session: NFCTagReaderSession, didInvalidateWithError error: Error) {
|
|
24
102
|
print("NFC reader session error: \(error.localizedDescription)")
|
|
103
|
+
lastFallbackSignature = nil
|
|
104
|
+
readerSession = nil
|
|
105
|
+
guard let nfcError = error as? NFCReaderError else {
|
|
106
|
+
onError?(error)
|
|
107
|
+
return
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
if handleEntitlementOrSystemErrors(nfcError) {
|
|
111
|
+
return
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
if nfcError.code == .readerSessionInvalidationErrorUserCanceled {
|
|
115
|
+
return
|
|
116
|
+
}
|
|
117
|
+
|
|
25
118
|
onError?(error)
|
|
26
119
|
}
|
|
27
120
|
|
|
28
|
-
|
|
29
|
-
|
|
121
|
+
private func startCurrentModeSession() {
|
|
122
|
+
switch readerMode {
|
|
123
|
+
case .fullTag:
|
|
124
|
+
beginTagSession(pollingOption: [.iso14443, .iso15693, .iso18092])
|
|
125
|
+
case .limitedTag:
|
|
126
|
+
beginTagSession(pollingOption: [.iso14443])
|
|
127
|
+
case .ndefFallback:
|
|
128
|
+
beginNDEFFallbackSession()
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
private func beginTagSession(pollingOption: NFCTagReaderSession.PollingOption) {
|
|
133
|
+
guard NFCTagReaderSession.readingAvailable else {
|
|
134
|
+
print("[NFC] Tag reading not supported on this device")
|
|
135
|
+
return
|
|
136
|
+
}
|
|
137
|
+
DispatchQueue.main.async {
|
|
138
|
+
if let existingSession = self.readerSession {
|
|
139
|
+
existingSession.invalidate()
|
|
140
|
+
}
|
|
141
|
+
self.ndefReaderSession?.invalidate()
|
|
142
|
+
self.ndefReaderSession = nil
|
|
143
|
+
|
|
144
|
+
guard let session = NFCTagReaderSession(pollingOption: pollingOption, delegate: self, queue: nil) else {
|
|
145
|
+
print("[NFC] Failed to create NFCTagReaderSession (nil).")
|
|
146
|
+
return
|
|
147
|
+
}
|
|
148
|
+
session.alertMessage = "Hold your iPhone near the NFC tag" + self.readerMode.alertSuffix
|
|
149
|
+
self.readerSession = session
|
|
150
|
+
session.begin()
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
private func beginNDEFFallbackSession() {
|
|
155
|
+
guard NFCNDEFReaderSession.readingAvailable else { return }
|
|
156
|
+
DispatchQueue.main.async {
|
|
157
|
+
if self.ndefReaderSession != nil { return }
|
|
158
|
+
let session = NFCNDEFReaderSession(delegate: self, queue: nil, invalidateAfterFirstRead: false)
|
|
159
|
+
session.alertMessage = "Hold your iPhone near the NFC tag. (NDEF mode)"
|
|
160
|
+
self.ndefReaderSession = session
|
|
161
|
+
session.begin()
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
private func scheduleRestart(after delay: TimeInterval = 0.25) {
|
|
166
|
+
autoRestartWorkItem?.cancel()
|
|
167
|
+
let workItem = DispatchWorkItem { [weak self] in
|
|
168
|
+
guard let self = self else { return }
|
|
169
|
+
self.autoRestartWorkItem = nil
|
|
170
|
+
self.startCurrentModeSession()
|
|
171
|
+
}
|
|
172
|
+
autoRestartWorkItem = workItem
|
|
173
|
+
DispatchQueue.main.asyncAfter(deadline: .now() + delay, execute: workItem)
|
|
30
174
|
}
|
|
31
175
|
|
|
176
|
+
private func emitFallbackMetadata(for mode: ReaderMode, reason: String? = nil) {
|
|
177
|
+
guard mode != .fullTag else { return }
|
|
178
|
+
if let last = lastFallbackSignature, last.mode == mode, last.reason == reason {
|
|
179
|
+
return
|
|
180
|
+
}
|
|
181
|
+
lastFallbackSignature = (mode, reason)
|
|
182
|
+
|
|
183
|
+
var metadata: [String: Any] = [
|
|
184
|
+
"fallback": true,
|
|
185
|
+
"fallbackMode": mode.metadataValue
|
|
186
|
+
]
|
|
187
|
+
if let reason = reason {
|
|
188
|
+
metadata["reason"] = reason
|
|
189
|
+
}
|
|
190
|
+
DispatchQueue.main.async {
|
|
191
|
+
self.onNDEFMessageReceived?([], metadata)
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
private func handleEntitlementOrSystemErrors(_ error: NFCReaderError) -> Bool {
|
|
196
|
+
let description = error.localizedDescription.lowercased()
|
|
197
|
+
|
|
198
|
+
if description.contains("missing required entitlement") || error.code == .readerErrorSecurityViolation {
|
|
199
|
+
if readerMode == .fullTag {
|
|
200
|
+
print("[NFC] Missing advanced tag entitlement detected -> switching to compatibility mode")
|
|
201
|
+
readerMode = .limitedTag
|
|
202
|
+
entitlementFailureDetected = true
|
|
203
|
+
emitFallbackMetadata(for: readerMode, reason: "missing-entitlement")
|
|
204
|
+
scheduleRestart()
|
|
205
|
+
return true
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
if readerMode == .limitedTag {
|
|
209
|
+
print("[NFC] Compatibility mode also unavailable -> falling back to NDEF session")
|
|
210
|
+
readerMode = .ndefFallback
|
|
211
|
+
entitlementFailureDetected = true
|
|
212
|
+
emitFallbackMetadata(for: readerMode, reason: "missing-entitlement")
|
|
213
|
+
scheduleRestart()
|
|
214
|
+
return true
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
if description.contains("system resource unavailable") || error.code == .readerSessionInvalidationErrorSystemIsBusy {
|
|
219
|
+
print("[NFC] System resource unavailable; retrying current reader mode")
|
|
220
|
+
scheduleRestart(after: 0.35)
|
|
221
|
+
return true
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
return false
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// MARK: - NFCNDEFReaderSessionDelegate
|
|
228
|
+
public func readerSession(_ session: NFCNDEFReaderSession, didInvalidateWithError error: Error) {
|
|
229
|
+
print("NDEF reader session error: \(error.localizedDescription)")
|
|
230
|
+
if session === ndefReaderSession {
|
|
231
|
+
ndefReaderSession = nil
|
|
232
|
+
lastFallbackSignature = nil
|
|
233
|
+
}
|
|
234
|
+
onError?(error)
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// Called when the NFCNDEFReaderSession becomes active (needed to silence runtime delegate warning)
|
|
32
238
|
public func readerSessionDidBecomeActive(_ session: NFCNDEFReaderSession) {
|
|
33
|
-
|
|
239
|
+
let isFallback = (session === ndefReaderSession)
|
|
240
|
+
print("NDEF reader session became active (fallback mode: \(isFallback))")
|
|
241
|
+
if isFallback {
|
|
242
|
+
let reason = entitlementFailureDetected ? "missing-entitlement" : nil
|
|
243
|
+
emitFallbackMetadata(for: .ndefFallback, reason: reason)
|
|
244
|
+
}
|
|
34
245
|
}
|
|
35
246
|
|
|
36
|
-
// Handle detection of NDEF tags (need to connect and read the NDEF message)
|
|
37
247
|
public func readerSession(_ session: NFCNDEFReaderSession, didDetect tags: [NFCNDEFTag]) {
|
|
248
|
+
// Mirror writer logic for reading first NDEF tag
|
|
249
|
+
if tags.count > 1 {
|
|
250
|
+
let retryInterval = DispatchTimeInterval.milliseconds(500)
|
|
251
|
+
session.alertMessage = "More than one tag detected. Please try again."
|
|
252
|
+
DispatchQueue.global().asyncAfter(deadline: .now() + retryInterval) {
|
|
253
|
+
session.restartPolling()
|
|
254
|
+
}
|
|
255
|
+
return
|
|
256
|
+
}
|
|
257
|
+
guard let tag = tags.first else { return }
|
|
258
|
+
session.connect(to: tag) { connectError in
|
|
259
|
+
if let connectError = connectError {
|
|
260
|
+
session.invalidate(errorMessage: "Unable to connect to tag.")
|
|
261
|
+
self.onError?(connectError)
|
|
262
|
+
return
|
|
263
|
+
}
|
|
264
|
+
tag.queryNDEFStatus { status, _, statusError in
|
|
265
|
+
if let statusError = statusError {
|
|
266
|
+
session.invalidate(errorMessage: "Unable to query the NDEF status of tag.")
|
|
267
|
+
self.onError?(statusError)
|
|
268
|
+
return
|
|
269
|
+
}
|
|
270
|
+
guard status != .notSupported else {
|
|
271
|
+
session.invalidate(errorMessage: "Tag is not NDEF compliant.")
|
|
272
|
+
return
|
|
273
|
+
}
|
|
274
|
+
tag.readNDEF { message, readError in
|
|
275
|
+
if let readError = readError {
|
|
276
|
+
session.invalidate(errorMessage: "Failed to read NDEF message.")
|
|
277
|
+
self.onError?(readError)
|
|
278
|
+
return
|
|
279
|
+
}
|
|
280
|
+
if let message = message {
|
|
281
|
+
session.alertMessage = "Found 1 NDEF message."
|
|
282
|
+
session.invalidate()
|
|
283
|
+
self.onNDEFMessageReceived?([message], nil)
|
|
284
|
+
} else {
|
|
285
|
+
session.alertMessage = "No NDEF message found."
|
|
286
|
+
session.invalidate()
|
|
287
|
+
self.onNDEFMessageReceived?([], nil)
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
// Some SDK versions (and build settings) still require this legacy delegate method.
|
|
295
|
+
public func readerSession(_ session: NFCNDEFReaderSession, didDetectNDEFs messages: [NFCNDEFMessage]) {
|
|
296
|
+
// Forward directly; no tag info available in this callback.
|
|
297
|
+
if !messages.isEmpty {
|
|
298
|
+
session.invalidate()
|
|
299
|
+
onNDEFMessageReceived?(messages, nil)
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
public func tagReaderSession(_ session: NFCTagReaderSession, didDetect tags: [NFCTag]) {
|
|
38
304
|
if tags.count > 1 {
|
|
39
|
-
// Restart polling in 500ms
|
|
40
305
|
let retryInterval = DispatchTimeInterval.milliseconds(500)
|
|
41
306
|
session.alertMessage = "More than one tag detected. Please remove extra tags and try again."
|
|
42
307
|
DispatchQueue.global().asyncAfter(deadline: .now() + retryInterval) {
|
|
@@ -44,54 +309,199 @@ import CoreNFC
|
|
|
44
309
|
}
|
|
45
310
|
return
|
|
46
311
|
}
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
312
|
+
|
|
313
|
+
guard let tag = tags.first else {
|
|
314
|
+
session.invalidate(errorMessage: "No tag found.")
|
|
315
|
+
return
|
|
316
|
+
}
|
|
50
317
|
session.connect(to: tag) { (error: Error?) in
|
|
51
318
|
if let error = error {
|
|
52
|
-
session.
|
|
319
|
+
session.invalidate(errorMessage: "Unable to connect to tag.")
|
|
320
|
+
self.onError?(error)
|
|
321
|
+
return
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
// Extract tag information
|
|
325
|
+
let tagInfo = self.extractTagInfo(from: tag)
|
|
326
|
+
|
|
327
|
+
// Try to read NDEF if the tag supports it
|
|
328
|
+
if case let .iso7816(iso7816Tag) = tag {
|
|
329
|
+
self.handleISO7816Tag(iso7816Tag, session: session, tagInfo: tagInfo)
|
|
330
|
+
} else if case let .miFare(miFareTag) = tag {
|
|
331
|
+
self.handleMiFareTag(miFareTag, session: session, tagInfo: tagInfo)
|
|
332
|
+
} else if case let .feliCa(feliCaTag) = tag {
|
|
333
|
+
self.handleFeliCaTag(feliCaTag, session: session, tagInfo: tagInfo)
|
|
334
|
+
} else if case let .iso15693(iso15693Tag) = tag {
|
|
335
|
+
self.handleISO15693Tag(iso15693Tag, session: session, tagInfo: tagInfo)
|
|
336
|
+
} else {
|
|
337
|
+
// Unknown tag type, still return tag info
|
|
338
|
+
session.alertMessage = "Tag detected but no NDEF message found."
|
|
53
339
|
session.invalidate()
|
|
340
|
+
self.onNDEFMessageReceived?([], tagInfo)
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
private func extractTagInfo(from tag: NFCTag) -> [String: Any] {
|
|
346
|
+
var tagInfo: [String: Any] = [:]
|
|
347
|
+
var techTypes: [String] = []
|
|
348
|
+
var uid: String = ""
|
|
349
|
+
|
|
350
|
+
switch tag {
|
|
351
|
+
case .iso7816(let iso7816Tag):
|
|
352
|
+
uid = iso7816Tag.identifier.map { String(format: "%02X", $0) }.joined()
|
|
353
|
+
techTypes.append("ISO7816")
|
|
354
|
+
tagInfo["type"] = "ISO7816"
|
|
355
|
+
|
|
356
|
+
case .miFare(let miFareTag):
|
|
357
|
+
uid = miFareTag.identifier.map { String(format: "%02X", $0) }.joined()
|
|
358
|
+
techTypes.append("MiFare")
|
|
359
|
+
tagInfo["type"] = "MiFare"
|
|
360
|
+
|
|
361
|
+
case .feliCa(let feliCaTag):
|
|
362
|
+
uid = feliCaTag.currentIDm.map { String(format: "%02X", $0) }.joined()
|
|
363
|
+
techTypes.append("FeliCa")
|
|
364
|
+
tagInfo["type"] = "FeliCa"
|
|
365
|
+
|
|
366
|
+
case .iso15693(let iso15693Tag):
|
|
367
|
+
uid = iso15693Tag.identifier.map { String(format: "%02X", $0) }.joined()
|
|
368
|
+
techTypes.append("ISO15693")
|
|
369
|
+
tagInfo["type"] = "ISO15693"
|
|
370
|
+
|
|
371
|
+
@unknown default:
|
|
372
|
+
techTypes.append("Unknown")
|
|
373
|
+
tagInfo["type"] = "Unknown"
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
tagInfo["uid"] = uid
|
|
377
|
+
tagInfo["techTypes"] = techTypes
|
|
378
|
+
|
|
379
|
+
return tagInfo
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
private func handleMiFareTag(_ miFareTag: NFCMiFareTag, session: NFCTagReaderSession, tagInfo: [String: Any]) {
|
|
383
|
+
miFareTag.queryNDEFStatus { (ndefStatus: NFCNDEFStatus, capacity: Int, error: Error?) in
|
|
384
|
+
if let error = error {
|
|
385
|
+
session.invalidate(errorMessage: "Unable to query NDEF status of tag.")
|
|
54
386
|
self.onError?(error)
|
|
55
387
|
return
|
|
56
388
|
}
|
|
57
|
-
|
|
58
|
-
|
|
389
|
+
|
|
390
|
+
if ndefStatus == .notSupported {
|
|
391
|
+
session.alertMessage = "Tag detected but no NDEF message found."
|
|
392
|
+
session.invalidate()
|
|
393
|
+
self.onNDEFMessageReceived?([], tagInfo)
|
|
394
|
+
return
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
var updatedTagInfo = tagInfo
|
|
398
|
+
updatedTagInfo["maxSize"] = capacity
|
|
399
|
+
updatedTagInfo["isWritable"] = ndefStatus == .readWrite
|
|
400
|
+
|
|
401
|
+
miFareTag.readNDEF { (message: NFCNDEFMessage?, error: Error?) in
|
|
59
402
|
if let error = error {
|
|
60
|
-
session.
|
|
403
|
+
session.invalidate(errorMessage: "Failed to read NDEF from tag.")
|
|
404
|
+
self.onError?(error)
|
|
405
|
+
return
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
if let message = message {
|
|
409
|
+
session.alertMessage = "Found 1 NDEF message."
|
|
61
410
|
session.invalidate()
|
|
411
|
+
self.onNDEFMessageReceived?([message], updatedTagInfo)
|
|
412
|
+
} else {
|
|
413
|
+
session.alertMessage = "Tag detected but no NDEF message found."
|
|
414
|
+
session.invalidate()
|
|
415
|
+
self.onNDEFMessageReceived?([], updatedTagInfo)
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
private func handleISO7816Tag(_ iso7816Tag: NFCISO7816Tag, session: NFCTagReaderSession, tagInfo: [String: Any]) {
|
|
422
|
+
// ISO7816 tags don't typically support NDEF directly
|
|
423
|
+
session.alertMessage = "Tag detected but no NDEF message found."
|
|
424
|
+
session.invalidate()
|
|
425
|
+
self.onNDEFMessageReceived?([], tagInfo)
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
private func handleFeliCaTag(_ feliCaTag: NFCFeliCaTag, session: NFCTagReaderSession, tagInfo: [String: Any]) {
|
|
429
|
+
feliCaTag.queryNDEFStatus { (ndefStatus: NFCNDEFStatus, capacity: Int, error: Error?) in
|
|
430
|
+
if let error = error {
|
|
431
|
+
session.invalidate(errorMessage: "Unable to query NDEF status of tag.")
|
|
432
|
+
self.onError?(error)
|
|
433
|
+
return
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
if ndefStatus == .notSupported {
|
|
437
|
+
session.alertMessage = "Tag detected but no NDEF message found."
|
|
438
|
+
session.invalidate()
|
|
439
|
+
self.onNDEFMessageReceived?([], tagInfo)
|
|
440
|
+
return
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
var updatedTagInfo = tagInfo
|
|
444
|
+
updatedTagInfo["maxSize"] = capacity
|
|
445
|
+
updatedTagInfo["isWritable"] = ndefStatus == .readWrite
|
|
446
|
+
|
|
447
|
+
feliCaTag.readNDEF { (message: NFCNDEFMessage?, error: Error?) in
|
|
448
|
+
if let error = error {
|
|
449
|
+
session.invalidate(errorMessage: "Failed to read NDEF from tag.")
|
|
62
450
|
self.onError?(error)
|
|
63
451
|
return
|
|
64
452
|
}
|
|
65
|
-
|
|
66
|
-
if
|
|
67
|
-
session.alertMessage = "
|
|
453
|
+
|
|
454
|
+
if let message = message {
|
|
455
|
+
session.alertMessage = "Found 1 NDEF message."
|
|
68
456
|
session.invalidate()
|
|
457
|
+
self.onNDEFMessageReceived?([message], updatedTagInfo)
|
|
458
|
+
} else {
|
|
459
|
+
session.alertMessage = "Tag detected but no NDEF message found."
|
|
460
|
+
session.invalidate()
|
|
461
|
+
self.onNDEFMessageReceived?([], updatedTagInfo)
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
private func handleISO15693Tag(_ iso15693Tag: NFCISO15693Tag, session: NFCTagReaderSession, tagInfo: [String: Any]) {
|
|
468
|
+
iso15693Tag.queryNDEFStatus { (ndefStatus: NFCNDEFStatus, capacity: Int, error: Error?) in
|
|
469
|
+
if let error = error {
|
|
470
|
+
session.invalidate(errorMessage: "Unable to query NDEF status of tag.")
|
|
471
|
+
self.onError?(error)
|
|
472
|
+
return
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
if ndefStatus == .notSupported {
|
|
476
|
+
session.alertMessage = "Tag detected but no NDEF message found."
|
|
477
|
+
session.invalidate()
|
|
478
|
+
self.onNDEFMessageReceived?([], tagInfo)
|
|
479
|
+
return
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
var updatedTagInfo = tagInfo
|
|
483
|
+
updatedTagInfo["maxSize"] = capacity
|
|
484
|
+
updatedTagInfo["isWritable"] = ndefStatus == .readWrite
|
|
485
|
+
|
|
486
|
+
iso15693Tag.readNDEF { (message: NFCNDEFMessage?, error: Error?) in
|
|
487
|
+
if let error = error {
|
|
488
|
+
session.invalidate(errorMessage: "Failed to read NDEF from tag.")
|
|
489
|
+
self.onError?(error)
|
|
69
490
|
return
|
|
70
491
|
}
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
if let message = message {
|
|
83
|
-
print("NDEF message read: \(message)")
|
|
84
|
-
statusMessage = "Found 1 NDEF message."
|
|
85
|
-
session.alertMessage = statusMessage
|
|
86
|
-
session.invalidate()
|
|
87
|
-
self.onNDEFMessageReceived?([message])
|
|
88
|
-
} else {
|
|
89
|
-
statusMessage = "No NDEF message found."
|
|
90
|
-
session.alertMessage = statusMessage
|
|
91
|
-
session.invalidate()
|
|
92
|
-
}
|
|
492
|
+
|
|
493
|
+
if let message = message {
|
|
494
|
+
session.alertMessage = "Found 1 NDEF message."
|
|
495
|
+
session.invalidate()
|
|
496
|
+
self.onNDEFMessageReceived?([message], updatedTagInfo)
|
|
497
|
+
} else {
|
|
498
|
+
session.alertMessage = "Tag detected but no NDEF message found."
|
|
499
|
+
session.invalidate()
|
|
500
|
+
self.onNDEFMessageReceived?([], updatedTagInfo)
|
|
93
501
|
}
|
|
94
502
|
}
|
|
95
503
|
}
|
|
96
504
|
}
|
|
97
505
|
}
|
|
506
|
+
|
|
507
|
+
// Removed supplemental stubs (logNFCFormatsIfAvailable, tagReaderSessionDidBecomeActive) as they are no longer needed.
|
|
@@ -31,7 +31,7 @@ import CoreNFC
|
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
public func readerSessionDidBecomeActive(_ session: NFCNDEFReaderSession) {
|
|
34
|
-
|
|
34
|
+
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
public func readerSession(_ session: NFCNDEFReaderSession, didDetect tags: [NFCNDEFTag]) {
|
|
@@ -48,33 +48,28 @@ import CoreNFC
|
|
|
48
48
|
|
|
49
49
|
session.connect(to: tag) { (error) in
|
|
50
50
|
if let error = error {
|
|
51
|
-
session.
|
|
52
|
-
session.invalidate()
|
|
51
|
+
session.invalidate(errorMessage: "Unable to connect to tag.")
|
|
53
52
|
self.onError?(error)
|
|
54
53
|
return
|
|
55
54
|
}
|
|
56
55
|
|
|
57
|
-
tag.queryNDEFStatus { (ndefStatus,
|
|
56
|
+
tag.queryNDEFStatus { (ndefStatus, _, error) in
|
|
58
57
|
if let error = error {
|
|
59
|
-
session.
|
|
60
|
-
session.invalidate()
|
|
58
|
+
session.invalidate(errorMessage: "Unable to query the NDEF status of tag.")
|
|
61
59
|
self.onError?(error)
|
|
62
60
|
return
|
|
63
61
|
}
|
|
64
62
|
|
|
65
63
|
switch ndefStatus {
|
|
66
64
|
case .notSupported:
|
|
67
|
-
session.
|
|
68
|
-
session.invalidate()
|
|
65
|
+
session.invalidate(errorMessage: "Tag is not NDEF compliant.")
|
|
69
66
|
case .readOnly:
|
|
70
|
-
session.
|
|
71
|
-
session.invalidate()
|
|
67
|
+
session.invalidate(errorMessage: "Tag is read-only.")
|
|
72
68
|
case .readWrite:
|
|
73
69
|
if let message = self.messageToWrite {
|
|
74
70
|
tag.writeNDEF(message) { (error) in
|
|
75
71
|
if let error = error {
|
|
76
|
-
session.
|
|
77
|
-
session.invalidate()
|
|
72
|
+
session.invalidate(errorMessage: "Failed to write NDEF message.")
|
|
78
73
|
self.onError?(error)
|
|
79
74
|
return
|
|
80
75
|
}
|
|
@@ -83,12 +78,10 @@ import CoreNFC
|
|
|
83
78
|
self.onWriteSuccess?()
|
|
84
79
|
}
|
|
85
80
|
} else {
|
|
86
|
-
session.
|
|
87
|
-
session.invalidate()
|
|
81
|
+
session.invalidate(errorMessage: "No message to write.")
|
|
88
82
|
}
|
|
89
83
|
@unknown default:
|
|
90
|
-
session.
|
|
91
|
-
session.invalidate()
|
|
84
|
+
session.invalidate(errorMessage: "Unknown NDEF tag status.")
|
|
92
85
|
}
|
|
93
86
|
}
|
|
94
87
|
}
|
package/package.json
CHANGED
|
@@ -1,9 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@exxili/capacitor-nfc",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.13",
|
|
4
4
|
"description": "A Capacitor plugin for reading and writing NFC NDEFtags.",
|
|
5
|
+
"type": "module",
|
|
5
6
|
"main": "dist/plugin.cjs.js",
|
|
6
7
|
"module": "dist/esm/index.js",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"import": "./dist/esm/index.js",
|
|
11
|
+
"require": "./dist/plugin.cjs.js",
|
|
12
|
+
"types": "./dist/esm/index.d.ts"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
7
15
|
"types": "dist/esm/index.d.ts",
|
|
8
16
|
"unpkg": "dist/plugin.js",
|
|
9
17
|
"files": [
|
|
@@ -38,7 +46,7 @@
|
|
|
38
46
|
"fmt": "npm run eslint -- --fix && npm run prettier -- --write && npm run swiftlint -- --fix --format",
|
|
39
47
|
"eslint": "eslint . --ext ts",
|
|
40
48
|
"prettier": "prettier \"**/*.{css,html,ts,js,java}\" --plugin=prettier-plugin-java",
|
|
41
|
-
"swiftlint": "node-swiftlint",
|
|
49
|
+
"swiftlint": "node-swiftlint lint ios/Sources/NFCPlugin --config .swiftlint.yml",
|
|
42
50
|
"docgen": "docgen --api NFCPlugin --output-readme README.md --output-json dist/docs.json",
|
|
43
51
|
"build": "npm run clean && tsc && rollup -c rollup.config.js && rimraf *.tgz && npm pack",
|
|
44
52
|
"clean": "rimraf ./dist",
|
|
@@ -53,13 +61,14 @@
|
|
|
53
61
|
"@ionic/eslint-config": "^0.4.0",
|
|
54
62
|
"@ionic/prettier-config": "^4.0.0",
|
|
55
63
|
"@ionic/swiftlint-config": "^1.1.2",
|
|
64
|
+
"@types/node": "^22.18.8",
|
|
56
65
|
"eslint": "^8.57.0",
|
|
57
66
|
"prettier": "^3.3.3",
|
|
58
67
|
"prettier-plugin-java": "^2.6.4",
|
|
59
68
|
"rimraf": "^3.0.2",
|
|
60
69
|
"rollup": "^2.32.0",
|
|
61
70
|
"swiftlint": "^1.0.1",
|
|
62
|
-
"typescript": "
|
|
71
|
+
"typescript": "^5.9.3"
|
|
63
72
|
},
|
|
64
73
|
"peerDependencies": {
|
|
65
74
|
"@capacitor/core": ">=6.0.0 <9.0.0"
|
|
@@ -78,4 +87,4 @@
|
|
|
78
87
|
"src": "android"
|
|
79
88
|
}
|
|
80
89
|
}
|
|
81
|
-
}
|
|
90
|
+
}
|