Flutter越南地区功能插件cccd_vietnam的使用

Flutter越南地区功能插件cccd_vietnam的使用

本教程将介绍如何在Flutter项目中使用cccd_vietnam插件来读取越南地区的电子护照数据。该插件基于dmrtd库实现,支持ICAO标准。

关键特性

  • 支持PACE和BAC会话密钥建立协议
  • 可以读取所有基本文件(例如:EF.DG1, EF.DG2, EF.DG11, EF.DG12, EF.DG15等)
  • 支持主动认证(Active Authentication)
  • 基本实现了ICC ISO7816-4智能卡标准
  • 实现了ISO 9797算法3 MAC和填充方案

库结构

  • dmrtd.dart: 公共护照API
  • extensions.dart: 库的Dart扩展
  • internal.dart: 库的内部组件,如MrtdApi、ICC和加密

使用步骤

1. 在项目中添加依赖

在项目的pubspec.yaml文件中添加cccd_vietnam库:

dependencies:
  cccd_vietnam:
    path: '<path_to_cccd_vietnam_folder>'

然后运行以下命令获取依赖项:

flutter pub get

2. 示例代码

以下是一个完整的示例代码,演示如何使用cccd_vietnam插件来读取电子护照数据。

import 'package:flutter/material.dart';
import 'package:cccd_vietnam/dmrtd.dart';
import 'package:cccd_vietnam/extensions.dart';
import 'package:cccd_vietnam/src/proto/can_key.dart';
import 'package:cccd_vietnam/src/proto/ecdh_pace.dart';
import 'package:flutter/services.dart';
import 'dart:convert';
import 'dart:typed_data';

void main() {
  runApp(MaterialApp(home: MrtdEgApp()));
}

class MrtdEgApp extends StatelessWidget {
  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      home: MrtdHomePage(),
    );
  }
}

class MrtdHomePage extends StatefulWidget {
  [@override](/user/override)
  _MrtdHomePageState createState() => _MrtdHomePageState();
}

class _MrtdHomePageState extends State<MrtdHomePage> {
  final NfcProvider _nfc = NfcProvider();
  MrtdData? _mrtdData;
  String _alertMessage = "";

  [@override](/user/override)
  void initState() {
    super.initState();
    _initPlatformState();
  }

  Future<void> _initPlatformState() async {
    bool isNfcAvailable;
    try {
      NfcStatus status = await NfcProvider.nfcStatus;
      isNfcAvailable = status == NfcStatus.enabled;
    } on PlatformException {
      isNfcAvailable = false;
    }

    if (!mounted) return;

    setState(() {
      _isNfcAvailable = isNfcAvailable;
    });
  }

