How to communicate with smart card readers conncetd to USB-C port in iOS?

Hello All,

I am new to iOS development and would like to detect the smart card readers connected to USB-C port on iOS (16+) devices. The smart card reader is a custom hardware and not MFi certified. So as per my understanding, I cannot use ExternalAccessory.framework without MFi certification. Correct?

How else can I achieve this? Does TKSmartCardSlotManager works for this purpose (or is it only for NFC devices?)? Is there any example for how to use this interface? I couldn't find any example for this as a starting point...

Thanks in advance.

Replies

iOS does not have a mechanism for third-party code to talk to generic USB devices [1].

The smart card reader is a custom hardware and not MFi certified. So as per my understanding, I cannot use ExternalAccessory.framework without MFi certification.

True. But even if that were possible, it’s not easy to use EA framework from a CTK appex.

iOS has built-in support for standard USB smart cards (via USB CCID), so the easiest way to achieve your goal is to change your hardware to support that standard.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

[1] iPadOS can do this with DriverKit, but that one of a small set of iPadOS-specific facilities that aren’t on iOS.

  • Should we use TKSmartCardSlotManager for USB CCID smart cards?

Add a Comment

Hi  @eskimo , thanks for the update.

iOS has built-in support for standard USB smart cards (via USB CCID), so the easiest way to achieve your goal is to change your hardware to support that standard.

This is interesting. The hardware has USB CCID. Should we use TKSmartCardSlotManager for this? I wrote a basic swift file using TKSmartCardSlotManager

import CryptoTokenKit

class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()

        // Start observing smart card slot state changes
        startObservingSmartCardSlotStateChanges()
    }

    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        
        // Stop observing smart card slot state changes when the view disappears
        stopObservingSmartCardSlotStateChanges()
    }

    func startObservingSmartCardSlotStateChanges() {
        DispatchQueue.global().async {
            if let slotManager = TKSmartCardSlotManager.default {
                while true {
                    let slotNames = slotManager.slotNames // No need for optional binding
                    
                    for reader in slotNames {
                        slotManager.getSlot(withName: reader) { slot in
                            guard let slot = slot else {
                                print("Slot for reader \(reader) is nil")
                                return
                            }
                            
                            let state = slot.state
                            if state.contains(.cardPresent) {
                                // Smart card is present in the slot
                                print("Smart card is present in slot: \(reader)")
                                
                                // Example: Communicate with the smart card
                                if let card = slot.makeSmartCard() {
                                    card.beginSession { session, error in
                                        if let error = error {
                                            print("Error beginning session with smart card: \(error.localizedDescription)")
                                            return
                                        }
                                        // Session started, now you can communicate with the smart card
                                    }
                                }
                            } else if state.contains(.empty) {
                                // Smart card slot is empty
                                print("Smart card slot is empty: \(reader)")
                            } else {
                                // Unknown state or other state
                                print("Smart card slot is in an unknown state: \(reader)")
                            }
                        }
                    }
                    
                    // Poll every few seconds
                    sleep(5)
                }
            } else {
                // Handle the case where 'default' returns nil
                print("TKSmartCardSlotManager.default is nil")
            }
        }
    }

    func stopObservingSmartCardSlotStateChanges() {
    }
}

Do you think this is correct implementation? Your feedback would be helpful

Thanks in advance