Flutter NFC读写插件ndef的使用

发布于 1周前 作者 htzhanglong 来自 Flutter

Flutter NFC读写插件ndef的使用

ndef 是一个用于解码和编码NDEF记录的Dart库,支持多种类型(按类型名称格式分组),包括:

  • NFC Well-known Records (TNF 1 / urn:nfc:wkt:),包含:

    • 文本 (class T)
    • URI带有知名前缀 (class U)
    • 数字签名 (class Sig)
    • 智能海报 (class Sp),包括子记录:
      • 动作 (class act)
      • 大小 (class s)
      • 类型 (class t)
    • 连接切换 (class Hr/Hs/Hm/Hi/Hc/ac/cr)
  • Media Records (TNF 2, 包含MIME数据),包含:

    • 蓝牙简易配对 (class application/vnd.bluetooth.ep.oob)
    • 蓝牙低能耗 (class application/vnd.bluetooth.le.oob)
  • Absolute URI Records (TNF 3)

  • External Records (TNF 4 / urn:nfc:ext:),包含:

    • Android应用程序记录 (class android.com:pkg)

注意:此库仍在积极开发中,可能会出现破坏性API更改和功能故障。欢迎提交问题和拉取请求,特别是在以下方面:

  • Bug修复
  • 支持新的记录类型

使用示例

编码与解码NDEF记录

import 'package:ndef/ndef.dart' as ndef;

void main() {
  // 编码
  var uriRecord = ndef.UriRecord.fromString("https://github.com/nfcim/ndef");
  var textRecord = ndef.TextRecord(text: "Hello");
  var encodedUriRecord = uriRecord.encode().toHexString(); /// 编码单个记录,并使用Uint8List上的扩展方法
  var encodedAllRecords = ndef.encodeNdefMessage([uriRecord, textRecord]).toHexString(); // 编码多个记录为一条消息

  // 解码
  var encodedTextRecord = "d1010f5402656e48656c6c6f20576f726c6421";
  var decodedRecords = ndef.decodeRawNdefMessage(encodedTextRecord.toBytes());
  assert(decodedRecords.length == 1);
  if (decodedRecords[0] is ndef.TextRecord) {
    assert(decodedRecords[0].text == "Hello");
  } else {
    // 我们不会到这里
  }

  // 数据绑定(通过实现payload作为动态getter/setter)
  var origPayload = uriRecord.payload!;
  print(origPayload.toHexString());
  uriRecord.content = "github.com/nfcim/flutter_nfc_kit";
  print(uriRecord.payload!.toHexString()); // 已更改
  uriRecord.payload = origPayload;
  print(uriRecord.content); // 变回原来

  // 部分解码记录
  var partiallyDecodedUrlRecord = ndef.decodePartialNdefMessage(
      ndef.TypeNameFormat.nfcWellKnown, utf8.encode("U"), origPayload,
      id: Uint8List.fromList([0x1, 0x2]));
}

完整示例代码

import 'dart:convert';
import 'dart:typed_data';

import 'package:ndef/ndef.dart' as ndef;
import 'package:ndef/utilities.dart';

void main() {
  var encodedUrlRecord =
      "91011655046769746875622e636f6d2f6e6663696d2f6e64656651010b55046769746875622e636f6d";
  var urlRecords = [
    ndef.UriRecord.fromString("https://github.com/nfcim/ndef"),
    ndef.UriRecord.fromString("https://github.com")
  ];

  // 解码完整的NDEF消息(记录的连接)
  var decodedUrlRecords = ndef.decodeRawNdefMessage(encodedUrlRecord.toBytes());

  assert(urlRecords.length == decodedUrlRecords.length);

  for (int i = 0; i < urlRecords.length; i++) {
    var raw = urlRecords[i];
    var decoded = decodedUrlRecords[i];
    assert(decoded is ndef.UriRecord);
    assert((decoded as ndef.UriRecord).uri == raw.uri);
    print((decoded as ndef.UriRecord).toString());
  }

  // 修改记录通过数据绑定
  var origPayload = urlRecords[0].payload!;
  print('===================');
  print('original payload: ${origPayload.toHexString()}');
  print('original uri: ${urlRecords[0].uri}');

  // 更改URI
  print('===================');
  urlRecords[0].content =
      'github.com/nfcim/flutter_nfc_kit'; // 这也是我们很棒的库,快来看看!
  print(
      'payload after change content: ${urlRecords[0].payload!.toHexString()}'); // 在调用时编码
  print('uri after change content: ${urlRecords[0].uri}');

  // 通过使用payload恢复更改
  print('===================');
  urlRecords[0].payload = origPayload; // 在调用时解码
  print('payload after changed back: ${urlRecords[0].payload!.toHexString()}');
  print('uri after changed back: ${urlRecords[0].uri}');

  // 再次编码为消息(也规范MB & MF字段)
  var encodedAgain = ndef.encodeNdefMessage(urlRecords);
  assert(encodedAgain.toHexString() == encodedUrlRecord);
  print('encoded single record: ${urlRecords[0].encode().toHexString()}');

  // 也可以分别提供id、type和payload进行解码(通常来自手机API)
  print('===================');
  var partiallyDecodedUrlRecord = ndef.decodePartialNdefMessage(
      ndef.TypeNameFormat.nfcWellKnown, utf8.encode("U"), origPayload,
      id: Uint8List.fromList([0x1, 0x2]));
  assert(partiallyDecodedUrlRecord is ndef.UriRecord);
  print(
      'partially decoded record: ${partiallyDecodedUrlRecord as ndef.UriRecord}');
}

