まず確認すること: Info.plist のシステムコード登録が原因かどうか
iOS 17 で FeliCa が読めなくなった場合、最初に疑うべきは Info.plist に登録したシステムコード数が iOS 17 の処理上限に達していることです。上限に起因する問題は症状が「読めたり読めなかったりする」という断続的な不安定さとして現れるため、ハードウェア不良やNFCセッション管理のバグと混同されやすい点に注意が必要です。
Core NFC で FeliCa を読み取る仕組みの概要
Core NFC とは、Apple が iOS 13 から FeliCa 読み取りに対応したフレームワークです(出典: Apple Developer Documentation「Core NFC」、および WWDC 2020 セッション 10209「Core NFC Enhancements」)。
FeliCa 読み取りの流れは次のとおりです。
- 設定の準備: エンタイトルメントファイル(
.entitlements)と Info.plist の2箇所にcom.apple.developer.nfc.readersession.felica.systemcodesキーを記載し、読み取り対象のシステムコードを文字列配列として列挙する。どちらか一方が欠けると「Missing required entitlement」エラーが発生します(出典: Apple Developer Forums スレッド #685809「NFC (entitlements)」、スレッド #781710「NFCTagReaderSession - Missing required entitlement」)。 - セッション開始:
NFCTagReaderSessionを初期化し、デリゲートでNFCFeliCaTagプロトコルのメソッドを実装する。 - ポーリングと検出: セッション開始後、端末が NFC フィールドを有効化し、登録済みシステムコードを持つタグを検出する。
- データ取得: タグ検出後、
currentSystemCodeやcurrentIDmを取得してアプリのロジックへ渡す。
ここで重要な制約があります。Apple Developer Forums スレッド #122504 および GitHub metrodroid/metrodroid Issue #613(https://github.com/metrodroid/metrodroid/issues/613)で報告されているとおり、**1回の NFCTagReaderSession でポーリング対象にできるシステムコードは1件のみ**です。複数のシステムコードを持つ FeliCa カードを正しく読み取れないケースはこの制約に起因しており、バージョンをまたいで再現が確認されています。
対応デバイスは iPhone 7 以降の全モデルです。ただし FeliCa 読み取りを実機で試験する際は、日本国内で入手したデバイスを使用することを推奨します。
症状から原因を切り分けるチェックリスト
下表で、症状ごとに「システムコード登録数の上限が原因か否か」を一次判定できます。チェックがすべて「関係薄」であれば、タイムアウトやセッション管理など別の原因を疑い、詳しい診断は後続セクションで扱います。
| 症状 | システムコード登録数が原因の可能性 | 次のアクション |
|---|---|---|
| 特定カード種別だけ読めない、他は読める | 高い | 該当カードのシステムコードが Info.plist に含まれているか確認 |
| iOS バージョンアップ後に突然読めなくなった | 高い | バージョンごとの処理上限を後述の比較表で確認 |
| 登録コード数が多いほど失敗率が上がる | 高い | 登録数を段階的に削減して再検証 |
| 読み取り成功率は変わらないが遅くなった | 低い | 読み取り速度の最適化手順を参照してください |
| 特定端末モデルでのみ発生する | 低い | 端末固有の NFC チップ挙動を疑う |
| エラーログに「Missing required entitlement」が出る | 原因が異なる | エンタイトルメントと Info.plist の両方に登録されているか確認 |
以上のチェックリストで「高い」に該当する症状がある場合、次のセクションで iOS 17 の具体的な上限値と挙動を確認してください。
iOS 17 におけるシステムコード登録数の上限とは?
当社の実機調査では、iOS 17 では Info.plist に登録できるシステムコードの処理上限が約 148 個であることを特定しています。ただしこの上限以前に、より根本的な動作制約として押さえておくべき仕様があります。
上限を超えたときに起きる挙動
Apple Developer Forums(スレッド #122504「CoreNFC/FeliCa bug: cannot read da…」)および GitHub の metrodroid/metrodroid Issue #613「iOS: FeliCa with more than 1 system code cannot be read」では、1 回の NFCTagReaderSession でポーリング対象にできるシステムコードは 1 件のみ という動作制約が報告されています。
つまり、Info.plist に複数のシステムコードを列挙していても、1 セッションで実際に検索対象となるのは 1 件だけです。この制約を踏まえた上で、登録数が iOS 17 の処理上限(当社実機調査: 約 148 個)を超えた場合の挙動は以下のとおりです。
| 登録数の状態 | 発生する挙動 |
|---|---|
| 1 件 | 正常に検出・読み取りできる |
| 2 件以上・上限以内 | セッションごとに 1 件しかポーリングされないため、対象外コードのカードは読み取れない |
| 約 148 件超(iOS 17 実測) | カード自体が検出されない、またはセッション開始直後にエラーで終了する |
上限超過時に表示されるエラーコードは NFCReaderSessionInvalidationErrorSystemIsBusy や NFCReaderErrorUnsupportedFeature として現れるケースが多く、ログだけでは登録数が原因とは気づきにくいため注意が必要です。
なお、2 件以上のシステムコードを持つ物理カード(例: 交通系 IC と電子マネー機能が共存するカード)の読み取り失敗も、同一の根本原因から生じます。この問題への対処は「Info.plist への正しいシステムコード設定手順」セクションで詳しく扱います。
iOS 16 / iOS 18 / iOS 26 との上限比較
当社の実機調査で計測したバージョン別の処理上限を以下にまとめます。数値はすべて同一テスト環境(機種・試行回数を統一)での実測値です。バージョン間の検出時間の詳細な比較については、別記事「iOS NFC FeliCa 検出時間 iOS 17 iOS 18 比較 実測」を参照してください。
| iOS バージョン | システムコード処理上限(実測) | 備考 |
|---|---|---|
| iOS 16 | 当社未計測 | 案件により変動する可能性あり |
| iOS 17 | 約 148 個 | 本記事の対象バージョン |
| iOS 18 | 当社調査中 | 案件により変動する可能性あり |
| iOS 26 | 当社調査中 | 2025年時点でベータ段階 |
Apple は Core NFC の仕様をメジャーアップデートだけでなくマイナアップデートでも変更することがあります。iOS 16 以前や iOS 18 以降の上限値については現時点で確定数値を公表できないため、自社環境での実機計測を推奨します。
また、Core NFC による FeliCa 読み取り自体は iOS 13 から対応しています(出典: Apple Developer Documentation「Core NFC」および WWDC 2020 セッション 10209「Core NFC Enhancements」)。iOS 12 以前のデバイスはそもそも FeliCa 読み取り非対応のため、サポート対象バージョンの下限として必ず確認してください。
設定に必要な箇所は エンタイトルメントファイルと Info.plist の 2 箇所です(出典: Apple Developer Forums スレッド #685809「NFC (entitlements)」、スレッド #781710「NFCTagReaderSession - Missing required entitlement」)。どちらか一方でも登録数が上限を超えた場合、もう一方が正常でも読み取りが失敗します。両ファイルを必ずセットで確認してください。具体的な設定手順は次のセクションで説明します。
Info.plist への正しいシステムコード設定手順
com.apple.developer.nfc.readersession.felica.systemcodes キーに、読み取り対象のシステムコードを16進数文字列の配列として登録するのが基本形です。ただし設定箇所はInfo.plistだけではなく、エンタイトルメントファイルとの2段構えになっている点を押さえてください。
必須設定項目と記述フォーマット
FeliCaをCore NFCで読み取るには、以下の2ファイルへの設定が両方そろって初めて機能します。どちらか一方が欠けていると、ビルドは通ってもランタイムでNFCReaderSessionInvalidationErrorが返ります。
| 設定ファイル | キー名 | 値の形式 | 役割 |
|---|---|---|---|
Info.plist |
com.apple.developer.nfc.readersession.felica.systemcodes |
16進数文字列の配列(例: "8008", "88B4") |
セッション起動時にポーリング対象をOSへ宣言する |
*.entitlements |
com.apple.developer.nfc.readersession.felica.systemcodes |
同上 | App Storeレビュー時および実機起動時の権限チェックに使われる |
Info.plist |
NFCReaderUsageDescription |
任意の日本語説明文字列 | システムダイアログに表示するユーザ向け説明文 |
設定手順は番号順に実施してください。
エンタイトルメントファイルの確認(所要時間: 1〜2分)
Xcodeの「Signing & Capabilities」タブから「Near Field Communication Tag Reading」を追加する。追加済みの場合はスキップ可。つまずきやすい点: 複数ターゲットを持つプロジェクトでは、ターゲットごとにエンタイトルメントが分かれているため、誤ったターゲットに追加しても症状が再現します。エンタイトルメントファイルへのシステムコード記入(所要時間: 2〜5分)
.entitlementsをソースエディタで開き、com.apple.developer.nfc.readersession.felica.systemcodesキーの<array>内に<string>XXXX</string>形式で追加する。16進数は大文字・小文字どちらでも動作しますが、チームで表記を統一しておくと照合が容易です。Info.plist への同一リストの転記(所要時間: 2〜5分)
エンタイトルメントに書いたシステムコードと同一のリストをInfo.plistにも記載する。2ファイルの内容が一致していないとOSが権限エラーを返すことがあります。つまずきやすい点: Xcodeのプロパティリストエディタで入力すると先頭ゼロが数値として丸められる場合があるため、ソースエディタで文字列として直接編集することを推奨します。NFCReaderUsageDescriptionの記載確認(所要時間: 1分)
空文字や未設定のままだとApp Storeの審査で差し戻されます。端末のシステムダイアログに表示される文言なので、読み取り目的が伝わる文章を設定してください。実機での起動確認(所要時間: 5〜10分)
シミュレータはCore NFCを未サポートのため、実機が必須です。XcodeのデバッグコンソールでNFCReaderErrorが出ないことを確認してください。
つまずきやすいポイント: ワイルドカードと固定コードの混在
88B4 はFeliCa規格のワイルドカードに相当するシステムコードで、これを登録すると多くのカード種別をまとめて検出できます。ただし、ワイルドカードと固定コードを配列に混在させる場合には注意が必要です。
混在時に確認すべき3点
- 優先順位の保証がない: iOSがポーリング時にリスト内のシステムコードをどの順序で使うかは非公開仕様です。固定コードを先頭に書いても必ずしも優先されません。
- 登録数にカウントされる:
88B4も1個としてカウントされます。ワイルドカードを使えば合計登録数が自動的に減るわけではありません。登録数の上限については前セクションで触れたとおりです。 - カード種別の取り違えリスク: ワイルドカードでヒットしたカードをアプリ側で種別判定するには、レスポンスのシステムコードフィールドを解析するロジックが別途必要になります。このロジックが不足していると、意図しないカードのデータを読み込む誤作動につながります。
固定コードのみで運用が完結する場合は、ワイルドカードを混在させないほうがデバッグが容易です。読み取り対象カードの種別が確定しておらず、広く拾う必要がある場合のみワイルドカードの採用を検討してください。