Flutter NFC主机卡模拟插件flutter_nfc_hce的使用

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

Flutter NFC主机卡模拟插件flutter_nfc_hce的使用

1. 介绍

flutter_nfc_hce 插件项目是在探索跨平台之间使用NFC交换数据的方法过程中发起的。该插件旨在利用Flutter的功能,基于Qifan Yang的NFCAndroid项目中的com.qifan.nfcbank.cardEmulation.KHostApduService实现(参考:NFCAndroid)。关于Android 13版本中与NFC HCE操作相关的问题,参考了MichaelsPlayground/NfcHceNdefEmulator进行了修改。

// KHostApduService.kt
private val READ_CAPABILITY_CONTAINER_RESPONSE = byteArrayOf(
0x00.toByte(), 0x0F.toByte(), // CCLEN 长度为15字节
0x20.toByte(), // 映射版本2.0
0x00.toByte(), 0x3B.toByte(), // MLe 最大值60
0x00.toByte(), 0x34.toByte(), // MLc 最大值52
0x04.toByte(), // NDEF文件控制TLV的T字段
0x06.toByte(), // NDEF文件控制TLV的L字段
0xE1.toByte(), 0x04.toByte(), // NDEF文件标识符
0x00.toByte(), 0xFF.toByte(), // 最大NDEF文件大小为65534字节
0x00.toByte(), // 无需任何安全措施即可读取
0xFF.toByte(), // 无需任何安全措施即可写入
0x90.toByte(), 0x00.toByte(), // A_OKAY
)

NFC HCE操作支持从Android 11到13版本,在当前初始项目中,支持的AID固定为D2760000850101。对于NFC HCE读取器,可以参考使用flutter_manager创建的示例(flutter_nfc_hce_reader)。

2. 截图

主界面 Android NFC HCE
Main Android NFC HCE

3. 设置

Android设置
  1. AndroidManifest.xml中添加权限:

    <uses-permission android:name="android.permission.NFC" />
    <uses-feature android:name="android.hardware.nfc" android:required="true" />
    <uses-feature android:name="android.hardware.nfc.hce" android:required="true" />
    <uses-permission android:name="android.permission.VIBRATE" />
    
  2. AndroidManifest.xml中注册服务:

    <service android:name="com.novice.flutter_nfc_hce.KHostApduService"
             android:exported="true"
             android:enabled="true"
             android:permission="android.permission.BIND_NFC_SERVICE">
        <intent-filter>
            <action android:name="android.nfc.cardemulation.action.HOST_APDU_SERVICE"/>
            <category android:name="android.intent.category.DEFAULT"/>
        </intent-filter>
        <meta-data android:name="android.nfc.cardemulation.host_apdu_service"
                   android:resource="@xml/apduservice"/>
    </service>
    
  3. res/xml目录下添加apduservice.xml

    <?xml version="1.0" encoding="utf-8"?>
    <host-apdu-service xmlns:android="http://schemas.android.com/apk/res/android"
                       android:description="@string/servicedesc" 
                       android:requireDeviceScreenOn="false" 
                       android:requireDeviceUnlock="false">
        <aid-group android:description="@string/aiddescription"  android:category="other" >
            <aid-filter android:name="D2760000850101"/>
        </aid-group>
    </host-apdu-service>
    
  4. res/values目录下添加strings.xml

    <resources>
        <string name="servicedesc">服务描述</string>
        <string name="aiddescription">AID描述</string>
    </resources>
    

4. 使用示例

以下是一个完整的示例代码,展示了如何使用flutter_nfc_hce插件:

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

void main() {
  runApp(const MyApp());
}

class MyApp extends StatefulWidget {
  const MyApp({super.key});

  [@override](/user/override)
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  final _flutterNfcHcePlugin = FlutterNfcHce();
  bool _showNFCScanDialog = false;
  var platformVersion;
  bool? isNfcHceSupported;
  bool? isSecureNfcEnabled;
  bool? isNfcEnabled;

  void _getInfo() async {
    platformVersion = await _flutterNfcHcePlugin.getPlatformVersion();
    isNfcHceSupported = await _flutterNfcHcePlugin.isNfcHceSupported();
    isSecureNfcEnabled = await _flutterNfcHcePlugin.isSecureNfcEnabled();
    isNfcEnabled = await _flutterNfcHcePlugin.isNfcEnabled();
  }

  void _onScanButtonPressed() async {
    _getInfo();

    var content = 'flutter_nfc_hce';
    var result = await _flutterNfcHcePlugin.startNfcHce(content, persistMessage: true);

    print('---------------------------------->$result');

    setState(() {
      _showNFCScanDialog = true;
    });
  }

