2026-03-31 08:51:18 +08:00
2026-03-31 08:51:18 +08:00
2026-03-31 08:51:18 +08:00
2026-03-31 08:51:18 +08:00
2026-03-31 08:51:18 +08:00
2026-03-31 08:51:18 +08:00
2026-03-31 08:51:18 +08:00
2026-03-31 08:51:18 +08:00
2026-03-31 08:51:18 +08:00
2026-03-31 08:51:18 +08:00
2026-03-31 08:51:18 +08:00

身份证读卡器 Flutter 插件

一个用于读取中国二代身份证的 Flutter 插件集成了01SDK身份证识别功能支持USB和蓝牙连接方式。

功能特性

  • 支持二代身份证读取
  • 获取完整的身份证信息(姓名、性别、民族、出生日期、地址、身份证号、签发机关、有效期)
  • 支持读取身份证照片
  • 支持USB连接读卡器
  • 支持蓝牙连接读卡器
  • 完整的错误处理和状态管理
  • 简单易用的API接口

支持平台

  • Android
  • iOS暂不支持

安装

pubspec.yaml 文件中添加依赖:

dependencies:
  idcard: ^0.0.1

然后运行:

flutter pub get

Android 配置

权限配置

android/app/src/main/AndroidManifest.xml 中添加必要权限:

<!-- USB权限 -->
<uses-permission android:name="android.permission.USB_PERMISSION" />
<uses-feature android:name="android.hardware.usb.host" android:required="false" />

<!-- Android 12+ USB权限 -->
<uses-permission android:name="android.permission.MANAGE_USB" android:maxSdkVersion="30" />

<!-- 蓝牙权限 -->
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

<!-- Android 12+ 蓝牙权限 -->
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" android:usesPermissionFlags="neverForLocation" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />

SDK版本配置

确保 minSdkVersion 至少为 21targetSdkVersion 为 34

android {
    compileSdk 34
    
    defaultConfig {
        minSdkVersion 21
        targetSdkVersion 34
    }
}

Android 12+ 兼容性

本插件已针对 Android 12+ 进行了优化,包括:

  • PendingIntent 兼容性:自动处理 Android 12+ 的 FLAG_IMMUTABLE 要求
  • USB 权限优化:改进了权限请求流程,增加了超时处理
  • 错误处理增强:提供更详细的错误信息和用户指导

使用方法

基本用法

import 'package:idcard/idcard.dart';

class IdCardReader {
  final _idcardPlugin = Idcard();

  /// 连接设备并读取身份证
  Future<void> readIdCard() async {
    try {
      // 1. 获取USB权限
      int permissionResult = await _idcardPlugin.getUsbPermission();
      if (permissionResult != 0) {
        print('获取USB权限失败错误码$permissionResult');
        return;
      }

      // 2. 打开设备
      int openResult = await _idcardPlugin.openDevice();
      if (openResult <= 0) {
        print('打开设备失败,错误码:$openResult');
        return;
      }
      print('设备打开成功,句柄:$openResult');

      // 3. 读取身份证信息(完整流程)
      IdCardInfo cardInfo = await _idcardPlugin.readCardComplete();
      
      print('姓名:${cardInfo.name}');
      print('身份证号:${cardInfo.idNumber}');
      print('性别:${cardInfo.gender}');
      // ... 其他信息
      
      // 4. 关闭设备
      await _idcardPlugin.closeDevice();
      
    } catch (e) {
      print('读卡失败:$e');
    }
  }
}

高级用法

分步骤读取

// 手动控制每个步骤
try {
  // 寻卡
  int findResult = await _idcardPlugin.findCard();
  if (findResult <= 0) {
    throw Exception('寻卡失败,错误码:$findResult');
  }

  // 选卡
  int selectResult = await _idcardPlugin.selectCard();
  if (selectResult <= 0) {
    throw Exception('选卡失败,错误码:$selectResult');
  }

  // 读取详细信息
  IdCardInfo cardInfo = await _idcardPlugin.readCardInfo();
  print('读取成功:${cardInfo.toString()}');
  
} catch (e) {
  print('读卡过程出错:$e');
}

蓝牙连接

// 使用蓝牙连接
int result = await _idcardPlugin.openDevice(
  portType: 'BLUETOOTH',
  portPara: 'BLUETOOTH_DEVICE_NAME', // 蓝牙设备名称
);

读取原始数据

// 读取原始二进制数据
Map<String, dynamic> result = await _idcardPlugin.readCard(
  cardType: 1,
  infoEncoding: 0,
  timeOut: 30000,
);

if (result['result'] > 0) {
  List<int> rawData = result['data'];
  // 处理原始数据
}

返回值说明

根据神思标准化接口规范,所有设备操作方法的返回值遵循以下规则:

  • 大于0:表示操作成功
    • 对于 openDevice():返回值是设备句柄,用于后续操作
    • 对于其他方法:返回值表示操作成功的状态码
  • 小于等于0:表示操作失败,返回值为错误码
    • 具体错误码含义请参考设备厂商提供的接口文档

