taler-ios

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

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 }