  void _buttonPressed() async {
    try {
      setState(() {
        _mrtdData = null;
        _alertMessage = "Waiting for Passport tag ...";
        _isReading = true;
      });

      await _nfc.connect(iosAlertMessage: "Hold your phone near Biometric Passport");
      final passport = Passport(_nfc);

      setState(() {
        _alertMessage = "Reading Passport ...";
      });

      _nfc.setIosAlertMessage("Trying to read EF.CardAccess ...");
      final mrtdData = MrtdData();

      try {
        mrtdData.cardAccess = await passport.readEfCardAccess();
      } catch (e) {
        print('ss');
      }

      _nfc.setIosAlertMessage("Trying to read EF.CardSecurity ...");

      try {
        mrtdData.cardSecurity = await passport.readEfCardSecurity();
      } catch (e) {
        print('ss');
      }

      _nfc.setIosAlertMessage("Initiating session with PACE...");
      mrtdData.isPACE = true;
      mrtdData.isDBA = false;

      if (mrtdData.isPACE) {
        await passport.startSessionPACE(mrtdData.cardAccess!, mrtdData);
      } else {
        await passport.startSession(mrtdData as DBAKey);
      }

      _nfc.setIosAlertMessage(formatProgressMsg("Reading EF.COM ...", 0));
      mrtdData.com = await passport.readEfCOM();

      _nfc.setIosAlertMessage(formatProgressMsg("Reading Data Groups ...", 20));

      if (mrtdData.com!.dgTags.contains(EfDG1.TAG)) {
        mrtdData.dg1 = await passport.readEfDG1();
      }

      if (mrtdData.com!.dgTags.contains(EfDG2.TAG)) {
        mrtdData.dg2 = await passport.readEfDG2();
      }

      if (mrtdData.com!.dgTags.contains(EfDG14.TAG)) {
        mrtdData.dg14 = await passport.readEfDG14();
      }

      if (mrtdData.com!.dgTags.contains(EfDG15.TAG)) {
        mrtdData.dg15 = await passport.readEfDG15();
        _nfc.setIosAlertMessage(formatProgressMsg("Doing AA ...", 60));
        mrtdData.aaSig = await passport.activeAuthenticate(Uint8List(8));
      }

      _nfc.setIosAlertMessage(formatProgressMsg("Reading EF.SOD ...", 80));
      mrtdData.sod = await passport.readEfSOD();

      setState(() {
        _mrtdData = mrtdData;
      });

      setState(() {
        _alertMessage = "";
      });
    } on Exception catch (e) {
      final se = e.toString().toLowerCase();
      String alertMsg = "An error has occurred while reading Passport!";
      if (e is PassportError) {
        if (se.contains("security status not satisfied")) {
          alertMsg = "Failed to initiate session with passport.\nCheck input data!";
        }
      }

      if (se.contains('timeout')) {
        alertMsg = "Timeout while waiting for Passport tag";
      } else if (se.contains("tag was lost")) {
        alertMsg = "Tag was lost. Please try again!";
      } else if (se.contains("invalidated by user")) {
        alertMsg = "";
      }

      setState(() {
        _alertMessage = alertMsg;
      });
    } finally {
      if (_alertMessage.isNotEmpty) {
        await _nfc.disconnect(iosErrorMessage: _alertMessage);
      } else {
        await _nfc.disconnect(iosAlertMessage: formatProgressMsg("Finished", 100));
      }
      setState(() {
        _isReading = false;
      });
    }
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('MRTD Example App'),
      ),
      body: Padding(
        padding: EdgeInsets.all(8.0),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: [
            ElevatedButton(
              onPressed: _buttonPressed,
              child: Text(_isReading ? 'Reading ...' : 'Read Passport'),
            ),
            SizedBox(height: 20),
            Text(_alertMessage, textAlign: TextAlign.center),
            SizedBox(height: 20),
            Expanded(
              child: ListView.builder(
                itemCount: _mrtdDataWidgets().length,
                itemBuilder: (context, index) {
                  return _mrtdDataWidgets()[index];
                },
              ),
            ),
          ],
        ),
      ),
    );
  }

  List<Widget> _mrtdDataWidgets() {
    List<Widget> list = [];
    if (_mrtdData == null) return list;

    if (_mrtdData!.cardAccess != null) {
      list.add(_makeMrtdDataWidget(
          header: 'EF.CardAccess',
          collapsedText: '',
          dataText: _mrtdData!.cardAccess!.toBytes().hex()));
    }

    if (_mrtdData!.cardSecurity != null) {
      list.add(_makeMrtdDataWidget(
          header: 'EF.CardSecurity',
          collapsedText: '',
          dataText: _mrtdData!.cardSecurity!.toBytes().hex()));
    }

    if (_mrtdData!.sod != null) {
      list.add(_makeMrtdDataWidget(
          header: 'EF.SOD',
          collapsedText: '',
          dataText: _mrtdData!.sod!.toBytes().hex()));
    }

    if (_mrtdData!.com != null) {
      list.add(_makeMrtdDataWidget(
          header: 'EF.COM',
          collapsedText: '',
          dataText: formatEfCom(_mrtdData!.com!)));
    }

    if (_mrtdData!.dg1 != null) {
      list.add(_makeMrtdDataWidget(
          header: 'EF.DG1',
          collapsedText: '',
          dataText: formatMRZ(_mrtdData!.dg1!.mrz)));
    }

    if (_mrtdData!.dg2 != null) {
      list.add(_makeMrtdDataWidget(
          header: 'EF.DG2',
          collapsedText: '',
          dataText: _mrtdData!.dg2!.toBytes().hex()));
    }

    return list;
  }

  Widget _makeMrtdDataWidget(
      {required String header,
      required String collapsedText,
      required String dataText}) {
    return ExpansionTile(
      title: Text(header),
      subtitle: Text(collapsedText),
      children: [
        Padding(
          padding: const EdgeInsets.all(16.0),
          child: SelectableText(dataText),
        ),
      ],
    );
  }
}

