SkyBlue1903
SkyBlue1903

Reputation: 3

How to send ISO7816 Command APDU in Swift?

I want to send this command 00B300003F as APDU in ISO7816 Tag in Swift language, I already implement with error session invalidated unexpectedly. How to prevent this?

My full code:

import CoreNFC

class ViewController: UIViewController, NFCTagReaderSessionDelegate {
  var nfcSession: NFCTagReaderSession?
  override func viewDidLoad() {
    super.viewDidLoad()
  }
  @IBAction func btnScan(_ sender: Any) {
    nfcSession = NFCTagReaderSession(pollingOption: [.iso14443], delegate: self, queue: nil)
    nfcSession?.alertMessage = "Hold your iPhone near the NFC tag."
    nfcSession?.begin()
  }
  
  // NFC session becomes active
  func tagReaderSessionDidBecomeActive(_ session: NFCTagReaderSession) {
    print("NFC session started")
  }
  
  // Handle errors or invalidation of the session
  func tagReaderSession(_ session: NFCTagReaderSession, didInvalidateWithError error: Error) {
    print("Session invalidated: \(error.localizedDescription)")
    nfcSession = nil
  }
  
  // Handle detection of the NFC tag
  func tagReaderSession(_ session: NFCTagReaderSession, didDetect tags: [NFCTag]) {
    guard let firstTag = tags.first else {
      session.invalidate(errorMessage: "No tags found")
      return
    }
    
    // Connect to the detected tag
    session.connect(to: firstTag) { (error: Error?) in
      if let error = error {
        print("Error connecting to tag: \(error.localizedDescription)")
        session.invalidate(errorMessage: "Connection failed")
        return
      }
      
      // Check if the tag is ISO7816 compatible
      switch firstTag {
      case let .iso7816(tag):
        // APDU command: 00B300003F
        let apduCommand = NFCISO7816APDU(
          instructionClass: 0x00,   // CLA
          instructionCode: 0xB3,    // INS
          p1Parameter: 0x00,        // P1
          p2Parameter: 0x00,        // P2
          data: Data([0x3F]),       // Data (003F)
          expectedResponseLength: 256
        )
        
        // Send the APDU command to the tag
        tag.sendCommand(apdu: apduCommand) { (response: Data, sw1: UInt8, sw2: UInt8, error: Error?) in
          if let error = error {
            print("Error sending APDU command: \(error.localizedDescription)")
            session.invalidate(errorMessage: "Failed to send command")
            return
          }
          
          // Check status words SW1 and SW2
          if sw1 == 0x90 && sw2 == 0x00 {
            print("Command successful!")
            print("Response: \(response.hexEncodedString())")
            session.alertMessage = "Command sent successfully."
          } else {
            print("Command failed: SW1=\(sw1), SW2=\(sw2)")
            session.alertMessage = "Command failed."
          }
          
          session.invalidate()
        }
        
      default:
        session.invalidate(errorMessage: "Tag not compatible with ISO7816.")
      }
    }
  }
  
}

extension Data {
  func hexEncodedString() -> String {
    return map { String(format: "%02hhx", $0) }.joined()
  }
}

My expected results are Response Data along with SW1 SW2. The result is always "Error sending APDU command: Session invalidated"

But when I using third party apps such as NFC Tools in App Store, I can get response data like this:

Result of send APDU command "00B300003F" on NFC Tools app

My Info.plist:

<key>com.apple.developer.nfc.readersession.iso7816.select-identifiers</key>
    <array>
        <string>0000000000000001</string>
    </array>

My Entitlement:

    <key>com.apple.developer.nfc.readersession.formats</key>
    <array>
        <string>TAG</string>
        <string>NDEF</string>
    </array>

Upvotes: 0

Views: 138

Answers (0)

Related Questions