  void _onCloseButtonPressed() async {
    await _flutterNfcHcePlugin.stopNfcHce();

    setState(() {
      _showNFCScanDialog = false;
    });
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Plugin Nfc Hce example app'),
        ),
        body: Container(
          child: Stack(
            children: [
              // 背景Widget
              Container(
                color: Colors.transparent,
                child: Center(
                  child: Column(
                    children: [
                      Text('platformVersion: ${platformVersion ?? ""}'),
                      SizedBox(height: 5),
                      Text('isSupportNfcHceFeature: ${isNfcHceSupported ?? ""}'),
                      SizedBox(height: 5),
                      Text('isSupportSecureNfcSupported: ${isSecureNfcEnabled ?? ""}'),
                      SizedBox(height: 5),
                      Text('isNfcEnagle: ${isNfcEnabled ?? ""}'),
                    ],
                  ),
                ),
              ),

              // NFC扫描对话框
              if (_showNFCScanDialog)
                GestureDetector(
                  onTap: _onCloseButtonPressed,
                  child: Container(
                    color: Colors.black54,
                    alignment: Alignment.center,
                    child: Column(
                      mainAxisAlignment: MainAxisAlignment.center,
                      children: [
                        Image.asset('assets/nfc_tag.png', width: 100, height: 100),
                        SizedBox(height: 16),
                        Text(
                          'Start Nfc Hce',
                          style: TextStyle(color: Colors.white, fontSize: 18),
                        ),
                      ],
                    ),
                  ),
                ),
            ],
          ),
        ),
        floatingActionButton: FloatingActionButton(
          onPressed: _onScanButtonPressed,
          child: Icon(Icons.nfc),
        ),
      ),
    );
  }
}

更多关于Flutter NFC主机卡模拟插件flutter_nfc_hce的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter NFC主机卡模拟插件flutter_nfc_hce的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,下面是一个关于如何在Flutter应用中使用flutter_nfc_hce插件来实现NFC主机卡模拟的示例代码。这个插件允许你的设备在支持NFC的Android设备上模拟一个NFC卡。

首先,你需要在你的pubspec.yaml文件中添加flutter_nfc_hce依赖:

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

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

接下来,你需要在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
        ...>
        <service
            android:name=".MyNfcHceService"
            android:exported="true"
            android:permission="android.permission.BIND_NFC_SERVICE">
            <intent-filter>
                <action android:name="android.nfc.cardemulation.action.HOST_APDU_SERVICE" />
            </intent-filter>
            <meta-data
                android:name="android.nfc.cardemulation.host_apdu_service"
                android:resource="@xml/apdu_service" />
        </service>
    </application>
</manifest>

你还需要在res/xml目录下创建一个名为apdu_service.xml的文件,用于定义你的APDU服务:

<?xml version="1.0" encoding="utf-8"?>
<host-apdu-service xmlns:android="http://schemas.android.com/apk/res/android"
    android:apduServiceDescriptor="@string/apdu_service_descriptor"
    android:requireDeviceUnlock="false">
    <aid-group
        android:category="payment"
        android:description="@string/aid_group_description"
        android:priority="0">
        <aid android:name="F28012040007A0000000871002" />
    </aid-group>
</host-apdu-service>

然后,在res/values/strings.xml中添加相应的字符串资源:

<resources>
    <string name="apdu_service_descriptor">"com.example.yourapp.MyNfcHceService"</string>
    <string name="aid_group_description">"My NFC AID Group"</string>
</resources>

接下来,创建一个服务类MyNfcHceService来处理APDU命令:

import 'dart:typed_data';
import 'package:flutter/services.dart';
import 'package:flutter_nfc_hce/flutter_nfc_hce.dart';

class MyNfcHceService extends HostApduService {
  @override
  Future<Uint8List> processCommandApdu(Uint8List commandApdu) async {
    // 这里处理接收到的APDU命令
    // 例如,简单地回显接收到的命令
    return commandApdu;
  }

  @override
  Future<Uint8List> processChannelSelect(int aidLength, Uint8List aid) async {
    // 处理SELECT命令
    return Uint8List.fromList([0x90, 0x00]); // 状态字:成功
  }

  @override
  Future<void> onDeactivated() async {
    // 当卡被去激活时调用
  }
}

注意:由于Dart和Flutter的限制,实际上你需要在原生Android代码(Kotlin或Java)中实现MyNfcHceService类。但上面的代码展示了在Dart中你期望实现的功能。

在Android原生代码中(例如MyNfcHceService.kt),你可能需要这样实现:

import android.nfc.cardemulation.HostApduService
import android.nfc.tech.IsoDep
import androidx.annotation.NonNull
import java.nio.ByteBuffer
import java.nio.ByteOrder

class MyNfcHceService : HostApduService() {

    override fun onProcessCommandApdu(
        @NonNull commandApdu: ByteArray?,
        @NonNull extras: Bundle?
    ): ByteArray {
        // 处理APDU命令
        return commandApdu ?: byteArrayOf(0x90.toByte(), 0x00.toByte())
    }

    override fun onSelectApdu(aid: ByteArray?): ByteArray {
        // 处理SELECT命令
        return byteArrayOf(0x90.toByte(), 0x00.toByte())
    }

    override fun onDeactivated(reason: Int) {
        // 当卡被去激活时调用
    }
}

最后,在你的Flutter应用中启动和配置NFC主机卡模拟(注意:这部分操作通常也需要原生代码支持,因为Flutter本身对底层NFC操作的支持有限):

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

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Flutter NFC HCE Demo'),
        ),
        body: Center(
          child: Text('NFC HCE Service is running in the background.'),
        ),
      ),
    );
  }
}

请注意,由于Flutter对NFC的直接操作有限,大部分NFC HCE相关的配置和处理需要在原生Android代码中进行。上面的示例展示了如何在Flutter中集成和使用flutter_nfc_hce插件,但实际的NFC HCE服务实现需要在原生Android代码中完成。

希望这能帮助你开始使用flutter_nfc_hce插件进行NFC主机卡模拟的开发!

回到顶部