要了解更多详细信息,请参阅 官方文档完整示例代码

希望这能帮助您更好地理解和使用ndef库。如果您有任何问题或需要进一步的帮助,请随时提问!


更多关于Flutter NFC读写插件ndef的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter NFC读写插件ndef的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,关于在Flutter中使用NFC读写插件进行NDEF(NFC Data Exchange Format)操作,这里是一个示例代码案例,展示如何使用flutter_nfc_reader插件来实现这一功能。请注意,这个插件主要用于读取NFC标签,而写入功能可能需要使用其他插件或者平台通道来实现,因为Flutter本身对NFC写入的支持有限。

首先,确保在pubspec.yaml文件中添加依赖:

dependencies:
  flutter:
    sdk: flutter
  flutter_nfc_reader: ^x.y.z  # 请替换为最新版本号

然后运行flutter pub get来安装依赖。

接下来,在android/app/src/main/AndroidManifest.xml文件中添加NFC权限和特性声明:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.yourapp">

    <uses-permission android:name="android.permission.NFC" />

    <application
        ...>
        <uses-library android:name="android.nfc" />
        <intent-filter>
            <action android:name="android.nfc.action.TAG_DISCOVERED" />
            <category android:name="android.intent.category.DEFAULT" />
        </intent-filter>
        <meta-data
            android:name="android.nfc.action.TECH_LIST"
            android:resource="@xml/nfc_tech_filter" />
    </application>
</manifest>

还需要在res/xml/目录下创建一个名为nfc_tech_filter.xml的文件,内容如下:

<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
    <tech-list>
        <tech>android.nfc.tech.NfcA</tech>
        <tech>android.nfc.tech.NfcB</tech>
        <tech>android.nfc.tech.NfcF</tech>
        <tech>android.nfc.tech.NfcV</tech>
        <tech>android.nfc.tech.IsoDep</tech>
        <tech>android.nfc.tech.MifareClassic</tech>
        <tech>android.nfc.tech.MifareUltralight</tech>
        <tech>android.nfc.tech.Ndef</tech>
        <tech>android.nfc.tech.NdefFormatable</tech>
    </tech-list>
</resources>

现在,在Dart代码中实现NFC读取功能:

import 'package:flutter/material.dart';
import 'package:flutter_nfc_reader/flutter_nfc_reader.dart';

void main() => runApp(MyApp());

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

class _MyAppState extends State<MyApp> {
  NfcManager? _nfcManager;

  @override
  void initState() {
    super.initState();
    _nfcManager = NfcManager.instance;
    _nfcManager!.startSession().then((_) {
      _nfcManager!.onDiscovered!.listen((NfcTag tag) {
        // 当NFC标签被发现时触发
        print("NFC Tag Discovered: ${tag.id}");

        // 尝试读取NDEF消息
        tag.ndef?.readNdefMessages().then((ndefMessages) {
          ndefMessages.forEach((message) {
            print("NDEF Message: ${message.toJson()}");
          });
        }).catchError((error) {
          print("Error reading NDEF: $error");
        });
      });
    }).catchError((error) {
      print("Error starting NFC session: $error");
    });
  }

  @override
  void dispose() {
    _nfcManager?.endSession();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Flutter NFC Reader'),
        ),
        body: Center(
          child: Text('Place your NFC tag near the device to read it.'),
        ),
      ),
    );
  }
}

请注意,这个示例代码只展示了如何读取NFC标签上的NDEF消息。对于写入NDEF消息,由于Flutter社区对NFC写入的直接支持有限,你可能需要使用平台通道与原生Android或iOS代码进行交互来实现这一功能。这通常涉及到编写自定义的原生插件或者利用现有的原生NFC写入库。

此外,确保在测试应用时,设备已经启用了NFC功能,并且应用具有相应的权限。

回到顶部