【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<StatefulWidget> createState() => MyAppState();
}

class MyAppState extends State<MyApp> {
  ValueNotifier<dynamic> result = ValueNotifier(null);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text('NfcManager Plugin Example')),
        body: SafeArea(
          child: FutureBuilder<bool>(
            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<dynamic>(
                        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<int> 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<int> 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);
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,以下是一个使用 Flutterflutter_blue 包读取 BLE 设备的代码示例: 首先,需要在 pubspec.yaml 文件中添加 flutter_blue 依赖: ```yaml dependencies: flutter: sdk: flutter flutter_blue: ^0.7.3 ``` 然后在 Dart 文件中导入 flutter_blue 包: ```dart import 'package:flutter_blue/flutter_blue.dart'; ``` 接下来,我们可以创建一个 StatefulWdiget 来管理连接状态和搜索结果: ```dart class BleDeviceScreen extends StatefulWidget { @override _BleDeviceScreenState createState() => _BleDeviceScreenState(); } class _BleDeviceScreenState extends State<BleDeviceScreen> { FlutterBlue flutterBlue = FlutterBlue.instance; StreamSubscription<ScanResult> scanSubscription; BluetoothDevice connectedDevice; List<BluetoothDevice> devicesList = []; void startScan() { scanSubscription = flutterBlue.scan().listen((scanResult) { if (!devicesList.contains(scanResult.device)) { setState(() { devicesList.add(scanResult.device); }); } }); } void stopScan() { scanSubscription?.cancel(); } void connectToDevice(BluetoothDevice device) async { await device.connect(); setState(() { connectedDevice = device; }); } void disconnectFromDevice() async { await connectedDevice.disconnect(); setState(() { connectedDevice = null; }); } @override void initState() { super.initState(); startScan(); } @override void dispose() { stopScan(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('BLE Device'), ), body: Column( children: [ Expanded( child: ListView.builder( itemCount: devicesList.length, itemBuilder: (BuildContext context, int index) { BluetoothDevice device = devicesList[index]; return ListTile( title: Text(device.name), subtitle: Text(device.id.toString()), trailing: connectedDevice == device ? FlatButton( child: Text('Disconnect'), onPressed: disconnectFromDevice, ) : FlatButton( child: Text('Connect'), onPressed: () => connectToDevice(device), ), ); }, ), ), connectedDevice != null ? StreamBuilder<List<int>>( stream: connectedDevice.characteristic( Guid("00002a37-0000-1000-8000-00805f9b34fb")), builder: (BuildContext context, AsyncSnapshot<List<int>> snapshot) { if (snapshot.hasData) { List<int> value = snapshot.data; String result = String.fromCharCodes(value); return Text('Result: $result'); } else { return Text('No result yet'); } }, ) : Container(), ], ), ); } } ``` 在 initState 方法中,我们调用 startScan 方法开始扫描周围的 BLE 设备,并通过 StreamSubscription 监听扫描结果。每当扫描到一个新设备时,将其添加到 devicesList 中,并使用 setState 更新 UI。 在 ListView 中,我们将扫描到的设备显示为列表项,并提供连接和断开连接的按钮。如果设备已连接,则显示断开连接按钮。我们还为每个设备添加了一个 onTap 方法,以便在点击设备时连接到该设备。 如果已连接到设备,则会在页面底部显示一个 StreamBuilder,用于从设备读取数据。我们使用 characteristic 方法获取一个 characteristic,并使用 StreamBuilder 监听该 characteristic 的值。如果有新的值,则将其显示在页面上。 最后,我们在 dispose 方法中停止扫描并取消 StreamSubscription。 这就是一个简单的使用 Flutterflutter_blue 包读取 BLE 设备的示例。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值