最新,项目对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
基于上面的文章,我得到了一下两个重要的结论:
下面就是我写的一个建单例子。大家关注_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);
}