# 身份证读卡器 Flutter 插件 一个用于读取中国二代身份证的 Flutter 插件,集成了01SDK身份证识别功能,支持USB和蓝牙连接方式。 ## 功能特性 - ✅ 支持二代身份证读取 - ✅ 获取完整的身份证信息(姓名、性别、民族、出生日期、地址、身份证号、签发机关、有效期) - ✅ 支持读取身份证照片 - ✅ 支持USB连接读卡器 - ✅ 支持蓝牙连接读卡器 - ✅ 完整的错误处理和状态管理 - ✅ 简单易用的API接口 ## 支持平台 - ✅ Android - ❌ iOS(暂不支持) ## 安装 在 `pubspec.yaml` 文件中添加依赖: ```yaml dependencies: idcard: ^0.0.1 ``` 然后运行: ```bash flutter pub get ``` ## Android 配置 ### 权限配置 在 `android/app/src/main/AndroidManifest.xml` 中添加必要权限: ```xml ``` ### SDK版本配置 确保 `minSdkVersion` 至少为 21,`targetSdkVersion` 为 34: ```gradle android { compileSdk 34 defaultConfig { minSdkVersion 21 targetSdkVersion 34 } } ``` ### Android 12+ 兼容性 本插件已针对 Android 12+ 进行了优化,包括: - **PendingIntent 兼容性**:自动处理 Android 12+ 的 `FLAG_IMMUTABLE` 要求 - **USB 权限优化**:改进了权限请求流程,增加了超时处理 - **错误处理增强**:提供更详细的错误信息和用户指导 ## 使用方法 ### 基本用法 ```dart import 'package:idcard/idcard.dart'; class IdCardReader { final _idcardPlugin = Idcard(); /// 连接设备并读取身份证 Future 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'); } } } ``` ### 高级用法 #### 分步骤读取 ```dart // 手动控制每个步骤 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'); } ``` #### 蓝牙连接 ```dart // 使用蓝牙连接 int result = await _idcardPlugin.openDevice( portType: 'BLUETOOTH', portPara: 'BLUETOOTH_DEVICE_NAME', // 蓝牙设备名称 ); ``` #### 读取原始数据 ```dart // 读取原始二进制数据 Map result = await _idcardPlugin.readCard( cardType: 1, infoEncoding: 0, timeOut: 30000, ); if (result['result'] > 0) { List rawData = result['data']; // 处理原始数据 } ``` ## 返回值说明 根据神思标准化接口规范,所有设备操作方法的返回值遵循以下规则: - **大于0**:表示操作成功 - 对于 `openDevice()`:返回值是设备句柄,用于后续操作 - 对于其他方法:返回值表示操作成功的状态码 - **小于等于0**:表示操作失败,返回值为错误码 - 具体错误码含义请参考设备厂商提供的接口文档 ### 重要提醒 在判断操作是否成功时,请使用 `> 0` 而不是 `== 0` 来判断成功状态: ```dart // ✅ 正确的判断方式 int result = await _idcardPlugin.openDevice(); if (result > 0) { print('设备打开成功,句柄:$result'); } else { print('设备打开失败,错误码:$result'); } // ❌ 错误的判断方式 if (result == 0) { // 这样判断是错误的 } ``` ## API 参考 ### Idcard 类 #### 方法 | 方法 | 描述 | 参数 | 返回值 | |------|------|------|--------| | `getPlatformVersion()` | 获取平台版本 | 无 | `Future` | | `getUsbPermission({int vid, int pid})` | 获取USB权限 | vid: 厂商ID, pid: 产品ID | `Future` | | `openDevice({String portType, String portPara, String extendPara})` | 打开设备 | portType: 端口类型, portPara: 端口参数, extendPara: 扩展参数 | `Future` - 大于0表示成功(设备句柄),小于等于0表示失败 | | `closeDevice()` | 关闭设备 | 无 | `Future` - 大于0表示成功,小于等于0表示失败 | | `findCard()` | 寻卡 | 无 | `Future` - 大于0表示成功,小于等于0表示失败 | | `selectCard()` | 选卡 | 无 | `Future` - 大于0表示成功,小于等于0表示失败 | | `readCard({int cardType, int infoEncoding, int timeOut})` | 读取原始数据 | cardType: 卡片类型, infoEncoding: 编码, timeOut: 超时时间 | `Future>` | | `readCardInfo()` | 读取详细信息 | 无 | `Future` | | `readCardComplete({int timeOut})` | 完整读卡流程 | timeOut: 超时时间 | `Future` | | `isDeviceConnected()` | 检查设备连接状态 | 无 | `Future` | ### IdCardInfo 类 身份证信息数据模型: ```dart 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? photo; // 照片数据(JPEG格式) } ``` ## 错误码说明 | 错误码 | 说明 | |--------|------| | 0 | 成功 | | -1 | 设备未找到 | | -2 | 设备接口错误 | | -3 | 权限被拒绝 | | 其他 | 具体错误码请参考01SDK文档 | ## 示例应用 查看 `example` 目录中的完整示例应用,演示了如何使用本插件的所有功能。 运行示例: ```bash cd example flutter run ``` ## 故障排除 ### Android 12+ USB权限问题 如果在Android 12或更高版本上遇到"获取USB权限失败"的问题,请尝试以下解决方案: #### 1. 检查权限配置 确保在 `AndroidManifest.xml` 中正确配置了所有必要权限: ```xml ``` #### 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()` 显示: ```dart if (cardInfo.photo != null) { Image.memory(Uint8List.fromList(cardInfo.photo!)) } ``` ## 许可证 本项目采用 MIT 许可证。详见 [LICENSE](LICENSE) 文件。 ## 贡献 欢迎提交 Issue 和 Pull Request! ## 更新日志 ### 0.0.1 - 初始版本 - 支持基本的身份证读取功能 - 集成01SDK - 支持USB和蓝牙连接