更多关于Flutter越南地区功能插件cccd_vietnam的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter越南地区功能插件cccd_vietnam的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是如何在Flutter项目中集成和使用cccd_vietnam插件的示例代码,该插件假设是用于处理越南地区特定功能的。请注意,由于我无法直接访问实际的插件文档或源代码,以下代码是基于插件通常的使用模式编写的。如果插件的实际用法有所不同,请参考插件的官方文档进行调整。

1. 添加依赖

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

dependencies:
  flutter:
    sdk: flutter
  cccd_vietnam: ^最新版本号  # 请替换为实际可用的最新版本号

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

2. 导入插件

在你的Dart文件中导入插件:

import 'package:cccd_vietnam/cccd_vietnam.dart';

3. 初始化插件

通常在应用启动时初始化插件,例如在MainActivity.kt(对于Android)或AppDelegate.swift(对于iOS)中进行必要的配置(如果插件需要的话)。不过,大多数Flutter插件只需在Dart代码中初始化即可。

void main() {
  WidgetsFlutterBinding.ensureInitialized();
  // 初始化插件(如果插件有初始化方法)
  CccdVietnam.instance.init();
  
  runApp(MyApp());
}

注意CccdVietnam.instance.init(); 这行代码是假设的,具体初始化方法请参考插件文档。

4. 使用插件功能

以下是一个假设的插件功能使用示例,比如获取越南地区的特定信息或服务:

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

void main() {
  WidgetsFlutterBinding.ensureInitialized();
  // 初始化插件(如果插件有初始化方法)
  CccdVietnam.instance.init();
  
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: VietnamFeatureScreen(),
    );
  }
}

class VietnamFeatureScreen extends StatefulWidget {
  @override
  _VietnamFeatureScreenState createState() => _VietnamFeatureScreenState();
}

class _VietnamFeatureScreenState extends State<VietnamFeatureScreen> {
  String vietnamFeatureInfo = '';

  @override
  void initState() {
    super.initState();
    // 调用插件的某个方法,例如获取越南地区特定信息
    _getVietnamFeatureInfo();
  }

  Future<void> _getVietnamFeatureInfo() async {
    try {
      // 假设插件有一个名为getVietnamFeatureInfo的异步方法
      String info = await CccdVietnam.instance.getVietnamFeatureInfo();
      setState(() {
        vietnamFeatureInfo = info;
      });
    } catch (e) {
      print("Error fetching Vietnam feature info: $e");
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Vietnam Feature Info'),
      ),
      body: Center(
        child: Text(vietnamFeatureInfo),
      ),
    );
  }
}

注意事项

  1. 实际方法名:上述代码中的CccdVietnam.instance.init()CccdVietnam.instance.getVietnamFeatureInfo()是假设的方法名。你需要参考插件的实际文档来找到正确的方法名和使用方式。

  2. 错误处理:在实际应用中,应添加更多的错误处理逻辑,以确保应用的健壮性。

  3. 权限:如果插件需要访问设备的某些权限(如网络访问、位置信息等),你需要在AndroidManifest.xmlInfo.plist中声明这些权限,并在运行时请求用户授权。

  4. 平台特定代码:如果插件有平台特定的实现,你可能需要在ios/android/文件夹中添加额外的代码。

请务必参考cccd_vietnam插件的官方文档和示例代码,以获取最准确的使用指南。

回到顶部