身份证读卡器 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 至少为 21,targetSdkVersion 为 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权限
- 进入 设置 > 应用管理 > 您的应用
- 点击 权限管理
- 找到并开启 USB 相关权限
- 重新启动应用
3. 开发者选项设置
- 进入 设置 > 开发者选项
- 开启 USB调试
- 开启 USB安装 (如果有)
- 关闭 监控ADB安装应用 (如果有)
4. 设备连接顺序
- 先启动应用
- 再连接USB设备
- 在权限对话框中点击"允许"
- 调用
getUsbPermission()方法
5. 检查设备兼容性
确保您的身份证读卡器设备:
- 支持USB HID协议
- 与Android系统兼容
- VID/PID参数正确
常见错误码
| 错误码 | 含义 | 解决方案 |
|---|---|---|
| -1 | 设备未找到 | 检查设备连接和VID/PID |
| -2 | 接口错误 | 检查设备驱动和兼容性 |
| -3 | 权限被拒绝 | 手动授权USB权限 |
| -99 | 未知错误 | 重启应用或设备 |
其他常见问题
Q: 设备连接失败怎么办?
A: 请检查:
- 设备是否正确连接
- USB权限是否已授权
- 设备驱动是否正常
- VID/PID参数是否正确
Q: 读取身份证失败?
A: 请确保:
- 身份证放置正确
- 身份证芯片完好
- 设备工作正常
- 按正确顺序调用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
Languages
Java
61.6%
Dart
38.4%