SwiftNFC.swift (5517B)
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 import CoreNFC 25 26 @available(iOS 15.0, *) 27 public class NFCWriter: NSObject, ObservableObject, NFCNDEFReaderSessionDelegate { 28 29 public var startAlert = String(localized: "Hold your iPhone near the tag.") 30 public var endAlert = EMPTYSTRING 31 public var msg = EMPTYSTRING 32 public var type = "T" // T=Text - U=URL 33 public var data: Data? = nil 34 35 public var session: NFCNDEFReaderSession? 36 37 public func write(_ data: Data? = nil) { 38 guard NFCNDEFReaderSession.readingAvailable else { 39 print("Error readingAvailable") 40 return 41 } 42 self.data = data 43 session = NFCNDEFReaderSession(delegate: self, queue: nil, invalidateAfterFirstRead: false) 44 if let session { 45 session.alertMessage = self.startAlert 46 session.begin() 47 } else { 48 print("Error NFCNDEFReaderSession") 49 } 50 } 51 52 public func readerSession(_ session: NFCNDEFReaderSession, didDetectNDEFs messages: [NFCNDEFMessage]) { 53 // Do not add code in this function. 54 // This method isn't called when you provide `reader(_:didDetect:)`. 55 // print("didDetectNDEFs", messages) 56 } 57 58 public func readerSession(_ session: NFCNDEFReaderSession, didDetect tags: [NFCNDEFTag]) { 59 if tags.count > 1 { 60 let retryInterval = DispatchTimeInterval.milliseconds(500) 61 session.alertMessage = "Detected more than 1 tag. Please try again." 62 DispatchQueue.global().asyncAfter(deadline: .now() + retryInterval, execute: { 63 session.restartPolling() 64 }) 65 return 66 } 67 68 let tag = tags.first! 69 session.connect(to: tag, completionHandler: { (error: Error?) in 70 if nil != error { 71 session.alertMessage = "Unable to connect to tag." 72 session.invalidate() 73 return 74 } 75 76 tag.queryNDEFStatus(completionHandler: { (ndefStatus: NFCNDEFStatus, capacity: Int, error: Error?) in 77 guard error == nil else { 78 session.alertMessage = "Unable to query the status of the tag." 79 session.invalidate() 80 return 81 } 82 83 switch ndefStatus { 84 case .notSupported: 85 session.alertMessage = "Tag is not NDEF compliant." 86 session.invalidate() 87 case .readOnly: 88 session.alertMessage = "Read only tag detected." 89 session.invalidate() 90 case .readWrite: 91 let payload: NFCNDEFPayload? 92 if self.type == "T" { // TAG 93 payload = NFCNDEFPayload.init( 94 format: .nfcWellKnown, 95 type: Data("\(self.type)".utf8), 96 identifier: Data(), 97 payload: self.data ?? Data("\(self.msg)".utf8) 98 ) 99 } else { 100 payload = NFCNDEFPayload.wellKnownTypeURIPayload(string: "\(self.msg)") 101 } 102 let message = NFCNDEFMessage(records: [payload].compactMap({ $0 })) 103 tag.writeNDEF(message, completionHandler: { (error: Error?) in 104 if nil != error { 105 session.alertMessage = "Write to tag failed: \(error!)" 106 } else { 107 session.alertMessage = self.endAlert != EMPTYSTRING ? self.endAlert 108 : "Write \(self.msg) to tag successful." 109 } 110 session.invalidate() 111 }) 112 @unknown default: 113 session.alertMessage = "Unknown tag status." 114 session.invalidate() 115 } 116 }) 117 }) 118 } 119 120 public func readerSessionDidBecomeActive(_ session: NFCNDEFReaderSession) { 121 // TODO: change statusLabel 122 } 123 124 public func readerSession(_ session: NFCNDEFReaderSession, didInvalidateWithError error: Error) { 125 print("Session did invalidate with error: \(error)") 126 self.session = nil 127 } 128 }