NFC (Near Field Communication)
Type
Mode
NFC card emulation |
NFC reader/writer |
NFC peer-to-peer |
NFC를 탑재한 기기가 기존의 비접촉식 카드와 같이 동작 |
NFC를 탑재한 기기가 RFID 태그 리더기로 동작 |
NFC 기기 간 데이터 송수신 |
HCE (Host Card Emulation)
- 호스트 카드 에뮬레이션(Host card emulation, HCE)은 소프트웨어만을 사용하여 다양한 전자 식별자(접근, 수송, 은행업무)의 정확한 가상 표현을 제공하는 소프트웨어 구조
iOS NFC
NFC Type
- https://smartits.tistory.com/206
iso14443
- ISO14443-4 type A / B tag with ISO7816 communication
- MiFare technology tag (MIFARE Plus, UltraLight, DESFire)
iso15693
- ISO15693 tag
iso18092
- FeliCa tag
pace
- Password Authenticated Connection Establishment (PACE) with ISO7816 communication
VAS (Value Added Service)
- Apple
지원 모드
NFC card emulation |
NFC reader/writer |
NFC peer-to-peer |
애플페이(월렛)에서만 지원 |
개발 가능하도록 지원 |
로드맵상 지원 예정 없음 |
SampleCode
iso7816 (T-Money)
- Project Setting
Capability
: Near Field Communication Tag Reading
- Adds the Near Field Communication Tag Reader Session Formats
Entitlement
to the entitlements file
<key>com.apple.developer.nfc.readersession.formats</key>
<array>
<string>TAG</string>
</array>
- add the
NFCReaderUsageDescription
key as a string item to the Info.plist file
<key>NFCReaderUsageDescription</key>
<string>NFC tag to read Tags Info into the application</string>
- add the list of the application identifiers supported in your app (T-Money AID : D4100000030001)
<key>com.apple.developer.nfc.readersession.iso7816.select-identifiers</key>
<array>
<string>D4100000030001</string>
</array>
import CoreNFC
class NFCTagReader: NFCTagReaderSessionDelegate {
var session: NFCReaderSession?
// MARK: - BeginScanning
func beginScanning(_ sender: Any) {
session = NFCTagReaderSession(pollingOption: .iso14443, delegate: self)
session?.alertMessage = "Hold your iPhone near the item to learn more about it."
session?.begin()
}
// MARK: - NFCTagReaderSessionDelegate
func tagReaderSessionDidBecomeActive(_ session: NFCTagReaderSession) {
}
func tagReaderSession(_ session: NFCTagReaderSession, didInvalidateWithError error: Error) {
// Check the invalidation reason from the returned error.
if let readerError = error as? NFCReaderError {
// Show an alert when the invalidation reason is not because of a
// successful read during a single-tag read session, or because the
// user canceled a multiple-tag read session from the UI or
// programmatically using the invalidate method call.
if ((readerError.code != .readerSessionInvalidationErrorUserCanceled) {
let alertController = UIAlertController(
title: "Session Invalidated",
message: error.localizedDescription,
preferredStyle: .alert
)
alertController.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
DispatchQueue.main.async {
self.present(alertController, animated: true, completion: nil)
}
}
}
// To read new tags, a new session instance is required.
self.session = nil
}
func tagReaderSession(_ session: NFCTagReaderSession, didDetect tags: [NFCTag]) {
if tags.count > 1 {
// Restart polling in 500ms
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, execute: {
session.restartPolling()
})
return
}
if case let NFCTag.iso7816(tag) = tags.first! {
session.connect(to: tags.first!) { (error: Error?) in
guard error == nil else {
session.alertMessage = "Application failure : \(String(describing: error))"
session.invalidate(errorMessage: "Application failure")
return
}
// Application Data Unit (APDU).
let myAPDU = NFCISO7816APDU(data: "00a4040007d4100000030001".hexaData)!
tag.sendCommand(apdu: myAPDU) { (response: Data, sw1: UInt8, sw2: UInt8, error: Error?) in
guard error == nil else {
session.alertMessage = "Application failure (\(String(describing: error)))"
session.invalidate(errorMessage: "Application failure (\(String(describing: error)))")
return
}
session.alertMessage = "\(response.hexEncodedString())"
session.invalidate()
}
}
}
}
}
extension StringProtocol {
var hexaData: Data { .init(hexa) }
var hexaBytes: [UInt8] { .init(hexa) }
private var hexa: UnfoldSequence<UInt8, Index> {
sequence(state: startIndex) { startIndex in
guard startIndex < self.endIndex else { return nil }
let endIndex = self.index(startIndex, offsetBy: 2, limitedBy: self.endIndex) ?? self.endIndex
defer { startIndex = endIndex }
return UInt8(self[startIndex..<endIndex], radix: 16)
}
}
}
extension Data {
struct HexEncodingOptions: OptionSet {
let rawValue: Int
static let upperCase = HexEncodingOptions(rawValue: 1 << 0)
}
func hexEncodedString(options: HexEncodingOptions = []) -> String {
let format = options.contains(.upperCase) ? "%02hhX" : "%02hhx"
return self.map { String(format: format, $0) }.joined()
}
}
NDEF
Leave a comment