taler-ios

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

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 }