SwiftNFC.swift (5919B)
1 // MIT License 2 // Copyright © Ming 3 // https://github.com/1998code/SwiftNFC 4 // 5 // Permission is hereby granted, free of charge, to any person obtaining a copy of this software 6 // and associated documentation files (the "Software"), to deal in the Software without restriction, 7 // including without limitation the rights to use, copy, modify, merge, publish, distribute, 8 // sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 9 // furnished to do so, subject to the following conditions: 10 // 11 // The above copyright notice and this permission notice shall be included in all copies or 12 // substantial portions of the Software. 13 // 14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 15 // BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 16 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 17 // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 19 // 20 /** 21 * @author Marc Stibane 22 */ 23 import SwiftUI 24 @preconcurrency import CoreNFC 25 26 fileprivate let comment: StaticString = "NFC tag reader" 27 28 public class NFCWriter: NSObject, ObservableObject, NFCNDEFReaderSessionDelegate { 29 30 public var startAlert = String(localized: "Hold your iPhone near the tag.", comment: comment) 31 public var endAlert = EMPTYSTRING 32 public var msg = EMPTYSTRING 33 public var type = "T" // T=Text - U=URL 34 public var data: Data? = nil 35 36 public var session: NFCNDEFReaderSession? 37 38 public func write(_ data: Data? = nil) { 39 guard NFCNDEFReaderSession.readingAvailable else { 40 print(" ❗️Error readingAvailable") 41 return 42 } 43 self.data = data 44 session = NFCNDEFReaderSession(delegate: self, queue: nil, invalidateAfterFirstRead: false) 45 if let session { 46 session.alertMessage = self.startAlert 47 session.begin() 48 } else { 49 print(" ❗️Error NFCNDEFReaderSession") 50 } 51 } 52 53 public func readerSession(_ session: NFCNDEFReaderSession, didDetectNDEFs messages: [NFCNDEFMessage]) { 54 // Do not add code in this function. 55 // This method isn't called when you provide `reader(_:didDetect:)`. 56 // print(" ❗️didDetectNDEFs", messages) 57 } 58 59 public func readerSession(_ session: NFCNDEFReaderSession, didDetect tags: [NFCNDEFTag]) { 60 if tags.count > 1 { 61 let retryInterval = DispatchTimeInterval.milliseconds(500) 62 session.alertMessage = String(localized: "Detected more than 1 tag. Please try again.", comment: comment) 63 DispatchQueue.global().asyncAfter(deadline: .now() + retryInterval, execute: { 64 session.restartPolling() 65 }) 66 return 67 } 68 69 let tag = tags.first! 70 session.connect(to: tag) { (error: Error?) in 71 if nil != error { 72 print(" ❗️Connection error: \(String(describing: error))") 73 session.alertMessage = String(localized: "Unable to connect to tag.", comment: comment) 74 session.invalidate() 75 return 76 } 77 78 tag.queryNDEFStatus() { (ndefStatus: NFCNDEFStatus, capacity: Int, error: Error?) in 79 guard error == nil else { 80 session.alertMessage = "Unable to query the status of the tag." 81 session.invalidate() 82 return 83 } 84 85 switch ndefStatus { 86 case .notSupported: 87 session.alertMessage = "Tag is not NDEF compliant." 88 session.invalidate() 89 case .readOnly: 90 session.alertMessage = "Read only tag detected." 91 session.invalidate() 92 case .readWrite: 93 let payload: NFCNDEFPayload? 94 if self.type == "T" { // TAG 95 payload = NFCNDEFPayload.init(format: .nfcWellKnown, 96 type: Data("\(self.type)".utf8), 97 identifier: Data(), 98 payload: self.data ?? Data("\(self.msg)".utf8) 99 ) 100 } else { 101 payload = NFCNDEFPayload.wellKnownTypeURIPayload(string: "\(self.msg)") 102 } 103 let message = NFCNDEFMessage(records: [payload].compactMap({ $0 })) 104 tag.writeNDEF(message) { (error: Error?) in 105 if nil != error { 106 session.alertMessage = String(localized: "Write to tag failed: \(error!)", comment: comment) 107 } else { 108 session.alertMessage = self.endAlert != EMPTYSTRING ? self.endAlert 109 : String(localized: "Write \(self.msg) to tag successful.", comment: comment) 110 } 111 session.invalidate() 112 } 113 @unknown default: 114 session.alertMessage = String(localized: "Unknown tag status.", comment: comment) 115 session.invalidate() 116 } 117 } 118 } 119 } 120 121 public func readerSessionDidBecomeActive(_ session: NFCNDEFReaderSession) { 122 session.alertMessage = String(localized: "Reading Tag...", comment: comment) 123 } 124 125 public func readerSession(_ session: NFCNDEFReaderSession, didInvalidateWithError error: Error) { 126 print(" ❗️Session did invalidate with error: \(error)") 127 self.session = nil 128 } 129 }