Flutter应用调用NFC标签transceive方法触发NoSuchMethodError问题
问题:使用nfc_manager读取NFC标签时出现NoSuchMethodError错误
读取NFC标签时触发如下错误:
Error reading data: NoSuchMethodError: Class '_Map<Object?, Object?>' has no instance method 'transceive'. Receiver: _Map len:5 Tried calling: transceive(_Uint8List)
相关代码如下:
nfc_service.dart
import 'dart:typed_data'; import 'dart:convert'; import 'package:nfc_manager/nfc_manager.dart'; import 'package:nfc_manager/platform_tags.dart'; // Ensure this import is included class NfcService { Future<String> readData(NfcTag tag) async { try { // Print the contents of tag.data for debugging print('!!!!!!!!!!!!! TAG DATA: ${tag.data}'); // Extract NFC-A data from the tag final nfcaData = tag.data['nfca']; // Print the type and contents of nfcaData for debugging print('QQQQQQ nfcaData type: ${nfcaData.runtimeType}'); print('MMMMMM nfcaData contents: $nfcaData'); if (nfcaData != null) { // Create NfcA instance from the tag final nfca = NfcA.from(tag); // Check if nfca is not null if (nfca != null) { // Prepare the command to read data from the tag final command = Uint8List.fromList( [0x3A, 0x00, 0x01]); // Example command for reading // Call transceive method with the command final result = await nfca.transceive(data: command); // Print raw result for debugging print('Raw result (Uint8List): $result'); // Attempt to decode the result using UTF-8 String resultText; try { resultText = utf8.decode(result, allowMalformed: true); } catch (e) { resultText = 'Failed to decode text: ${result.toString()}'; // Show raw result if decoding fails } return resultText; } else { return 'NfcA instance could not be created'; } } else { return 'Unsupported NFC tag type or no NFC-A data'; } } catch (e, s) { print('SSSSSS Stack trace:\n$s'); return 'Error reading data: $e'; } } }
scan_page.dart
import 'package:flutter/material.dart'; import 'package:nfc_manager/nfc_manager.dart'; import 'package:soremar_inventory/services/nfc_service.dart'; class ScanTagPage extends StatefulWidget { const ScanTagPage({super.key}); @override ScanTagPageState createState() => ScanTagPageState(); } class ScanTagPageState extends State<ScanTagPage> { final NfcService _nfcService = NfcService(); bool _isScanning = false; String _scanMessage = 'Placez votre téléphone près de l\'étiquette NFC pour scanner.'; @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Controller un produit'), centerTitle: true, backgroundColor: const Color.fromARGB(255, 42, 48, 161), leading: IconButton( icon: const Icon(Icons.arrow_back), onPressed: () { Navigator.of(context).pop(); }, ), ), body: Stack( children: [ // Background GIF Positioned.fill( child: Image.asset( 'assets/images/scan.gif', // Ensure the path is correct fit: BoxFit.cover, ), ), // Foreground content Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ ElevatedButton( onPressed: _startScan, child: const Text('Cliquez ici pour scanner une tag NFC'), ), if (_isScanning) const CircularProgressIndicator(), Text(_scanMessage), ], ), ), ], ), ); } void _startScan() async { if (_isScanning) return; // Prevent starting multiple scans setState(() { _isScanning = true; _scanMessage = 'Placez votre téléphone près de l\'étiquette NFC pour scanner.'; }); try { await NfcManager.instance.startSession(onDiscovered: (NfcTag tag) async { final data = await _nfcService.readData(tag); setState(() { _scanMessage = 'Data: $data'; }); _stopScan(); // Stop scan after reading data }).catchError((e) { setState(() { _scanMessage = 'Error: $e'; }); _stopScan(); // Ensure the session is stopped on error }); } catch (e) { setState(() { _scanMessage = 'Error: $e'; }); _stopScan(); // Ensure the session is stopped on error } } void _stopScan() { NfcManager.instance.stopSession().catchError((e) { print('Error stopping NFC session: $e'); }); setState(() { _isScanning = false; }); } }
问题分析
错误核心是代码尝试调用_Map对象的transceive方法,但该方法仅存在于NfcA实例中。出现此问题的可能原因:
NfcA.from(tag)未正确返回NfcA实例,可能是标签不支持NfcA协议,或依赖包版本存在兼容性问题- 直接依赖
tag.data['nfca']的存在性,未通过官方API验证标签协议支持性 - NFC指令不匹配目标标签的通信规范,导致底层调用异常
解决方案
1. 严格验证标签协议支持性
使用NfcA.isSupported(tag)替代直接判断tag.data['nfca'],确保标签确实支持NfcA协议:
// 替换原nfcaData判断逻辑 if (NfcA.isSupported(tag)) { final nfca = NfcA.from(tag); if (nfca != null) { // 执行后续读取操作 } else { return '无法初始化NfcA实例'; } } else { return '该NFC标签不支持NfcA协议'; }
2. 更新nfc_manager依赖到最新稳定版
旧版本可能存在NfcA.from(tag)返回值异常问题,在pubspec.yaml中更新依赖:
dependencies: nfc_manager: ^最新稳定版本号
执行flutter pub get完成更新。
3. 修正NFC指令适配目标标签
当前使用的[0x3A, 0x00, 0x01]可能不符合目标标签的通信规范,建议先执行标签选中指令(如ISO7816标准的选择指令),再执行读取操作:
// 先发送标签选中指令 final selectCommand = Uint8List.fromList([0x00, 0xA4, 0x04, 0x00, 0x00]); await nfca.transceive(data: selectCommand); // 再发送读取指令(根据标签文档调整) final readCommand = Uint8List.fromList([0x3A, 0x00, 0x01]); final result = await nfca.transceive(data: readCommand);
4. 完善平台权限配置
确保Android和iOS的NFC权限配置正确:
- Android:在
AndroidManifest.xml中添加<uses-permission android:name="android.permission.NFC" /> <uses-feature android:name="android.hardware.nfc" android:required="true" /> - iOS:在
Info.plist中添加<key>NFCReaderUsageDescription</key> <string>需要访问NFC功能以读取标签数据</string> <key>com.apple.developer.nfc.readersession.iso7816.select-identifiers</key> <array> <string>A0000002471001</string> <!-- 根据标签AID调整 --> </array>
内容的提问来源于stack exchange,提问作者Mohammed Elyaakoubi
相关产品推荐
相关产品推荐

