【Flutter】利用nfc_manager 读取NFC交通卡信息

 一,问题

        最新,项目对Flutter 读取公交卡内容进行了调查,在pub上看到nfc_manager 反馈还不错,就下了代码使用。因为是对日项目,所以主要是针对日系的Felica的读取,用了一个下午的时间,调查了一下,基本目的可以达到。在此,总结一下几个关键点,希望可以帮助到更多的小伙伴。

二,正文

        nfc_manager 提供了一个非常不错的例子,利用他,我们可以实现nfc卡的基本信息读取。通过读取我们可以获得nfc卡的基本信息。然后我根据tag类型,对felica的信息进行了读取。这里还特意去sony官网查看了相关的卡片文档资料。如果你是一个日系开发者,想看相关的文档,可以参看一下网站,收益匪浅。

ソニー株式会社 | FeliCa | 法人のお客様 | 技術情報

suica - FeliCa Library Wiki - FeliCa Library - OSDN

[PASMO] FeliCa から情報を吸い出してみる - FeliCaの仕様編 [Android][Kotlin] - Qiita

https://www.kenichi-odo.com/articles/2020_10_08_read-suica-by-android

        基于上面的文章,我得到了一下两个重要的结论:

  • felica 中存储的信息最多是20条记录,者20条记录需要通过指令读取,而且一次最多只能读取15条,如果想读取20条信息的话,你就要读两次。
  • 两条命令之间需要有一定的时间间隔 >=501um 。这个需要注意,否则会出问题。 

        下面就是我写的一个建单例子。大家关注_tagRead和_getReadHistoryCommandBytes就好。

import 'dart:typed_data';
import 'package:nfc_manager/platform_tags.dart';
import 'package:flutter/material.dart';
import 'package:nfc_manager/nfc_manager.dart';

void main() {
  WidgetsFlutterBinding.ensureInitialized();
  runApp(MyApp());
}

class MyApp extends StatefulWidget {
  @override
  State createState() => MyAppState();
}

class MyAppState extends State {
  ValueNotifier result = ValueNotifier(null);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text('NfcManager Plugin Example')),
        body: SafeArea(
          child: FutureBuilder(
            future: NfcManager.instance.isAvailable(),
            builder: (context, ss) => ss.data != true
                ? Center(child: Text('NfcManager.isAvailable(): ${ss.data}'))
                : Flex(
              mainAxisAlignment: MainAxisAlignment.spaceBetween,
              direction: Axis.vertical,
              children: [
                Flexible(
                  flex: 2,
                  child: Container(
                    margin: EdgeInsets.all(4),
                    constraints: BoxConstraints.expand(),
                    decoration: BoxDecoration(border: Border.all()),
                    child: SingleChildScrollView(
                      child: ValueListenableBuilder(
                        valueListenable: result,
                        builder: (context, value, _) =>
                            Text('${value ?? ''}'),
                      ),
                    ),
                  ),
                ),
                Flexible(
                  flex: 3,
                  child: GridView.count(
                    padding: EdgeInsets.all(4),
                    crossAxisCount: 2,
                    childAspectRatio: 4,
                    crossAxisSpacing: 4,
                    mainAxisSpacing: 4,
                    children: [
                      ElevatedButton(
                          child: Text('Tag Read'), onPressed: _tagRead),
                      ElevatedButton(
                          child: Text('Ndef Write'),
                          onPressed: _ndefWrite),
                      ElevatedButton(
                          child: Text('Ndef Write Lock'),
                          onPressed: _ndefWriteLock),
                    ],
                  ),
                ),
              ],
            ),
          ),
        ),
      ),
    );
  }

  void _tagRead() {
    NfcManager.instance.startSession(onDiscovered: (NfcTag tag) async {
      result.value = tag.data;
      Uint8List commoddata1= _getReadHistoryCommandBytes(NfcF.from(tag)!.identifier,10,0);
      Uint8List commoddata2= _getReadHistoryCommandBytes(NfcF.from(tag)!.identifier,10,10);
      print( NfcF.from(tag)?.identifier.length);
      print( NfcF.from(tag));

      List command=[];
      command.addAll(commoddata1);
      // command.addAll(commoddata);
      Uint8List.fromList(command);
      await NfcF.from(tag)?.transceive(data: commoddata1)
         .then((value) {
        print((value.length - 1) / 15);
        print(value);
      });
      await Future.delayed(const Duration(seconds: 1));
      await NfcF.from(tag)?.transceive(data: commoddata2)
          .then((value) {
        print((value.length - 1) / 15);
        print(value);
      });
        NfcManager.instance.stopSession();
    });
  }

  void _ndefWrite() {
    NfcManager.instance.startSession(onDiscovered: (NfcTag tag) async {
      var ndef = Ndef.from(tag);
      if (ndef == null || !ndef.isWritable) {
        result.value = 'Tag is not ndef writable';
        NfcManager.instance.stopSession(errorMessage: result.value);
        return;
      }

      NdefMessage message = NdefMessage([
        NdefRecord.createText('Hello World!'),
        NdefRecord.createUri(Uri.parse('https://flutter.cn')),
        NdefRecord.createMime(
            'text/plain', Uint8List.fromList('Hello'.codeUnits)),
        NdefRecord.createExternal(
            'com.example', 'mytype', Uint8List.fromList('mydata'.codeUnits)),
      ]);

      try {
        await ndef.write(message);
        result.value = 'Success to "Ndef Write"';
        NfcManager.instance.stopSession();
      } catch (e) {
        result.value = e;
        NfcManager.instance.stopSession(errorMessage: result.value.toString());
        return;
      }
    });
  }

  void _ndefWriteLock() {
    NfcManager.instance.startSession(onDiscovered: (NfcTag tag) async {
      var ndef = Ndef.from(tag);
      if (ndef == null) {
        result.value = 'Tag is not ndef';
        NfcManager.instance.stopSession(errorMessage: result.value.toString());
        return;
      }

      try {
        await ndef.writeLock();
        result.value = 'Success to "Ndef Write Lock"';
        NfcManager.instance.stopSession();
      } catch (e) {
        result.value = e;
        NfcManager.instance.stopSession(errorMessage: result.value.toString());
        return;
      }
    });
  }
}

Uint8List _getReadHistoryCommandBytes(Uint8List identifier,int size,int offset) {
  List command=[];
  command.add(0); // data length. change after all byte set.
  command.add(0x06);        // Felica command, Read Without Encryption
  command.addAll(identifier);       // NFC ID (8byte)
  command.add(1);           // service code length (2byte)
  command.add(0x0f);        // low byte of service code for pasmo history (little endian)
  command.add(0x09);        // high byte of service code for pasmo history (little endian)
  command.add(size);        // number of block. (=< 15)
  for (int i = offset; i < offset+size; i++) {
    command.add(0x80);    // ブロックエレメント上位バイト 「Felicaユーザマニュアル抜粋」の4.3項参照
    command.add(i);       // ブロック番号
  }
  int length=command.length;
  command.replaceRange(0, 1, [length]);
  print(command);
  return Uint8List.fromList(command);
}

你可能感兴趣的:(flutter,nfc,suica,pasmo,nfc_manager)