お、iOS 13 の Core NFC、
— treastrain / とれいん (@treastrain) June 4, 2019
ついに FeliCa、MIFARE タグの読み取りができるようになるみたい!!!#WWDC19 #iOS13 #NFC #FeliCa pic.twitter.com/C1UtAV2byr
iOS 13 以降の Core NFC では FeliCa の読み取りに対応したことがわかったので、読み取るためのサンプルコードを載せます。
サンプルコード
// Created by treastrain on 2019/06/06.
// Copyright © 2019 treastrain / Tanaka Ryoga. All rights reserved.
//
import UIKit
import CoreNFC
class ViewController: UIViewController, NFCTagReaderSessionDelegate {
var session: NFCTagReaderSession?
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
@IBAction func beginScanning(_ sender: UIButton) {
guard NFCTagReaderSession.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
}
self.session = NFCTagReaderSession(pollingOption: .iso18092, delegate: self)
self.session?.alertMessage = "Hold your iPhone near the item to learn more about it."
self.session?.begin()
}
func tagReaderSessionDidBecomeActive(_ session: NFCTagReaderSession) {
print("tagReaderSessionDidBecomeActive(_:)")
}
func tagReaderSession(_ session: NFCTagReaderSession, didInvalidateWithError error: Error) {
if let readerError = error as? NFCReaderError {
if (readerError.code != .readerSessionInvalidationErrorFirstNDEFTagRead)
&& (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)
}
}
}
self.session = nil
}
func tagReaderSession(_ session: NFCTagReaderSession, didDetect tags: [NFCTag]) {
print("tagReaderSession(_:didDetect:)")
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, execute: {
session.restartPolling()
})
return
}
let tag = tags.first!
session.connect(to: tag) { (error) in
if nil != error {
session.invalidate(errorMessage: "Connection error. Please try again.")
return
}
guard case .feliCa(let feliCaTag) = tag else {
let retryInterval = DispatchTimeInterval.milliseconds(500)
session.alertMessage = "A tag that is not FeliCa is detected, please try again with tag FeliCa."
DispatchQueue.global().asyncAfter(deadline: .now() + retryInterval, execute: {
session.restartPolling()
})
return
}
print(feliCaTag)
let idm = feliCaTag.currentIDm.map { String(format: "%.2hhx", $0) }.joined()
let systemCode = feliCaTag.currentSystemCode.map { String(format: "%.2hhx", $0) }.joined()
print("IDm: \(idm)")
print("System Code: \(systemCode)")
session.alertMessage = "Read success!\nIDm: \(idm)\nSystem Code: \(systemCode)"
session.invalidate()
}
}
}
設定事項
Core NFC を使うにあたって、コードだけでなく Xcode プロジェクトの設定もいくつか必要です。
特に、読み取りたい FeliCa のシステムコードをあらかじめ全て指定しておく必要があります。
こちらの記事を参照してください。
動作確認
FeliCa カードを読み取ることはもちろん、Apple Watch の Suica であっても(エミュレートカード)読み取ることができます。
サンプルプロジェクト
このコードが使用されているサンプルプロジェクトを GitHub にて公開しております。
treastrain/ios13-felica-reader: Sample project to read FeliCa on iOS 13 and later - GitHub