taler-ios

iOS apps for GNU Taler (wallet)
Log | Files | Refs | README | LICENSE

SwiftNFC.swift (7159B)


      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 NFCReader: NSObject, ObservableObject, NFCNDEFReaderSessionDelegate {
     28 
     29     public var startAlert = String(localized: "Hold your iPhone near the tag.")
     30     public var endAlert = ""
     31     public var msg = String(localized: "Scan to read or Edit here to write...")
     32     public var raw = String(localized: "Raw Data available after scan.")
     33 
     34     public var session: NFCNDEFReaderSession?
     35     
     36     public func read() {
     37         guard NFCNDEFReaderSession.readingAvailable else {
     38             print("Error")
     39             return
     40         }
     41         session = NFCNDEFReaderSession(delegate: self, queue: nil, invalidateAfterFirstRead: true)
     42         session?.alertMessage = self.startAlert
     43         session?.begin()
     44     }
     45     
     46     public func readerSession(_ session: NFCNDEFReaderSession, didDetectNDEFs messages: [NFCNDEFMessage]) {
     47         DispatchQueue.main.async {
     48             self.msg = messages.map {
     49                 $0.records.map {
     50                     String(decoding: $0.payload, as: UTF8.self)
     51                 }.joined(separator: "\n")
     52             }.joined(separator: " ")
     53             
     54             self.raw = messages.map {
     55                 $0.records.map {
     56                     "\($0.typeNameFormat) \(String(decoding:$0.type, as: UTF8.self)) \(String(decoding:$0.identifier, as: UTF8.self)) \(String(decoding: $0.payload, as: UTF8.self))"
     57                 }.joined(separator: "\n")
     58             }.joined(separator: " ")
     59 
     60 
     61             session.alertMessage = self.endAlert != "" ? self.endAlert : "Read \(messages.count) NDEF Messages, and \(messages[0].records.count) Records."
     62         }
     63     }
     64     
     65     public func readerSessionDidBecomeActive(_ session: NFCNDEFReaderSession) {
     66     }
     67     
     68     public func readerSession(_ session: NFCNDEFReaderSession, didInvalidateWithError error: Error) {
     69         print("Session did invalidate with error: \(error)")
     70         self.session = nil
     71     }
     72 }
     73 
     74 public class NFCWriter: NSObject, ObservableObject, NFCNDEFReaderSessionDelegate {
     75     
     76     public var startAlert = String(localized: "Hold your iPhone near the tag.")
     77     public var endAlert = ""
     78     public var msg = ""
     79     public var type = "T"   // T=Text - U=URL
     80     public var data: Data? = nil
     81 
     82     public var session: NFCNDEFReaderSession?
     83     
     84     public func write(_ data: Data? = nil) {
     85         guard NFCNDEFReaderSession.readingAvailable else {
     86             print("Error readingAvailable")
     87             return
     88         }
     89         self.data = data
     90         session = NFCNDEFReaderSession(delegate: self, queue: nil, invalidateAfterFirstRead: false)
     91         if let session {
     92             session.alertMessage = self.startAlert
     93             session.begin()
     94         } else {
     95             print("Error NFCNDEFReaderSession")
     96         }
     97     }
     98     
     99     public func readerSession(_ session: NFCNDEFReaderSession, didDetectNDEFs messages: [NFCNDEFMessage]) {
    100         print("didDetectNDEFs", messages)
    101     }
    102 
    103     public func readerSession(_ session: NFCNDEFReaderSession, didDetect tags: [NFCNDEFTag]) {
    104         if tags.count > 1 {
    105             let retryInterval = DispatchTimeInterval.milliseconds(500)
    106             session.alertMessage = "Detected more than 1 tag. Please try again."
    107             DispatchQueue.global().asyncAfter(deadline: .now() + retryInterval, execute: {
    108                 session.restartPolling()
    109             })
    110             return
    111         }
    112         
    113         let tag = tags.first!
    114         session.connect(to: tag, completionHandler: { (error: Error?) in
    115             if nil != error {
    116                 session.alertMessage = "Unable to connect to tag."
    117                 session.invalidate()
    118                 return
    119             }
    120             
    121             tag.queryNDEFStatus(completionHandler: { (ndefStatus: NFCNDEFStatus, capacity: Int, error: Error?) in
    122                 guard error == nil else {
    123                     session.alertMessage = "Unable to query the status of the tag."
    124                     session.invalidate()
    125                     return
    126                 }
    127 
    128                 switch ndefStatus {
    129                 case .notSupported:
    130                     session.alertMessage = "Tag is not NDEF compliant."
    131                     session.invalidate()
    132                 case .readOnly:
    133                     session.alertMessage = "Read only tag detected."
    134                     session.invalidate()
    135                 case .readWrite:
    136                     let payload: NFCNDEFPayload?
    137                     if self.type == "T" {
    138                         payload = NFCNDEFPayload.init(
    139                             format: .nfcWellKnown,
    140                             type: Data("\(self.type)".utf8),
    141                             identifier: Data(),
    142                             payload: self.data ?? Data("\(self.msg)".utf8)
    143                         )
    144                     } else {
    145                         payload = NFCNDEFPayload.wellKnownTypeURIPayload(string: "\(self.msg)")
    146                     }
    147                     let message = NFCNDEFMessage(records: [payload].compactMap({ $0 }))
    148                     tag.writeNDEF(message, completionHandler: { (error: Error?) in
    149                         if nil != error {
    150                             session.alertMessage = "Write to tag failed: \(error!)"
    151                         } else {
    152                             session.alertMessage = self.endAlert != "" ? self.endAlert : "Write \(self.msg) to tag successful."
    153                         }
    154                         session.invalidate()
    155                     })
    156                 @unknown default:
    157                     session.alertMessage = "Unknown tag status."
    158                     session.invalidate()
    159                 }
    160             })
    161         })
    162     }
    163     
    164     public func readerSessionDidBecomeActive(_ session: NFCNDEFReaderSession) {
    165     }
    166 
    167     public func readerSession(_ session: NFCNDEFReaderSession, didInvalidateWithError error: Error) {
    168         print("Session did invalidate with error: \(error)")
    169         self.session = nil
    170     }
    171 }