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); }
问题原因与解决方案
核心问题点
- 键名拼写错误:标签响应中是
records(复数),错误代码里写成record(单数),导致数据读取失败引发异常,且未正确终止会话。 - NDEF Payload格式未处理:NDEF文本类型的payload包含控制字节(状态位+语言码),直接转换会包含无效字符,且需跳过这些字节才能提取有效文本。
- 未主动终止会话:错误代码未调用
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
相关产品推荐
相关产品推荐

