You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter中解析NFC标签响应并转换为可读字符串的问题

Flutter NFC标签文本解析阻塞问题解决

问题说明

开发Flutter应用时,使用nfc_manager插件读取NFC标签,需要将标签返回的payload转换为可读字符串,但尝试解析时出现NFC读取阻塞的情况。

标签响应数据

{
  "iso15693": {
    "identifier": [224, 4, 1, 8, 62, 149, 102, 100],
    "icManufacturerCode": 4,
    "icSerialNumber": [1, 8, 62, 149, 102, 100]
  },
  "ndef": {
    "cachedMessage": {
      "records": [
        {
          "payload": [2, 101, 110, 65, 100, 97, 109],
          "typeNameFormat": 1,
          "identifier": [],
          "type": [84]
        }
      ]
    }
  },
  "isWritable": true,
  "maxSize": 312
}

现有实现代码

class NFC_scanner extends StatefulWidget {
  const NFC_scanner({Key? key}) : super(key: key);

  @override
  State<StatefulWidget> createState() => MyNFCState();
}

class MyNFCState extends State<NFC_scanner> {
  ValueNotifier<dynamic> result = ValueNotifier(null);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: Scaffold(
        appBar: AppBar(
          title: const Text('NfcManager Plugin Example'),
          backgroundColor: Colors.transparent,
          foregroundColor: Colors.lightGreen,
          elevation: 0.0,
        ),
        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: const EdgeInsets.all(4),
                          constraints: const BoxConstraints.expand(),
                          decoration: const BoxDecoration(shape: BoxShape.circle),
                          child: SingleChildScrollView(
                            child: ValueListenableBuilder<dynamic>(
                              valueListenable: result,
                              builder: (context, value, _) => Container(
                                height: 200,
                                width: 200,
                                child: Text('${value ?? ''}'),
                              ),
                            ),
                          ),
                        ),
                      ),
                      Container(
                        height: 300,
                        width: 300,
                        child: Lottie.network('https://lottie.host/124ecd28-8486-478f-a479-4fa22242dda5/ycBN8Sr5aP.json'),
                      ),
                      const Text('Please keep your device near your phone'),
                      const SizedBox(height: 100),
                      FloatingActionButton(
                        onPressed: _tagRead,
                        backgroundColor: Colors.lightGreen,
                        child: const Icon(Icons.zoom_in),
                      )
                    ],
                  ),
          ),
        ),
      ),
    );
  }

  void _tagRead() async {
    showDialog(
      context: context,
      builder: (context) {
        return const AlertDialog(content: Text('You can tap the tag now !'));
      },
    );
    try {
      await NfcManager.instance.startSession(onDiscovered: (NfcTag tag) async {
        result.value = tag.data;
        print('tag.data: ${tag.data}');
        NfcManager.instance.stopSession();
      });
    } catch (e) {
      result.value = e.toString();
    }
  }
}

导致阻塞的错误解析代码

NfcManager.instance.startSession(onDiscovered : (NfcTag tag) async{
var payload = tag.data["ndef"]["cachedMessage"]["record"][0]["payload"];
// now convert that payload into string
var stringPayload = String.fromCharCodes(payload);
}

问题原因与解决方案

核心问题点

  1. 键名拼写错误:标签响应中是records(复数),错误代码里写成record(单数),导致数据读取失败引发异常,且未正确终止会话。
  2. NDEF Payload格式未处理:NDEF文本类型的payload包含控制字节(状态位+语言码),直接转换会包含无效字符,且需跳过这些字节才能提取有效文本。
  3. 未主动终止会话:错误代码未调用stopSession(),导致NFC会话持续激活,引发读取阻塞。

修正后的完整解析代码

替换原有_tagRead方法:

void _tagRead() async {
  showDialog(
    context: context,
    builder: (context) {
      return const AlertDialog(content: Text('You can tap the tag now !'));
    },
  );
  try {
    await NfcManager.instance.startSession(onDiscovered: (NfcTag tag) async {
      String? readableText;
      // 检查并解析NDEF数据
      if (tag.data.containsKey('ndef') && tag.data['ndef']['cachedMessage'] != null) {
        var records = tag.data['ndef']['cachedMessage']['records'];
        if (records.isNotEmpty) {
          var payload = records[0]['payload'];
          if (payload is List<int> && payload.length > 2) {
            // 从状态字节提取语言码长度(低4位)
            int languageCodeLength = payload[0] & 0x0F;
            // 跳过状态字节+语言码,提取有效文本
            readableText = String.fromCharCodes(payload.skip(1 + languageCodeLength));
          }
        }
      }
      
      // 更新显示结果,关闭弹窗并终止NFC会话
      result.value = readableText ?? '无法解析标签内容';
      Navigator.pop(context);
      await NfcManager.instance.stopSession();
    });
  } catch (e) {
    result.value = '读取错误: ${e.toString()}';
    Navigator.pop(context);
  }
}

修正说明

  • 修复了键名拼写错误,正确读取records数组
  • 按照NDEF文本格式规范解析payload,提取出有效可读文本(你的标签示例中最终会得到Adam)
  • 确保解析完成后终止NFC会话,彻底解决阻塞问题
  • 读取完成后自动关闭提示弹窗,优化用户体验

内容的提问来源于stack exchange,提问作者Aphtn

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 14:06:10