iOS13下无法读取电子护照NFC芯片,tagReaderSession未触发求助
解决iOS13下无法检测电子护照NFC芯片的问题
看起来你遇到的核心问题是使用了不适合的NFC会话类型,再加上权限配置的小疏漏,导致电子护照的检测方法从未被触发。我来一步步帮你梳理修复方案:
1. 替换为专门的ISO7816会话类型
电子护照是基于ISO7816标准的智能卡,iOS中针对这类卡片提供了NFCISO7816TagReaderSession,它比通用的NFCTagReaderSession更精准地适配这类设备的检测逻辑。通用会话对ISO7816卡片的支持有限,这也是你的didDetect方法没被调用的主要原因。
2. 修正Entitlements权限配置
你的授权文件里缺少了ISO7816格式的权限,需要把它添加到com.apple.developer.nfc.readersession.formats数组中,修改后的配置如下:
<key>com.apple.developer.nfc.readersession.formats</key> <array> <string>NDEF</string> <string>TAG</string> <string>ISO7816</string> </array>
3. 适配代码到ISO7816会话
把你的代码替换为适配NFCISO7816TagReaderSession的版本,包括代理协议和会话初始化:
import UIKit import CoreNFC class ViewController: UIViewController, NFCISO7816TagReaderSessionDelegate { var nfcSession: NFCISO7816TagReaderSession? func tagReaderSessionDidBecomeActive(_ session: NFCISO7816TagReaderSession) { print("Tag reader did become active") print("isReady: \(session.isReady)") } func tagReaderSession(_ session: NFCISO7816TagReaderSession, didInvalidateWithError error: Error) { print("Session error: \(error.localizedDescription)") nfcSession = nil } func tagReaderSession(_ session: NFCISO7816TagReaderSession, didDetect tags: [NFCISO7816Tag]) { // 现在这个方法应该能被触发了! guard let passportTag = tags.first else { // 如果没读到有效标签,重启轮询 session.restartPolling() return } print("Detected ePassport tag: \(passportTag)") // 连接标签并发送SELECT AID指令(对应你的电子护照AID) session.connect(to: passportTag) { [weak self] connectError in guard connectError == nil else { print("Failed to connect to tag: \(connectError!)") session.invalidate() return } // 构造选择AID的APDU指令 let selectAIDCommand = NFCISO7816APDU( instructionClass: 0x00, instructionCode: 0xA4, p1: 0x04, p2: 0x00, data: Data(hex: "A0000002471001"), expectedResponseLength: 0 ) passportTag.sendCommand(apdu: selectAIDCommand) { response, commandError in if let commandError = commandError { print("Command failed: \(commandError)") session.invalidate() return } if let response = response { print("Response data: \(response.data.hexString)") print("Status word: \(String(format: "%04X", response.sw))") // 这里可以继续处理电子护照的其他指令 } session.invalidate() } } } @IBAction func clickedNFC(_ sender: Any) { // 先检查设备是否支持NFC读取 guard NFCISO7816TagReaderSession.readingAvailable else { print("NFC reading is not available on this device") return } nfcSession = NFCISO7816TagReaderSession(pollingOption: .iso14443, delegate: self, queue: nil) nfcSession?.alertMessage = "Place the device on the inner cover of the passport" nfcSession?.begin() } } // 辅助扩展:方便处理十六进制数据 extension Data { init(hex: String) { self.init() let cleanedHex = hex.replacingOccurrences(of: " ", with: "") let hexChars = Array(cleanedHex) for i in stride(from: 0, to: hexChars.count, by: 2) { let byteString = String(hexChars[i...i+1]) if let byte = UInt8(byteString, radix: 16) { append(byte) } } } var hexString: String { return map { String(format: "%02X", $0) }.joined() } }
4. 额外注意事项
- 必须用物理设备测试:iOS模拟器不支持NFC功能,一定要用iPhone 7及以上的真机。
- 贴合位置要准确:电子护照的NFC芯片一般在护照内页的照片页附近,需要把设备紧贴芯片区域,避免中间有遮挡。
- 权限配置要生效:修改Entitlements后,记得重新签名应用,确保权限正确加载。
内容的提问来源于stack exchange,提问作者Jan Moritz




