This commit is contained in:
2026-03-31 08:51:00 +08:00
commit 12d21c4c90
71 changed files with 4529 additions and 0 deletions

360
README.md Normal file
View File

@@ -0,0 +1,360 @@
# 身份证读卡器 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
<!-- 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
```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<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');
}
}
}
```
### 高级用法
#### 分步骤读取
```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<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` 来判断成功状态:
```dart
// ✅ 正确的判断方式
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 类
身份证信息数据模型:
```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<int>? photo; // 照片数据JPEG格式
}
```
## 错误码说明
| 错误码 | 说明 |
|--------|------|
| 0 | 成功 |
| -1 | 设备未找到 |
| -2 | 设备接口错误 |
| -3 | 权限被拒绝 |
| 其他 | 具体错误码请参考01SDK文档 |
## 示例应用
查看 `example` 目录中的完整示例应用,演示了如何使用本插件的所有功能。
运行示例:
```bash
cd example
flutter run
```
## 故障排除
### Android 12+ USB权限问题
如果在Android 12或更高版本上遇到"获取USB权限失败"的问题,请尝试以下解决方案:
#### 1. 检查权限配置
确保在 `AndroidManifest.xml` 中正确配置了所有必要权限:
```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()` 显示:
```dart
if (cardInfo.photo != null) {
Image.memory(Uint8List.fromList(cardInfo.photo!))
}
```
## 许可证
本项目采用 MIT 许可证。详见 [LICENSE](LICENSE) 文件。
## 贡献
欢迎提交 Issue 和 Pull Request
## 更新日志
### 0.0.1
- 初始版本
- 支持基本的身份证读取功能
- 集成01SDK
- 支持USB和蓝牙连接