import Foundation import CoreNFC @available(iOS 13.0, *) extension NFCISO7816APDU { func toHexString() -> String { let dataFieldInHex = (self.data ?? Data(_ : [])).hexEncodedString() return String(format:"%02X %02X %02X %02X", self.instructionClass, self.instructionCode, self.p1Parameter, self.p2Parameter) + " " + dataFieldInHex + String(format:"%02X", self.expectedResponseLength) + " " } } typealias CompletionHandler = (_ response:ApduResponse) -> Void @available(iOS 13.0, *) public class ApduRunner: NSObject, NFCTagReaderSessionDelegate { public static let NFC_TAG_CONNECTED_EVENT:String = "nfcTagConnected" var sessionEx: NFCTagReaderSession? var callback: ApduCallback? var nfcApi : UnifiedNfcApi? func setApduCallback(callback : ApduCallback) { self.callback = callback } func setUnifiedNfcApi(nfcApi : UnifiedNfcApi) { self.nfcApi = nfcApi } func startScan() { let langCode = Locale.current.languageCode self.sessionEx = NFCTagReaderSession(pollingOption: [.iso14443, .iso18092], delegate: self) self.sessionEx?.alertMessage = "scanMessage".localizeString(string: langCode!) self.sessionEx?.begin() } public func tagReaderSession(_ session: NFCTagReaderSession, didDetect tags: [NFCTag]) { guard self.callback != nil else { debugLog("NfcCallback is empty.") return } guard self.sessionEx != nil else { return } guard tags.count > 0 else { debugLog("Nfc Tag???.") return } if case NFCTag.iso7816(_) = tags.first! { sessionEx?.connect(to: tags.first!) { [self] (error: Error?) in if let err = error { debugLog("Error connecting to Nfc Tag" + err.localizedDescription) return } debugLog("Nfc Tag is connected.") if (self.callback != nil){ self.callback!.connected(unifiedNfcApi: self.nfcApi!) } } } else if case .feliCa(let feliCaTag) = tags.first! { sessionEx?.connect(to: tags.first!) { [self] (error: Error?) in if let err = error { debugLog("Error connecting to Nfc Tag" + err.localizedDescription) return } // felicaTag = feliCaTag debugLog("Felica is connected.") if (self.callback != nil){ debugLog("Felica is connected 2.") self.callback!.felicaConnected(unifiedNfcApi: self.nfcApi!, tag: feliCaTag) } // self.sendFelicaCommand(tag: feliCaTag, session: sessionEx!) // let idm = feliCaTag.currentIDm.map { String(format: "%.2hhx", $0) }.joined() // let hexString = "0F06" + idm + "010B30018000" // print("hex: \(hexString)") // if let apduData = hexString.hexToData() { // feliCaTag.sendFeliCaCommand(commandPacket: apduData) // } // if (self.callback != nil){ // self.callback!.connected(felicaNfcApi: self.felicaNfcApi!) // } } } } func exchangeApdu(apduCommand: NFCISO7816APDU, completionHandler: @escaping CompletionHandler) { if case let NFCTag.iso7816(nfcTag) = self.sessionEx!.connectedTag! { nfcTag.sendCommand(apdu: apduCommand) { (response: Data, sw1: UInt8, sw2: UInt8, error: Error?) in let resp = ApduResponse() debugLog("SW1-SW2: " + String(format: "%02X, %02X", sw1, sw2)) resp.setSw1(_sw1: sw1) resp.setSw2(_sw2: sw2) resp.setData(_data: response) completionHandler(resp) } } } func invalidateSession() { sessionEx?.invalidate() } func invalidateSession(msg : String) { sessionEx?.invalidate(errorMessage: msg) } public func tagReaderSessionDidBecomeActive(_ session: NFCTagReaderSession) { debugLog("Nfc session is active") } public func tagReaderSession(_ session: NFCTagReaderSession, didInvalidateWithError error: Error) { debugLog("Error happend: " + error.localizedDescription) NotificationCenter.default.post(name: Notification.Name("stopTimer"), object: nil) if ((sessionEx?.isReady) != nil){ self.invalidateSession(msg: error.localizedDescription) } } }