💳

[Flutter]NFC読み取りで遊ぶ

に公開

ぽちぽちのつどいGW Advent(?) Calendar6日目の記事です!

今日は前から気になっていたNFC読み取りをやってみます。

ios,androidそれぞれの設定方法は参考記事を読んでください。

使用パッケージ

https://pub.dev/packages/nfc_manager

実行環境

Galaxy Z Fold3 5G SC55B
Android 14,OneUI 6.1.1

とりあえず読み取り

とりあえず参考のコードを動かしてみたのですが動いたけどなんだかよくわからないデータが出てきたのですがとりあえずnfc_managerで読み取りが可能であることがわかりました。
このコードの一部を借りて実装していくことにしました。
AI(GPT-4o)にも生成させたのですが精度が悪いのとFlutter_nfc_kitを使いたがることがわかりました。
AIの出したコードでやってみたのですが、タイムアウトするだけで使い物になりませんでした。
やはりさっきのコードが良さそうとなったのでさっきのコードを使いつつAIに修正を手伝ってもらって実装しました。

発生した問題

一番多かった問題は読み取りを完了する前に読み取れていないと言う理由でエラーになってしまって強制的に読み取りが終了してしまうということです。
これのバグの対処に時間がかかりました。
結果として原因はよく話からなかったですが別の方の記事では履歴を読み取っており履歴や交通系ICの仕様について詳しく書かれているのでこれを参考に一から再生成し直しました。

ついに・・・


読み取れた!
一応おサイフケータイでも確認してみると...!!!

あれ???残高が全然違う
FelicaはISO規格(iso18092←今回知った)で全国統一されているはずなので変わることはないはず...16進数の参照箇所が違うのは明確なので探してみる。

dart
final balanceBytes = response.sublist(13, 15);
final balance = balanceBytes[0] + (balanceBytes[1] << 8);
result.value = '残高: ¥$balance';

うーんこれ違うところを参照してね???となったので修正してみる。
GPTに投げてみると...

GPT:
Read Without Encryption コマンドで読み取った利用履歴のデータ構造は以下のようになっています(1ブロック = 16バイト):
0〜15バイト目 が1件目の履歴(1ブロック)
この中の 11バイト目と12バイト目(= インデックス[10], [11])に残高が入っていることが一般的です(ただし、カード種類による)

dart
// 残高は1ブロック内の [10], [11] に格納(リトルエンディアン)
final blockData = response.sublist(13, 29); // 最初のブロック(16バイト)
final balance = blockData[10] + (blockData[11] << 8);
result.value = '残高: ¥$balance';

これに修正して挑戦してみる。

おおおお!!!できた!
しっかりと残高が読み取れています。

コード

https://github.com/pochipochi-tudoi/nfc_app
https://github.com/pochipochi-tudoi/nfc_app/blob/main/lib/main.dart

おまけ

先日沖縄に行ってきた時に沖縄だけで使える交通系ICがあることを帰りの飛行機に乗る直前の路線バスの中の広告で知りました。その名もOKICAおお〜いい名前ですね😆。
https://info.okica.jp/
ということでお土産として購入したので試しに読み取ってみました。
結果は....

うーん何となく察してはいましたがやはり読み取ることはできませんでした。
色々調査してみると12バイトの長さしかないことが原因みたいです。今回のコードは残高に直接アクセスしているのではなく利用履歴の一番新しい部分の残高を参照していることが原因みたいです。
一回でも沖縄でゆいれーるで使っておけば...と今更後悔してます。全国共通交通系ICではないので本州では使えないです。なのでもし利用履歴があっても読み取れるとは限りません。誰か検証してくれ!

まとめ

利用履歴で読み取っているのと未検証な部分(iOS含む)が多いので正常に動作する可能性は低いです。
しかしFlutterでもNFC読み取りができること、交通系ICの読み取りができること、がわかっただけでも収穫があったと言えます。これを活用すれば色々なアプリに応用できると感じる結果となりました。
悔しかったのはOKICA読み取ることができなかったことですかね😅😅😅
このアプリでは読み取れたのでおそらく読み取り方を正しくすれば読み取れるようになりそう。
https://play.google.com/store/apps/details?id=digital.cardreader&pcampaignid=web_share
履歴が読み取れるということはいつ何駅から何駅まで移動したかもしくはいつ買い物に何円使ったかがわかるのでListViewと併用すればいい感じのアプリが作れるようになりそうですね(笑)

というわけで、ぽちぽちのつどいGW Advent(?) Calendar 6日目はNFCを使って遊んだ話でした!

参考

https://zenn.dev/joo_hashi/scraps/e45fdfdd179658
https://qiita.com/koji4104/items/4386a82e3fb92bb1580a

ぽちぽちのつどい

Discussion