NFC には A, B, F… がある【iOS  Core NFC】

Core NFC Advent Calendar 2019、私としては2回目の記事になります。

iOS 13 で大幅に機能が追加され、実用的になった Core NFC ですが、そもそも NFC には大きく3つのタイプがあります。

# 3つの通信規格
この記事でいう NFC の3つのタイプとは、

- NFC-A
- NFC-B
- NFC-F

のことを指します。また、NFC-A には MIFARE、NFC-F には FeliCa という呼称もあります。

記事タイトルと噛み合いませんが、この記事は Core NFC Advent Calendar に属するので NFC のより詳しい説明は[こちらの Qiita 記事「NFC関係用語と解説」](https://qiita.com/gpsnmeajp/items/49db2212e632869edaf8)が詳しいです。

これら3つのタイプにあうプロトコルが Core NFC では提供されており、読み書きしたいタグ（カード）の規格がどのタイプなのかに合わせてコーディングしていくことになります。

# それぞれのカードがどのタイプなのか
では、日本で使われているカードが上に挙げたどのタイプなのか一部列挙します。

- NFC-A (MIFARE)
    - taspo
    - いわゆる NFC Pay
- NFC-B
    - 運転免許証
    - パスポート
    - マイナンバーカード
    - 在留カード
    - いわゆる NFC Pay
- NFC-F (FeliCa)
    - 交通系ICカード（Suica、PASMO、ICOCA、…etc.）
    - 電子マネーカード（SF）（楽天Edy、nanaco、WAON、…etc.）
    - 電子マネー（SF 以外）（QUICPay、iD、…etc.）

# Core NFC - Tag Types
さて、[Apple Developer Documentation](https://developer.apple.com/documentation/corenfc) を確認すると、Tag Types の項目は以下のようになっていることがわかります（抜粋）。

- [`protocol NFCISO7816Tag`](https://developer.apple.com/documentation/corenfc/nfciso7816tag)
- [`protocol NFCFeliCaTag`](https://developer.apple.com/documentation/corenfc/nfcfelicatag)
- [`protocol NFCMiFareTag`](https://developer.apple.com/documentation/corenfc/nfcmifaretag)

以上のプロトコルは先に上げた各 Type に対応します。

- NFC-A (MIFARE) ⇔ `protocol NFCMiFareTag` or `protocol NFCISO7816Tag`
- NFC-B ⇔ `protocol NFCISO7816Tag`
- NFC-F (FeliCa) ⇔ `protocol NFCFeliCaTag`

Core NFC には `protocol NFCISO15693Tag` も存在し、RFID にも対応します。

# 使い方
この Core NFC Advent Calendar 2019 にはこれから実際にいろいろなカードを読み取ってみるというテーマの記事が公開予定なので、詳細はそちらに譲るとして、各 NFC Tag を iPhone が検出したときにどのようにデータが渡ってくるかを示します。

```swift:
// class に NFCTagReaderSessionDelegate を継承させる

var readerSession: NFCTagReaderSession?

// ...

func scan() {
    self.readerSession = NFCTagReaderSession(pollingOption: [.iso14443, .iso15693, .iso18092], delegate: self, queue: nil)
    self.readerSession?.alertMessage = "Hold your iPhone near an NFC tag."
    self.readerSession?.begin()
}

// ...

func tagReaderSession(_ session: NFCTagReaderSession, didDetect tags: [NFCTag]) {
    
    switch tags.first! {
    case let .iso7816(iso7816Tag):
        // iso7816Tag: NFCISO7816Tag
        break
    case let .feliCa(feliCaTag):
        // feliCaTag: NFCFeliCaTag
        break
    case let .iso15693(iso15693Tag):
        // iso15693Tag: NFCISO15693Tag
        break
    case let .miFare(miFareTag):
        // miFareTag: NFCMiFareTag
        break
    @unknown default:
        return
    }

    // ...

}
```

まずは `NFCTagReaderSession` を初期化します。上記サンプルでは `.iso14443`、`.iso15693`、`.iso18092`が指定されています。その後、`NFCTagReaderSession` の `begin()` を呼び出すことで iPhone が NFC の読み取りモードになります。
<img width="300" alt="スクリーンショット 2019-11-29 21.53.12.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/90125/57e82ccb-4f60-db17-b629-364da713f478.jpeg">
無事に iPhone が NFC Tag を見つけると `NFCTagReaderSessionDelegate` の `func tagReaderSession(_ session: NFCTagReaderSession, didDetect tags: [NFCTag])` が呼び出されるので、`switch`文を使ってどのプロトコルに合う `NFCTag` が検出されたかを判定します。`NFCTag` は以下のように定義されています。

```swift
@available(iOS 13.0, *)
public enum NFCTag {
    case feliCa(NFCFeliCaTag)
    case iso7816(NFCISO7816Tag)
    case iso15693(NFCISO15693Tag)
    case miFare(NFCMiFareTag)

    public var isAvailable: Bool { get }
}
```

各カードがどの `NFCTag` であるかを特定できたら、その後は `NFCTagReaderSession` の `connect(to:completionHandler:)` を使ってタグにアクセスしていきます。

次回以降はいよいよ実際のカードをどのようにして読み取っていくかを紹介します。

# 参照
- [NFCリーダー | ソリューション／製品・サービス | DNP 大日本印刷](https://www.dnp.co.jp/biz/solution/products/detail/1190582_1567.html)
- [MIFARE](https://www.mifare.net)
- [Creating NFC Tags from Your iPhone | Apple Developer Documentation](https://developer.apple.com/documentation/corenfc/creating_nfc_tags_from_your_iphone)