重要提醒

在判断操作是否成功时,请使用 > 0 而不是 == 0 来判断成功状态:

// ✅ 正确的判断方式
int result = await _idcardPlugin.openDevice();
if (result > 0) {
  print('设备打开成功,句柄:$result');
} else {
  print('设备打开失败,错误码:$result');
}

// ❌ 错误的判断方式
if (result == 0) {
  // 这样判断是错误的
}

API 参考

Idcard 类

方法

方法 描述 参数 返回值
getPlatformVersion() 获取平台版本 Future<String?>
getUsbPermission({int vid, int pid}) 获取USB权限 vid: 厂商ID, pid: 产品ID Future<int>
openDevice({String portType, String portPara, String extendPara}) 打开设备 portType: 端口类型, portPara: 端口参数, extendPara: 扩展参数 Future<int> - 大于0表示成功设备句柄小于等于0表示失败
closeDevice() 关闭设备 Future<int> - 大于0表示成功小于等于0表示失败
findCard() 寻卡 Future<int> - 大于0表示成功小于等于0表示失败
selectCard() 选卡 Future<int> - 大于0表示成功小于等于0表示失败
readCard({int cardType, int infoEncoding, int timeOut}) 读取原始数据 cardType: 卡片类型, infoEncoding: 编码, timeOut: 超时时间 Future<Map<String, dynamic>>
readCardInfo() 读取详细信息 Future<IdCardInfo>
readCardComplete({int timeOut}) 完整读卡流程 timeOut: 超时时间 Future<IdCardInfo>
isDeviceConnected() 检查设备连接状态 Future<bool>

IdCardInfo 类

身份证信息数据模型:

class IdCardInfo {
  final String name;        // 姓名
  final String gender;      // 性别
  final String nation;      // 民族
  final String birthDate;   // 出生日期
  final String address;     // 地址
  final String idNumber;    // 身份证号
  final String signOrgan;   // 签发机关
  final String validTerm;   // 有效期
  final List<int>? photo;   // 照片数据JPEG格式
}

错误码说明

错误码 说明
0 成功
-1 设备未找到
-2 设备接口错误
-3 权限被拒绝
其他 具体错误码请参考01SDK文档

示例应用

查看 example 目录中的完整示例应用,演示了如何使用本插件的所有功能。

运行示例:

cd example
flutter run

故障排除

Android 12+ USB权限问题

如果在Android 12或更高版本上遇到"获取USB权限失败"的问题,请尝试以下解决方案:

1. 检查权限配置

确保在 AndroidManifest.xml 中正确配置了所有必要权限:

<uses-permission android:name="android.permission.USB_PERMISSION" />
<uses-permission android:name="android.permission.MANAGE_USB" android:maxSdkVersion="30" />
<uses-feature android:name="android.hardware.usb.host" android:required="false" />

2. 手动授权USB权限

  1. 进入 设置 > 应用管理 > 您的应用
  2. 点击 权限管理
  3. 找到并开启 USB 相关权限
  4. 重新启动应用

3. 开发者选项设置

  1. 进入 设置 > 开发者选项
  2. 开启 USB调试
  3. 开启 USB安装 (如果有)
  4. 关闭 监控ADB安装应用 (如果有)

4. 设备连接顺序

  1. 先启动应用
  2. 再连接USB设备
  3. 在权限对话框中点击"允许"
  4. 调用 getUsbPermission() 方法

5. 检查设备兼容性

确保您的身份证读卡器设备:

  • 支持USB HID协议
  • 与Android系统兼容
  • VID/PID参数正确

常见错误码

错误码 含义 解决方案
-1 设备未找到 检查设备连接和VID/PID
-2 接口错误 检查设备驱动和兼容性
-3 权限被拒绝 手动授权USB权限
-99 未知错误 重启应用或设备

其他常见问题

Q: 设备连接失败怎么办?

A: 请检查:

  1. 设备是否正确连接
  2. USB权限是否已授权
  3. 设备驱动是否正常
  4. VID/PID参数是否正确

Q: 读取身份证失败?

A: 请确保:

  1. 身份证放置正确
  2. 身份证芯片完好
  3. 设备工作正常
  4. 按正确顺序调用API

Q: 在模拟器上无法使用?

A: 身份证读卡功能需要物理USB设备模拟器不支持。请在真机上测试。

Q: 照片数据如何显示?

A: 照片数据是JPEG格式的字节数组可以使用 Image.memory() 显示:

if (cardInfo.photo != null) {
  Image.memory(Uint8List.fromList(cardInfo.photo!))
}

许可证

本项目采用 MIT 许可证。详见 LICENSE 文件。

贡献

欢迎提交 Issue 和 Pull Request

更新日志

0.0.1

  • 初始版本
  • 支持基本的身份证读取功能
  • 集成01SDK
  • 支持USB和蓝牙连接
Description
No description provided
Readme 2.3 MiB
Languages
Java 61.6%
Dart 38.4%