如何用Flutter实现SUNMI V2S通过NFC读取安卓/iOS钱包凭证
实现SUNMI V2S Flutter读取Google Wallet/Apple Pass NFC数据
一、前置配置(SUNMI V2S + Flutter)
- 安卓权限配置:在项目
android/app/src/main/AndroidManifest.xml中添加以下权限和配置,确保APP能访问NFC并捕获前台NFC事件:<!-- NFC基础权限 --> <uses-permission android:name="android.permission.NFC" /> <uses-feature android:name="android.hardware.nfc" android:required="true" /> <!-- 前台NFC调度权限 --> <uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> <!-- 在主Activity中添加NFC intent过滤 --> <activity android:name=".MainActivity" ...> <intent-filter> <action android:name="android.nfc.action.NDEF_DISCOVERED" /> <category android:name="android.intent.category.DEFAULT" /> <!-- Google Wallet Pass MIME类型 --> <data android:mimeType="application/vnd.google.pass" /> </intent-filter> <intent-filter> <action android:name="android.nfc.action.TECH_DISCOVERED" /> </intent-filter> <meta-data android:name="android.nfc.action.TECH_DISCOVERED" android:resource="@xml/nfc_tech_filter" /> </activity> - 创建NFC技术过滤文件:在
android/app/src/main/res/xml下新建nfc_tech_filter.xml,适配SUNMI支持的NFC标准:<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <tech-list> <tech>android.nfc.tech.Ndef</tech> <tech>android.nfc.tech.NfcA</tech> <tech>android.nfc.tech.MifareClassic</tech> <tech>android.nfc.tech.Felica</tech> </tech-list> </resources>
二、核心依赖与代码实现
在pubspec.yaml中添加nfc_manager依赖:
dependencies: flutter: sdk: flutter nfc_manager: ^3.3.0
完整读取逻辑代码
import 'package:flutter/material.dart'; import 'package:nfc_manager/nfc_manager.dart'; class NfcPassReader extends StatefulWidget { const NfcPassReader({super.key}); @override State<NfcPassReader> createState() => _NfcPassReaderState(); } class _NfcPassReaderState extends State<NfcPassReader> { bool _nfcAvailable = false; bool _isScanning = false; String _status = ''; @override void initState() { super.initState(); _checkNfcStatus(); } // 检查NFC是否可用 Future<void> _checkNfcStatus() async { _nfcAvailable = await NfcManager.instance.isAvailable(); setState(() {}); } // 启动NFC扫描 Future<void> _startScan() async { if (!_nfcAvailable) { setState(() => _status = '设备NFC不可用'); return; } setState(() { _isScanning = true; _status = '请将手机钱包贴近NFC区域...'; }); NfcManager.instance.startSession( onDiscovered: (NfcTag tag) async { try { // 读取NDEF格式数据(Google/Apple Pass均基于NDEF) final ndef = Ndef.from(tag); if (ndef == null) { setState(() => _status = '标签不支持NDEF格式'); NfcManager.instance.stopSession(); return; } final message = ndef.cachedMessage; if (message == null) { setState(() => _status = '标签无有效数据'); NfcManager.instance.stopSession(); return; } // 遍历记录,匹配Google/Apple Pass for (final record in message.records) { // 处理Google Wallet Pass if (record.typeNameFormat == NdefTypeNameFormat.media && String.fromCharCodes(record.type) == 'application/vnd.google.pass') { final passData = String.fromCharCodes(record.payload); setState(() => _status = '读取Google Pass成功:\n$passData'); _activateTicket(passData); break; } // 处理Apple Pass(通常为URI格式记录) if (record.typeNameFormat == NdefTypeNameFormat.nfcWellKnown && String.fromCharCodes(record.type) == 'U') { final passUri = Uri.parse(String.fromCharCodes(record.payload)); setState(() => _status = '读取Apple Pass成功:\n$passUri'); _activateTicket(passUri.toString()); break; } } } catch (e) { setState(() => _status = '读取失败: ${e.toString()}'); } finally { NfcManager.instance.stopSession(); setState(() => _isScanning = false); } }, options: const NfcSessionOptions( android: AndroidNfcSessionOptions( foregroundMode: true, readerMode: AndroidNfcReaderMode.normal, ), ), ); } // 票证激活逻辑(替换为你的业务接口调用) void _activateTicket(String passInfo) { // 示例:调用后端接口完成激活,或触发SUNMI打印机打印凭证 setState(() { _status += '\n\n票证激活成功!'; }); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('NFC票证读取器')), body: Center( child: Padding( padding: const EdgeInsets.all(16), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Text(_status, textAlign: TextAlign.center, style: const TextStyle(fontSize: 16)), const SizedBox(height: 24), ElevatedButton( onPressed: _isScanning ? null : _startScan, child: Text(_isScanning ? '扫描中...' : '开始扫描'), ), if (!_nfcAvailable) const Padding( padding: EdgeInsets.only(top: 16), child: Text('当前设备不支持NFC', style: TextStyle(color: Colors.red)), ), ], ), ), ), ); } }
三、SUNMI V2S适配与测试要点
- 开启设备NFC:进入SUNMI系统设置->NFC,确保NFC功能已启用,并允许当前APP的NFC访问权限
- 测试场景要求:
- Google Wallet:打开Wallet应用并显示目标Pass,保持屏幕常亮后贴近SUNMI的NFC区域(通常在设备顶部)
- Apple设备:解锁手机,打开Wallet应用并显示目标Pass,贴近SUNMI NFC区域
- 模式调整:若无法捕获Apple Pass数据,可尝试将
AndroidNfcReaderMode改为cardEmulation,适配Apple使用的Felica标准
四、常见问题排查
- 读取无响应:检查AndroidManifest权限是否配置完整,确保APP处于前台运行状态
- 解析失败:打印完整的NDEF记录内容,确认Google/Apple Pass实际发送的记录类型,调整代码中的匹配逻辑
- Pass无NFC数据:确认创建Google/Apple Pass时已配置NFC字段(Google Pass需添加
nfc节点,Apple Pass需在pass.json中配置nfc字段)
内容的提问来源于stack exchange,提问作者f-accu
相关产品推荐
相关产品推荐

