Alex Huang
May 31
Estimated reading time: 10 minute(s)
NFCReaderUsageDescription
key to your Info.plist
file. This string should describe why your app needs access to the device’s NFC reader.NFCNDEFReaderSession
object. Here’s how to configure and start a reader session:import CoreNFC
class ViewController: UIViewController, NFCNDEFReaderSessionDelegate {
var session: NFCNDEFReaderSession?
@IBAction func beginScanning(_ sender: Any) {
guard NFCNDEFReaderSession.readingAvailable else {
let alertController = UIAlertController(
title: "Scanning Not Supported",
message: "This device doesn't support tag scanning.",
preferredStyle: .alert
)
alertController.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
self.present(alertController, animated: true, completion: nil)
return
}
session = NFCNDEFReaderSession(delegate: self, queue: nil, invalidateAfterFirstRead: false)
session?.alertMessage = "Hold your iPhone near the item to learn more about it."
session?.begin()
}
func readerSession(_ session: NFCNDEFReaderSession, didDetectNDEFs messages: [NFCNDEFMessage]) {
for message in messages {
for record in message.records {
if let string = String(data: record.payload, encoding: .utf8) {
print("NFC Tag Content: \(string)")
}
}
}
}
func readerSession(_ session: NFCNDEFReaderSession, didInvalidateWithError error: Error) {
print("NFC Session Invalidated: \(error.localizedDescription)")
}
}
@IBAction func beginWrite(_ sender: Any) {
session = NFCNDEFReaderSession(delegate: self, queue: nil, invalidateAfterFirstRead: false)
session?.alertMessage = "Hold your iPhone near an NDEF tag to write the message."
session?.begin()
}
func readerSession(_ session: NFCNDEFReaderSession, didDetect tags: [NFCNDEFTag]) {
if tags.count > 1 {
let retryInterval = DispatchTimeInterval.milliseconds(500)
session.alertMessage = "More than 1 tag is detected. Please remove all tags and try again."
DispatchQueue.global().asyncAfter(deadline: .now() + retryInterval) {
session.restartPolling()
}
return
}
let tag = tags.first!
session.connect(to: tag) { (error: Error?) in
if let error = error {
session.alertMessage = "Unable to connect to tag."
session.invalidate()
return
}
tag.queryNDEFStatus { (ndefStatus, capacity, error) in
if let error = error {
session.alertMessage = "Unable to query the NDEF status of tag."
session.invalidate()
return
}
switch ndefStatus {
case .notSupported:
session.alertMessage = "Tag is not NDEF compliant."
session.invalidate()
case .readOnly:
session.alertMessage = "Tag is read only."
session.invalidate()
case .readWrite:
let payload = NFCNDEFPayload.wellKnownTypeTextPayload(string: "Hello, NFC!", locale: Locale(identifier: "en"))
let message = NFCNDEFMessage(records: [payload!])
tag.writeNDEF(message) { (error: Error?) in
if let error = error {
session.alertMessage = "Write NDEF message failed: \(error)"
} else {
session.alertMessage = "Write NDEF message successful."
}
session.invalidate()
}
@unknown default:
session.alertMessage = "Unknown NDEF tag status."
session.invalidate()
}
}
}
}
NFCTagReaderSession
class. This session type allows you to send and receive data from these tags, enabling advanced use cases like secure element communication.import CoreNFC
func startISO7816Session() {
let session = NFCTagReaderSession(pollingOption: .iso14443, delegate: self)
session?.alertMessage = "Hold your iPhone near the ISO 7816 tag."
session?.begin()
}
func tagReaderSession(_ session: NFCTagReaderSession, didDetect tags: [NFCTag]) {
if let firstTag = tags.first {
session.connect(to: firstTag) { error in
if let error = error {
session.invalidate(errorMessage: "Connection failed: \(error.localizedDescription)")
return
}
if case let .iso7816(tag) = firstTag {
// Perform ISO 7816 specific operations
}
}
}
}
NFCTagReaderSession
. These tags are commonly used in transportation systems and access control.func startMIFARESession() {
let session = NFCTagReaderSession(pollingOption: .iso14443, delegate: self)
session?.alertMessage = "Hold your iPhone near the MIFARE tag."
session?.begin()
}
func tagReaderSession(_ session: NFCTagReaderSession, didDetect tags: [NFCTag]) {
if let firstTag = tags.first {
session.connect(to: firstTag) { error in
if let error = error {
session.invalidate(errorMessage: "Connection failed: \(error.localizedDescription)")
return
}
if case let .miFare(tag) = firstTag {
// Perform MIFARE specific operations
}
}
}
}
CardSession
class. This allows your app to emulate a card and interact with external NFC readers.import CoreNFC
func CardSessionSample() {
let ProcessAPDU: (_: Data) -> Data = { capdu in return Data() }
Task() {
guard NFCReaderSession.readingAvailable, CardSession.isSupported, await CardSession.isEligible else {
return
}
var presentmentIntent: NFCPresentmentIntentAssertion?
let cardSession: CardSession
do {
presentmentIntent = try await NFCPresentmentIntentAssertion.acquire()
cardSession = try await CardSession()
} catch {
return
}
for try await event in cardSession.eventStream {
switch event {
case .sessionStarted:
cardSession.alertMessage = "Communicating with card reader."
case .readerDetected:
try await cardSession.startEmulation()
case .readerDeselected:
await cardSession.stopEmulation(status: .success)
case .received(let cardAPDU):
do {
let responseAPDU = ProcessAPDU(cardAPDU.payload)
try await cardAPDU.respond(response: responseAPDU)
} catch {
// Handle the error
}
case .sessionInvalidated(reason: _):
cardSession.alertMessage = "Ending communication with card reader."
}
}
presentmentIntent = nil
}
}