Native 태그에 대한 지원 추가
지원 범위는 기존 Core NFC와 동일(아이폰 7, 7플러스 부터)
API 변화
entitlement에 NDEF 뿐 아니라, 네이티브 포맷을 지원하기 위한 엔트리도 추가
어떤 태그를 지원할지를 정해서, ReaderSession을 만든다.
콜백에서 발견한 태그 개체를 받는다.
원하는 태그 개체와 연결
태그 개체를 통해서 작업 수행
끝나면 세션을 무효화시키고 태그 개체를 릴리즈함
NDEF 태그 쓰기
백그라운드 스캐닝이 가능한 NDEF 태그를 iOS에서 만들어 낼 수 있다.
// 태그 discovery 콜백
optional func readerSession(_ session: NFCNDEFReaderSession, didDetect tags: [NFCNDEFTag])
// NDEF Tag 프로토콜
var isAvailable: Bool { get }
func queryNDEFStatus(completionHandler: @escaping (NFCNDEFStatus, Int, Error?) -> Void)
func readNDEF(completionHandler: @escaping (NFCNDEFMessage?, Error?) -> Void)
func writeNDEF(_ ndefMessage: NFCNDEFMessage, completionHandler: @escaping (Error?) -> Void)
func writeLock(completionHandler: @escaping (Error?) -> Void)
쓰기 예시
delegate와 함께 세션 만들기
@IBAction func beginScanning(_ sender: Any) {
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, didDetect tags: [NFCNDEFTag]) {
// 찾아낸 태그와 연결하고, 쓰기 연산을 수행
// 연결된 태그는 다른 태그를 연결하거나, 폴링을 다시 시작하거나, 세션이 무효화될 때까지 유지된다.
let tag = tags.first!
session.connect(to: tag) { (error: Error?) in
tag.queryNDEFStatus() { (ndefStatus: NFCNDEFStatus, capacity: Int, error: Error?) in
guard ndefStatus == .readWrite else { return } // 쓰기를 지원해야 함
let myMessage = NFCNDEFMessage(data: Data()) // capacity를 넘어가는 메시지는 쓰면 안됨
tag.writeNDEF(myMessage) { (error: Error?) in
session.invalidate()
}
}
}
네이티브 태그 읽기
ISO7816 - Type A와 Type B
사용 예시
APDU(Application Protocol Data Unit)인터페이스를 활용함
요구사항
Application Identifier(AID) 리스트가 Info.plist에 있어야 함
태그 발견 콜백은 태그가 ISO7816에 호환되고, 명시된 AID를 포함하고 있어야만 호출됨
이때 AID가 미리 선택된 상태로 전달되긴 하지만, 일단 전달되고 나면 다른 AID를 선택해도 됨
결제용 카드는 지원하지 않는다. (결제 관련 AID는 미지원)
NFCISO7816Tag
프로퍼티
메소드
func sendCommand(apdu: NFCIOS7816APDU, completionHandler: @escaping (Data, UInt8, UInt8, Error?) -> Void)
구현 예시
session 만들기
@IBAction func beginScanning(_ sender: Any) {
session = NFCTagReaderSession(pollingOption: .iso14443, delegate: self) // iso14443: Type A,B의 기반 기술
session?.alertMessage = "Hold your iPhone near the ISO7816 tag to begin transaction"
session?.begin()
}
태그 연결 및 작업
func tagReaderSession(_ session: NFCTagReaderSession, didDetect tags: [NFCTag]) {
if case let NFCTag.iso7816(tag) = tags.first {
session.connect(to: tag) { (error: Error?) in
let myAPDU = NFCISO7816APDU(instructionClass: 0, instructionCode: 0x00, p1Parameter: 0,
p2parameter: 0, data: Data(), expectedResponseLength: 16)
tag.sendCommand(apdu: myAPDU) { (response: Data, sw1: UInt8, sw2: UInt8, error: Error?) in
guard error != nil && !(sw1 == 0x90 && sw2 == 0) else {
session.invalidate(errorMessage: "Application failure") // sheet ui에 에러메시지가 나오게 된다.
return
}
}
}
}
}
MiFare
Type A 태그 기반의 기술(일부만 호환)
NXP에 의해 개발되었고, 티케팅과 뱃지 시스템에서 전세계적으로 사용됨
NFCMiFareTag
프로퍼티
메소드
func sendMiFareCommand(commandPacket command: Data, completionHandler: @escaping (Data, Error?) -> Void)
func sendMiFareISO7816Command(apdu: NFCIOS7816APDU, completionHandler: @escaping (Data, UInt8, UInt8, Error?) -> Void)
구현 예시
session 만들기
@IBAction func beginScanning(_ sender: Any) {
session = NFCTagReaderSession(pollingOption: .iso14443, delegate: self) // MiFare도 iso14443으로 지정
session?.alertMessage = "Hold your iPhone near the tag to begin transaction"
session?.begin()
}
태그 연결 및 작업
func tagReaderSession(_ session: NFCTagReaderSession, didDetect tags: [NFCTag]) {
if case let NFCTag.miFare(tag) = tags.first {
session.connect(to: tag) { (error: Error?) in
// ...
tag.sendMiFareCommand(coomandPacket: command) { (response: Data, error: Error?) in
// 에러 확인 후 결과 처리
}
}
}
}
ISO15693 - Type 5 혹은 vicinity tag(주변 태그, 도난 방지용으로 제품에 붙어있는 태그 생각하면 됨)
상품 판매, 산업용, 의료용으로도 사용됨
NFCISO15693Tag
대신 일반적인 연산들에 대해서는 편의 메소드를 제공한다.
구현 예시
session 만들기
@IBAction func beginScanning(_ sender: Any) {
session = NFCTagReaderSession(pollingOption: .iso15693, delegate: self) // MiFare도 iso14443으로 지정
session?.alertMessage = "Hold your iPhone near the tag to begin transaction"
session?.begin()
}
태그 연결 및 작업
func tagReaderSession(_ session: NFCTagReaderSession, didDetect tags: [NFCTag]) {
if case let NFCTag.iso15693(tag) = tags.first {
session.connect(to: tag) { (error: Error?) in
// ...
tag.readSingleBlock(requestFlags: [.highDataRate, .address], blockNumber: 0) { (response: Data, error: Error?) in
// 에러 확인 후 결과 처리
}
}
}
}
FeliCa
Sony에 의해 만들어진 포맷. 일본에서 교통 및 결제 시스템으로 많이 활용됨
요구사항
사용하고자 하는 FeliCa 시스템 코드가 info.plist에 있어야 함. → 보안을 위해 와일드 카드는 허용하지 않음
태그 발견 후, 해당 시스템 코드와 일치하는 경우에만 콜백 호출됨
NFCFeliCaTag
기본 메소드
func sendFeliCaCommand(commandPacket: Data, completionHandler: @escaping (Data, Error?) → Void)
그 외에도 일반적인 연산에 대해서는 편의 메소드 제공
구현 예시
session 만들기
@IBAction func beginScanning(_ sender: Any) {
session = NFCTagReaderSession(pollingOption: .iso18092, delegate: self) // MiFare도 iso14443으로 지정
session?.alertMessage = "Hold your iPhone near the tag to begin transaction"
session?.begin()
}
태그 연결 및 작업
func tagReaderSession(_ session: NFCTagReaderSession, didDetect tags: [NFCTag]) {
if case let NFCTag.feliCa(tag) = tags.first {
session.connect(to: tag) { (error: Error?) in
// ...
tag.requestResponse() { (mode: Int, error: Error?) in
// 에러 확인 후 결과 처리
}
}
}
}
데모