@capgo/capacitor-nfc 8.0.22 → 8.0.24

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.
@@ -4,7 +4,7 @@ import UIKit
4
4
 
5
5
  @objc(NfcPlugin)
6
6
  public class NfcPlugin: CAPPlugin, CAPBridgedPlugin {
7
- private let pluginVersion: String = "8.0.22"
7
+ private let pluginVersion: String = "8.0.24"
8
8
 
9
9
  public let identifier = "NfcPlugin"
10
10
  public let jsName = "CapacitorNfc"
@@ -28,6 +28,12 @@ public class NfcPlugin: CAPPlugin, CAPBridgedPlugin {
28
28
  private var currentTag: NFCNDEFTag?
29
29
  private var invalidateAfterFirstRead = true
30
30
  private var sessionType: String = "ndef"
31
+ private var pendingStartCall: CAPPluginCall?
32
+ private var pendingStartSession: NFCTagReaderSession?
33
+ private var pendingAlertMessage: String?
34
+ private var tagSessionActivated = false
35
+ private var tagSessionTriedFallback = false
36
+ private var tagSessionPollingOptions: NFCTagReaderSession.PollingOption = []
31
37
 
32
38
  private func isSessionAvailable(for type: String) -> Bool {
33
39
  if type == "tag" {
@@ -44,6 +50,9 @@ public class NfcPlugin: CAPPlugin, CAPBridgedPlugin {
44
50
  pollingOptions: NFCTagReaderSession.PollingOption,
45
51
  alertMessage: String?
46
52
  ) -> NFCTagReaderSession? {
53
+ tagSessionActivated = false
54
+ tagSessionPollingOptions = pollingOptions
55
+
47
56
  guard let session = NFCTagReaderSession(
48
57
  pollingOption: pollingOptions,
49
58
  delegate: self,
@@ -56,6 +65,7 @@ public class NfcPlugin: CAPPlugin, CAPBridgedPlugin {
56
65
  session.alertMessage = alertMessage
57
66
  }
58
67
 
68
+ tagReaderSession = session
59
69
  session.begin()
60
70
  return session
61
71
  }
@@ -69,7 +79,10 @@ public class NfcPlugin: CAPPlugin, CAPBridgedPlugin {
69
79
  sessionType = requestedSessionType == "tag" ? "tag" : "ndef"
70
80
 
71
81
  guard isSessionAvailable(for: sessionType) else {
72
- call.reject("NFC is not available on this device.", "NO_NFC")
82
+ let message = sessionType == "tag"
83
+ ? "NFC tag reading is not available on this device. Ensure the TAG reader entitlement is enabled."
84
+ : "NFC is not available on this device."
85
+ call.reject(message, "NO_NFC")
73
86
  return
74
87
  }
75
88
 
@@ -82,29 +95,37 @@ public class NfcPlugin: CAPPlugin, CAPBridgedPlugin {
82
95
  self.ndefReaderSession = nil
83
96
  self.tagReaderSession?.invalidate()
84
97
  self.tagReaderSession = nil
98
+ self.currentTag = nil
99
+ if let pendingStartCall = self.pendingStartCall, pendingStartCall !== call {
100
+ pendingStartCall.reject("NFC scan was superseded by a new startScanning call.", "CANCELLED")
101
+ }
102
+ self.pendingStartCall = nil
103
+ self.pendingStartSession = nil
104
+ self.pendingAlertMessage = nil
105
+ self.tagSessionTriedFallback = false
85
106
 
86
107
  if self.sessionType == "tag" {
87
108
  // Use NFCTagReaderSession for raw tag support
88
- self.tagReaderSession = self.makeTagReaderSession(
109
+ self.pendingStartCall = call
110
+ self.pendingAlertMessage = alertMessage
111
+
112
+ let session = self.makeTagReaderSession(
89
113
  pollingOptions: [.iso14443, .iso15693, .iso18092],
90
114
  alertMessage: alertMessage
91
115
  )
116
+ self.pendingStartSession = session
92
117
 
93
- // Some configurations block FeliCa polling; retry without iso18092 to keep common formats working.
94
- if self.tagReaderSession == nil {
95
- self.tagReaderSession = self.makeTagReaderSession(
96
- pollingOptions: [.iso14443, .iso15693],
97
- alertMessage: alertMessage
98
- )
99
- }
100
-
101
- guard self.tagReaderSession != nil else {
118
+ guard session != nil else {
119
+ self.pendingStartCall = nil
120
+ self.pendingStartSession = nil
102
121
  call.reject(
103
122
  "Failed to create NFC tag reader session. Make sure the 'Near Field Communication Tag Reader Session Formats' entitlement includes the 'TAG' format in your app target.",
104
123
  "NO_NFC"
105
124
  )
106
125
  return
107
126
  }
127
+
128
+ return
108
129
  } else {
109
130
  // Use NFCNDEFReaderSession (default behavior)
110
131
  self.ndefReaderSession = NFCNDEFReaderSession(
@@ -169,7 +190,7 @@ public class NfcPlugin: CAPPlugin, CAPBridgedPlugin {
169
190
  call.reject("No active NFC session or tag.")
170
191
  return
171
192
  }
172
-
193
+
173
194
  if let ndefSession = ndefReaderSession {
174
195
  // For NDEF session, we need to connect to the tag first
175
196
  performWrite(message: message, on: tag, session: ndefSession, call: call)
@@ -513,13 +534,89 @@ extension NfcPlugin: NFCNDEFReaderSessionDelegate {
513
534
  // MARK: - NFCTagReaderSessionDelegate
514
535
  extension NfcPlugin: NFCTagReaderSessionDelegate {
515
536
  public func tagReaderSessionDidBecomeActive(_ session: NFCTagReaderSession) {
516
- // Session became active, ready to detect tags
537
+ guard session === tagReaderSession else {
538
+ return
539
+ }
540
+
541
+ tagSessionActivated = true
542
+
543
+ if session === pendingStartSession, let pendingCall = pendingStartCall {
544
+ pendingStartCall = nil
545
+ pendingStartSession = nil
546
+ pendingAlertMessage = nil
547
+ DispatchQueue.main.async {
548
+ pendingCall.resolve()
549
+ }
550
+ }
517
551
  }
518
552
 
519
553
  public func tagReaderSession(_ session: NFCTagReaderSession, didInvalidateWithError error: Error) {
520
- currentTag = nil
521
554
  let nfcError = error as NSError
522
-
555
+
556
+ if let pendingCall = pendingStartCall {
557
+ guard session === pendingStartSession else {
558
+ return
559
+ }
560
+
561
+ currentTag = nil
562
+
563
+ let canRetryWithoutFeliCa = !tagSessionActivated &&
564
+ tagSessionPollingOptions.contains(.iso18092) &&
565
+ !tagSessionTriedFallback &&
566
+ (nfcError.code == NFCReaderError.readerErrorUnsupportedFeature.rawValue ||
567
+ nfcError.code == NFCReaderError.readerErrorSecurityViolation.rawValue)
568
+
569
+ if canRetryWithoutFeliCa {
570
+ let fallbackAlertMessage = pendingAlertMessage
571
+ tagSessionTriedFallback = true
572
+ tagReaderSession = nil
573
+ pendingStartSession = nil
574
+
575
+ DispatchQueue.main.async {
576
+ guard self.pendingStartCall === pendingCall, self.pendingStartSession == nil else {
577
+ return
578
+ }
579
+
580
+ let fallbackSession = self.makeTagReaderSession(
581
+ pollingOptions: [.iso14443, .iso15693],
582
+ alertMessage: fallbackAlertMessage
583
+ )
584
+ self.pendingStartSession = fallbackSession
585
+
586
+ if fallbackSession == nil {
587
+ self.pendingStartCall = nil
588
+ self.pendingStartSession = nil
589
+ self.pendingAlertMessage = nil
590
+ pendingCall.reject(
591
+ "Failed to start NFC tag session without FeliCa polling: \(error.localizedDescription)",
592
+ "NO_NFC",
593
+ error
594
+ )
595
+ }
596
+ }
597
+ return
598
+ }
599
+
600
+ pendingStartCall = nil
601
+ pendingStartSession = nil
602
+ pendingAlertMessage = nil
603
+ DispatchQueue.main.async {
604
+ pendingCall.reject(
605
+ "Failed to start NFC tag session: \(error.localizedDescription)",
606
+ "NO_NFC",
607
+ error
608
+ )
609
+ }
610
+ tagReaderSession = nil
611
+ return
612
+ }
613
+
614
+ guard session === tagReaderSession else {
615
+ return
616
+ }
617
+
618
+ currentTag = nil
619
+
523
620
  // Don't emit state change for normal session completion (user canceled)
524
621
  // Also check for successful read completion
525
622
  if nfcError.code != NFCReaderError.readerSessionInvalidationErrorUserCanceled.rawValue {
@@ -540,7 +637,7 @@ extension NfcPlugin: NFCTagReaderSessionDelegate {
540
637
  session.invalidate(errorMessage: "More than one tag detected. Please present only one tag.")
541
638
  return
542
639
  }
543
-
640
+
544
641
  guard let firstTag = tags.first else {
545
642
  return
546
643
  }
@@ -580,7 +677,7 @@ extension NfcPlugin: NFCTagReaderSessionDelegate {
580
677
 
581
678
  if error == nil && status != .notSupported {
582
679
  // Tag supports NDEF, try to read it
583
- tag.readNDEF { [weak self] message, readError in
680
+ tag.readNDEF { [weak self] message, _ in
584
681
  guard let self else {
585
682
  return
586
683
  }
@@ -613,15 +710,15 @@ extension NfcPlugin: NFCTagReaderSessionDelegate {
613
710
  currentTag = tag
614
711
 
615
712
  var tagInfo: [String: Any] = [:]
616
-
713
+
617
714
  // Extract and add the tag ID (UID)
618
715
  if let identifierData = extractIdentifier(from: tag) {
619
716
  tagInfo["id"] = array(from: identifierData)
620
717
  }
621
-
718
+
622
719
  tagInfo["techTypes"] = detectTechTypes(for: tag)
623
720
  tagInfo["type"] = translateType(for: tag)
624
-
721
+
625
722
  // Include writability and capacity information
626
723
  if status != .notSupported {
627
724
  tagInfo["isWritable"] = status == .readWrite
@@ -643,9 +740,9 @@ extension NfcPlugin: NFCTagReaderSessionDelegate {
643
740
  "type": message != nil ? "ndef" : "tag",
644
741
  "tag": tagInfo
645
742
  ]
646
-
743
+
647
744
  notify(event: event)
648
-
745
+
649
746
  if invalidateAfterFirstRead {
650
747
  session.invalidate()
651
748
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@capgo/capacitor-nfc",
3
- "version": "8.0.22",
3
+ "version": "8.0.24",
4
4
  "description": "Native NFC tag discovery, reading and writing for Capacitor apps on iOS and Android.",
5
5
  "main": "dist/plugin.cjs.js",
6
6
  "module": "dist/esm/index.js",