Last active
July 8, 2020 18:13
-
-
Save treastrain/f73334e4c7ef7591226277abe95ec071 to your computer and use it in GitHub Desktop.
iOS 14 での Core NFC による交通系ICカードの残高読み取りサンプル(集まれSwift好き!Swift愛好会スピンオフ WWDC20セッション要約会 @ Online July 9, 2020)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Created by treastrain on 2020/07/08. | |
// Copyright © 2020 treastrain / Tanaka Ryoga. All rights reserved. | |
// | |
/// 1. プロジェクトの TARGET から開発している iOS Application を選び、Signing & Capabilities で Near Field Communication Tag Reading を有効にする(Near Field Communication Tag Reader Session Formats が entitlements ファイルに含まれている必要がある)。 | |
/// 2. Near Field Communication Tag Reader Session Formats の中に "NFC tag-specific data protocol (TAG)" が含まれていることを確認する。 | |
/// 3. 開発している iOS Application の Info.plist に "Privacy - NFC Scan Usage Description (NFCReaderUsageDescription)" を追加する。 | |
/// 4. 開発している iOS Application の Info.plist に "ISO18092 system codes for NFC Tag Reader Session (com.apple.developer.nfc.readersession.felica.systemcodes)" を追加し、読み取る際に使用する FeliCa システムコード `0003` を記述する。 | |
import UIKit | |
import CoreNFC | |
class ViewController: UIViewController, NFCTagReaderSessionDelegate { | |
var session: NFCTagReaderSession? | |
override func viewDidLoad() { | |
super.viewDidLoad() | |
guard NFCTagReaderSession.readingAvailable else { | |
// ... | |
return | |
} | |
self.session = NFCTagReaderSession(pollingOption: .iso18092, delegate: self) | |
self.session?.alertMessage = "カードを平らな面に置き、カードの下半分を隠すように iPhone をその上に置きます。" | |
self.session?.begin() | |
} | |
func tagReaderSession(_ session: NFCTagReaderSession, didDetect tags: [NFCTag]) { | |
guard let tag = tags.first, tags.count == 1 else { | |
session.invalidate(errorMessage: "タグが見つからなかったか、複数のタグが同時に検出されました。") | |
return | |
} | |
session.connect(to: tag) { (error) in | |
if let error = error { | |
session.invalidate(errorMessage: error.localizedDescription) | |
return | |
} | |
guard case .feliCa(let feliCaTag) = tag else { | |
session.invalidate(errorMessage: "FeliCa タグではないものが検出されました。") | |
return | |
} | |
/* | |
// iOS 13 まで | |
feliCaTag.readWithoutEncryption(serviceCodeList: CJRC.Balance.serviceCodeList, blockList: CJRC.Balance.blockList) { (statusFlag1, statusFlag2, blockData, error) in | |
if let error = error { | |
session.invalidate(errorMessage: error.localizedDescription) | |
} | |
guard statusFlag1 == 0x00, statusFlag2 == 0x00 else { | |
session.invalidate(errorMessage: "ステータスフラグがエラーを示しています。\(statusFlag1), \(statusFlag2)") | |
return | |
} | |
let data = blockData.first! | |
let balance = Int(data[11]) + Int(data[12]) << 8 | |
session.alertMessage = "残高: ¥\(balance)" | |
session.invalidate() | |
} | |
*/ | |
// iOS 14 から | |
feliCaTag.readWithoutEncryption(serviceCodeList: CJRC.Balance.serviceCodeList, blockList: CJRC.Balance.blockList) { (response) in | |
switch response { | |
case .success((let statusFlag, let blockData)): | |
guard statusFlag.statusFlag1 == 0x00, statusFlag.statusFlag2 == 0x00 else { | |
session.invalidate(errorMessage: "ステータスフラグがエラーを示しています。\(statusFlag)") | |
return | |
} | |
let data = blockData.first! | |
let balance = Int(data[11]) + Int(data[12]) << 8 | |
session.alertMessage = "残高: ¥\(balance)" | |
session.invalidate() | |
case .failure(let error): | |
session.invalidate(errorMessage: error.localizedDescription) | |
} | |
} | |
} | |
} | |
func tagReaderSession(_ session: NFCTagReaderSession, didInvalidateWithError error: Error) { | |
print("Invalidate error:", error.localizedDescription) | |
} | |
func tagReaderSessionDidBecomeActive(_ session: NFCTagReaderSession) { | |
// ... | |
} | |
} | |
struct CJRC { | |
struct Balance { | |
static let serviceCodeList = [Data([0x8B, 0x00])] | |
static let blockList = [Data([0x80, 0x00])] | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment