init
This commit is contained in:
@@ -0,0 +1,32 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.example.idcard">
|
||||
|
||||
<!-- 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" />
|
||||
|
||||
<application>
|
||||
<!-- USB设备过滤器 -->
|
||||
<activity android:name=".UsbPermissionActivity" android:exported="false">
|
||||
<intent-filter>
|
||||
<action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
|
||||
</intent-filter>
|
||||
<meta-data android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
|
||||
android:resource="@xml/device_filter" />
|
||||
</activity>
|
||||
</application>
|
||||
|
||||
<!-- 蓝牙权限 -->
|
||||
<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" />
|
||||
|
||||
</manifest>
|
||||
@@ -0,0 +1,642 @@
|
||||
package com.example.idcard;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
|
||||
import io.flutter.embedding.engine.plugins.FlutterPlugin;
|
||||
import io.flutter.plugin.common.MethodCall;
|
||||
import io.flutter.plugin.common.MethodChannel;
|
||||
import io.flutter.plugin.common.MethodChannel.MethodCallHandler;
|
||||
import io.flutter.plugin.common.MethodChannel.Result;
|
||||
|
||||
import com.sdses.JniCommonInterface;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* IdcardPlugin - Flutter插件,用于身份证识别功能
|
||||
* 集成了01SDK的身份证读取功能
|
||||
*/
|
||||
public class IdcardPlugin implements FlutterPlugin, MethodCallHandler {
|
||||
private static final String TAG = "IdcardPlugin";
|
||||
|
||||
/// 与Flutter通信的方法通道
|
||||
private MethodChannel channel;
|
||||
private Context context;
|
||||
|
||||
@Override
|
||||
public void onAttachedToEngine(@NonNull FlutterPluginBinding flutterPluginBinding) {
|
||||
channel = new MethodChannel(flutterPluginBinding.getBinaryMessenger(), "idcard");
|
||||
channel.setMethodCallHandler(this);
|
||||
context = flutterPluginBinding.getApplicationContext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMethodCall(@NonNull MethodCall call, @NonNull Result result) {
|
||||
try {
|
||||
switch (call.method) {
|
||||
case "getPlatformVersion":
|
||||
result.success("Android " + android.os.Build.VERSION.RELEASE);
|
||||
break;
|
||||
case "openDevice":
|
||||
handleOpenDevice(call, result);
|
||||
break;
|
||||
case "setCurrentDevice":
|
||||
handleSetCurrentDevice(call, result);
|
||||
break;
|
||||
case "getCurrentDevice":
|
||||
handleGetCurrentDevice(result);
|
||||
break;
|
||||
case "getLibraryInfo":
|
||||
handleGetLibraryInfo(result);
|
||||
break;
|
||||
case "getTerminalModel":
|
||||
handleGetTerminalModel(result);
|
||||
break;
|
||||
case "terminalHeartBeat":
|
||||
handleTerminalHeartBeat(result);
|
||||
break;
|
||||
case "getLastRecvData":
|
||||
handleGetLastRecvData(result);
|
||||
break;
|
||||
case "getTerminalFirmVersion":
|
||||
handleGetTerminalFirmVersion(result);
|
||||
break;
|
||||
case "getTerminalSn":
|
||||
handleGetTerminalSn(result);
|
||||
break;
|
||||
case "closeDevice":
|
||||
handleCloseDevice(result);
|
||||
break;
|
||||
case "findCard":
|
||||
handleFindCard(result);
|
||||
break;
|
||||
case "selectCard":
|
||||
handleSelectCard(result);
|
||||
break;
|
||||
case "idReadCard":
|
||||
handleIdReadCard(call, result);
|
||||
break;
|
||||
case "readCard":
|
||||
handleReadCard(call, result);
|
||||
break;
|
||||
case "readCardInfo":
|
||||
handleReadCardInfo(result);
|
||||
break;
|
||||
case "readNewAddress":
|
||||
handleReadNewAddress(result);
|
||||
break;
|
||||
case "getSamStatus":
|
||||
handleGetSamStatus(result);
|
||||
break;
|
||||
case "getSamIdStr":
|
||||
handleGetSamIdStr(result);
|
||||
break;
|
||||
case "getUsbPermission":
|
||||
handleGetUsbPermission(call, result);
|
||||
break;
|
||||
default:
|
||||
result.notImplemented();
|
||||
break;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Error in method call: " + call.method, e);
|
||||
result.error("ERROR", "Method call failed: " + e.getMessage(), null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取USB权限
|
||||
*/
|
||||
private void handleGetUsbPermission(MethodCall call, Result result) {
|
||||
Integer vid = call.argument("vid");
|
||||
Integer pid = call.argument("pid");
|
||||
|
||||
if (vid == null || pid == null) {
|
||||
result.error("INVALID_PARAMS", "VID and PID are required", null);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
long ret = JniCommonInterface.GetUsbPermission(context, vid, pid);
|
||||
|
||||
// 根据返回值提供更详细的错误信息
|
||||
switch ((int)ret) {
|
||||
case 0:
|
||||
result.success(ret);
|
||||
break;
|
||||
case -1:
|
||||
result.error("DEVICE_NOT_FOUND", "未找到指定的USB设备 (VID:" + vid + ", PID:" + pid + ")", null);
|
||||
break;
|
||||
case -2:
|
||||
result.error("INTERFACE_ERROR", "USB设备接口错误", null);
|
||||
break;
|
||||
case -3:
|
||||
result.error("PERMISSION_DENIED", "USB权限请求被拒绝或超时,请在系统设置中手动授权USB权限", null);
|
||||
break;
|
||||
case -99:
|
||||
result.error("UNKNOWN_ERROR", "获取USB权限时发生未知错误", null);
|
||||
break;
|
||||
default:
|
||||
result.error("ERROR", "获取USB权限失败,错误码: " + ret, null);
|
||||
break;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
result.error("EXCEPTION", "获取USB权限时发生异常: " + e.getMessage(), null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 打开设备
|
||||
*/
|
||||
private void handleOpenDevice(MethodCall call, Result result) {
|
||||
try {
|
||||
String portType = call.argument("portType");
|
||||
String portPara = call.argument("portPara");
|
||||
String extendPara = call.argument("extendPara");
|
||||
|
||||
if (portType == null) portType = "USB";
|
||||
if (portPara == null) portPara = "";
|
||||
if (extendPara == null) extendPara = "";
|
||||
|
||||
long deviceHandle = JniCommonInterface.OpenDevice(portType, portPara, extendPara);
|
||||
|
||||
// 根据接口文档,返回值大于0表示成功(设备句柄),小于等于0表示失败
|
||||
if (deviceHandle > 0) {
|
||||
result.success(deviceHandle);
|
||||
} else {
|
||||
result.error("OPEN_DEVICE_FAILED", "Failed to open device, error code: " + deviceHandle, null);
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Error opening device", e);
|
||||
result.error("ERROR", "Failed to open device: " + e.getMessage(), null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭设备
|
||||
*/
|
||||
private void handleCloseDevice(Result result) {
|
||||
try {
|
||||
long closeResult = JniCommonInterface.CloseDevice();
|
||||
|
||||
// 根据接口文档,返回值0表示成功;非0表示失败
|
||||
if (closeResult == 0) {
|
||||
result.success(closeResult);
|
||||
} else {
|
||||
result.error("CLOSE_DEVICE_FAILED", "Failed to close device, error code: " + closeResult, null);
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Error closing device", e);
|
||||
result.error("ERROR", "Failed to close device: " + e.getMessage(), null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 寻卡
|
||||
*/
|
||||
private void handleFindCard(Result result) {
|
||||
try {
|
||||
long findResult = JniCommonInterface.IdFindCard();
|
||||
|
||||
if (findResult == 0) {
|
||||
result.success(findResult);
|
||||
} else {
|
||||
result.error("FIND_CARD_FAILED", "Failed to find card, error code: " + findResult, null);
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Error finding card", e);
|
||||
result.error("ERROR", "Failed to find card: " + e.getMessage(), null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 选卡
|
||||
*/
|
||||
private void handleSelectCard(Result result) {
|
||||
try {
|
||||
long selectResult = JniCommonInterface.IdSelectCard();
|
||||
|
||||
if (selectResult == 0) {
|
||||
result.success(selectResult);
|
||||
} else {
|
||||
result.error("SELECT_CARD_FAILED", "Failed to select card, error code: " + selectResult, null);
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Error selecting card", e);
|
||||
result.error("ERROR", "Failed to select card: " + e.getMessage(), null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取身份证信息
|
||||
*/
|
||||
private void handleReadCard(MethodCall call, Result result) {
|
||||
Integer cardType = call.argument("cardType");
|
||||
Integer infoEncoding = call.argument("infoEncoding");
|
||||
Integer timeOut = call.argument("timeOut");
|
||||
|
||||
if (cardType == null) cardType = 1;
|
||||
if (infoEncoding == null) infoEncoding = 0;
|
||||
if (timeOut == null) timeOut = 30000;
|
||||
|
||||
byte[] idCardInfo = new byte[4096];
|
||||
long ret = JniCommonInterface.IdReadCard((byte)cardType.intValue(),
|
||||
(byte)infoEncoding.intValue(),
|
||||
idCardInfo,
|
||||
timeOut);
|
||||
|
||||
Map<String, Object> resultMap = new HashMap<>();
|
||||
resultMap.put("result", ret);
|
||||
// 根据接口文档,返回值0表示成功;非0表示失败
|
||||
if (ret == 0) {
|
||||
resultMap.put("data", idCardInfo);
|
||||
}
|
||||
result.success(resultMap);
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取身份证详细信息
|
||||
*/
|
||||
private void handleReadCardInfo(Result result) {
|
||||
try {
|
||||
// 读取基本信息和照片
|
||||
byte[] chMsg = new byte[256];
|
||||
long[] chMsgLen = new long[1];
|
||||
byte[] phMsg = new byte[1024];
|
||||
long[] phMsgLen = new long[1];
|
||||
|
||||
long ret = JniCommonInterface.IdReadBaseMsg(chMsg, chMsgLen, phMsg, phMsgLen);
|
||||
|
||||
if (ret != 0) {
|
||||
result.error("READ_failed", "Failed to read card info, error code: " + ret, null);
|
||||
return;
|
||||
}
|
||||
|
||||
// 解析身份证信息
|
||||
Map<String, Object> cardInfo = new HashMap<>();
|
||||
|
||||
// 获取各个字段
|
||||
byte[] name = new byte[32];
|
||||
byte[] gender = new byte[4];
|
||||
byte[] nation = new byte[32];
|
||||
byte[] birthDate = new byte[16];
|
||||
byte[] address = new byte[128];
|
||||
byte[] idNumber = new byte[32];
|
||||
byte[] signOrgan = new byte[64];
|
||||
byte[] validTerm = new byte[32];
|
||||
|
||||
JniCommonInterface.IdCardGetName(name);
|
||||
JniCommonInterface.IdCardGetGender(gender);
|
||||
JniCommonInterface.IdCardGetNation(nation);
|
||||
JniCommonInterface.IdCardGetBirthDate(birthDate);
|
||||
JniCommonInterface.IdCardGetAddress(address);
|
||||
JniCommonInterface.IdCardGetIdNumber(idNumber);
|
||||
JniCommonInterface.IdCardGetSignOrgan(signOrgan);
|
||||
JniCommonInterface.IdCardGetValidTerm(validTerm);
|
||||
|
||||
// 获取照片
|
||||
byte[] photoBuffer = new byte[10240];
|
||||
long[] photoBufferLen = new long[1];
|
||||
JniCommonInterface.IdCardGetPhotoBuffer((byte)1, photoBuffer, photoBufferLen);
|
||||
|
||||
cardInfo.put("name", new String(name, "GBK").trim());
|
||||
cardInfo.put("gender", new String(gender, "GBK").trim());
|
||||
cardInfo.put("nation", new String(nation, "GBK").trim());
|
||||
cardInfo.put("birthDate", new String(birthDate, "GBK").trim());
|
||||
cardInfo.put("address", new String(address, "GBK").trim());
|
||||
cardInfo.put("idNumber", new String(idNumber, "GBK").trim());
|
||||
cardInfo.put("signOrgan", new String(signOrgan, "GBK").trim());
|
||||
cardInfo.put("validTerm", new String(validTerm, "GBK").trim());
|
||||
|
||||
if (photoBufferLen[0] > 0) {
|
||||
byte[] photo = new byte[(int)photoBufferLen[0]];
|
||||
System.arraycopy(photoBuffer, 0, photo, 0, (int)photoBufferLen[0]);
|
||||
cardInfo.put("photo", photo);
|
||||
}
|
||||
|
||||
result.success(cardInfo);
|
||||
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Error reading card info", e);
|
||||
result.error("ERROR", "Failed to read card2 info: " + e.getMessage(), null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置当前设备(多设备操作)
|
||||
*/
|
||||
private void handleSetCurrentDevice(MethodCall call, Result result) {
|
||||
try {
|
||||
Integer devHandle = call.argument("devHandle");
|
||||
if (devHandle == null) {
|
||||
result.error("INVALID_PARAMS", "Device handle is required", null);
|
||||
return;
|
||||
}
|
||||
|
||||
long ret = JniCommonInterface.SetCurrentDevice(devHandle);
|
||||
|
||||
// 根据接口文档,返回值0表示成功;非0表示失败
|
||||
if (ret == 0) {
|
||||
result.success(ret);
|
||||
} else {
|
||||
result.error("SET_CURRENT_DEVICE_FAILED", "Failed to set current device, error code: " + ret, null);
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Error setting current device", e);
|
||||
result.error("ERROR", "Failed to set current device: " + e.getMessage(), null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前设备(多设备操作)
|
||||
*/
|
||||
private void handleGetCurrentDevice(Result result) {
|
||||
try {
|
||||
long currentDevice = JniCommonInterface.GetCurrentDevice();
|
||||
result.success(currentDevice);
|
||||
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Error getting current device", e);
|
||||
result.error("ERROR", "Failed to get current device: " + e.getMessage(), null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取接口库信息
|
||||
*/
|
||||
private void handleGetLibraryInfo(Result result) {
|
||||
try {
|
||||
byte[] version = new byte[64];
|
||||
byte[] description = new byte[256];
|
||||
|
||||
long ret = JniCommonInterface.GetLibraryInfo(version, description);
|
||||
|
||||
// 根据接口文档,返回值0表示成功;非0表示失败
|
||||
if (ret == 0) {
|
||||
Map<String, String> info = new HashMap<>();
|
||||
info.put("version", new String(version, "GBK").trim());
|
||||
info.put("description", new String(description, "GBK").trim());
|
||||
result.success(info);
|
||||
} else {
|
||||
result.error("GET_LIBRARY_INFO_FAILED", "Failed to get library info, error code: " + ret, null);
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Error getting library info", e);
|
||||
result.error("ERROR", "Failed to get library info: " + e.getMessage(), null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取设备型号
|
||||
*/
|
||||
private void handleGetTerminalModel(Result result) {
|
||||
try {
|
||||
byte[] model = new byte[64];
|
||||
long ret = JniCommonInterface.GetTerminalModel(model);
|
||||
|
||||
// 根据接口文档,返回值0表示成功;非0表示失败
|
||||
if (ret == 0) {
|
||||
String modelStr = new String(model, "GBK").trim();
|
||||
result.success(modelStr);
|
||||
} else {
|
||||
result.error("GET_TERMINAL_MODEL_FAILED", "Failed to get terminal model, error code: " + ret, null);
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Error getting terminal model", e);
|
||||
result.error("ERROR", "Failed to get terminal model: " + e.getMessage(), null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设备轮询心跳
|
||||
*/
|
||||
private void handleTerminalHeartBeat(Result result) {
|
||||
try {
|
||||
long ret = JniCommonInterface.TerminalHeartBeat();
|
||||
|
||||
// 根据接口文档,返回值0表示成功;非0表示失败
|
||||
if (ret == 0) {
|
||||
result.success(ret);
|
||||
} else {
|
||||
result.error("TERMINAL_HEARTBEAT_FAILED", "Terminal heartbeat failed, error code: " + ret, null);
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Error in terminal heart beat", e);
|
||||
result.error("ERROR", "Failed to perform terminal heart beat: " + e.getMessage(), null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取接收数据
|
||||
*/
|
||||
private void handleGetLastRecvData(Result result) {
|
||||
try {
|
||||
byte[] data = new byte[1024];
|
||||
long[] dataLen = new long[1];
|
||||
|
||||
JniCommonInterface.GetLastRecvData(data, dataLen);
|
||||
|
||||
if (dataLen[0] > 0) {
|
||||
byte[] actualData = new byte[(int)dataLen[0]];
|
||||
System.arraycopy(data, 0, actualData, 0, (int)dataLen[0]);
|
||||
result.success(actualData);
|
||||
} else {
|
||||
result.success(new byte[0]);
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Error getting last recv data", e);
|
||||
result.error("ERROR", "Failed to get last recv data: " + e.getMessage(), null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取设备固件版本
|
||||
*/
|
||||
private void handleGetTerminalFirmVersion(Result result) {
|
||||
try {
|
||||
byte[] firmVersion = new byte[64];
|
||||
byte[] hardwareVersion = new byte[64];
|
||||
|
||||
long ret = JniCommonInterface.GetTerminalFirmVersion(firmVersion, hardwareVersion);
|
||||
|
||||
// 根据接口文档,返回值0表示成功;非0表示失败
|
||||
if (ret == 0) {
|
||||
Map<String, String> versionInfo = new HashMap<>();
|
||||
versionInfo.put("firmVersion", new String(firmVersion, "GBK").trim());
|
||||
versionInfo.put("hardwareVersion", new String(hardwareVersion, "GBK").trim());
|
||||
result.success(versionInfo);
|
||||
} else {
|
||||
result.error("GET_FIRM_VERSION_FAILED", "Failed to get terminal firm version, error code: " + ret, null);
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Error getting terminal firm version", e);
|
||||
result.error("ERROR", "Failed to get terminal firm version: " + e.getMessage(), null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取设备序列号
|
||||
*/
|
||||
private void handleGetTerminalSn(Result result) {
|
||||
try {
|
||||
byte[] sn = new byte[64];
|
||||
long ret = JniCommonInterface.GetTerminalSn(sn);
|
||||
|
||||
// 根据接口文档,返回值0表示成功;非0表示失败
|
||||
if (ret == 0) {
|
||||
String snStr = new String(sn, "GBK").trim();
|
||||
result.success(snStr);
|
||||
} else {
|
||||
result.error("GET_TERMINAL_SN_FAILED", "Failed to get terminal SN, error code: " + ret, null);
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Error getting terminal SN", e);
|
||||
result.error("ERROR", "Failed to get terminal SN: " + e.getMessage(), null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取身份证(新版接口)
|
||||
*/
|
||||
private void handleIdReadCard(MethodCall call, Result result) {
|
||||
try {
|
||||
Integer cardType = call.argument("cardType");
|
||||
Integer infoEncoding = call.argument("infoEncoding");
|
||||
Integer timeOut = call.argument("timeOut");
|
||||
|
||||
if (cardType == null) cardType = 0x00;
|
||||
if (infoEncoding == null) infoEncoding = 0x01;
|
||||
if (timeOut == null) timeOut = 30000;
|
||||
|
||||
byte[] idCardInfo = new byte[4096];
|
||||
long ret = JniCommonInterface.IdReadCard((byte)cardType.intValue(),
|
||||
(byte)infoEncoding.intValue(),
|
||||
idCardInfo,
|
||||
timeOut);
|
||||
|
||||
Map<String, Object> resultMap = new HashMap<>();
|
||||
resultMap.put("result", ret);
|
||||
|
||||
// 根据接口文档,返回值0表示成功;非0表示失败
|
||||
if (ret == 0) {
|
||||
// 将字节数组转换为字符串(根据编码方式)
|
||||
String encoding = "GBK";
|
||||
if (infoEncoding == 0x02) {
|
||||
encoding = "UTF-16LE";
|
||||
} else if (infoEncoding == 0x03) {
|
||||
encoding = "UTF-8";
|
||||
}
|
||||
|
||||
// 找到字节数组中第一个null字符的位置
|
||||
int length = 0;
|
||||
for (int i = 0; i < idCardInfo.length; i++) {
|
||||
if (idCardInfo[i] == 0) {
|
||||
length = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 如果没有找到null字符,使用整个数组长度
|
||||
if (length == 0) {
|
||||
length = idCardInfo.length;
|
||||
}
|
||||
|
||||
// 只转换有效的字节数据
|
||||
String dataStr = new String(idCardInfo, 0, length, encoding).trim();
|
||||
resultMap.put("data", dataStr);
|
||||
|
||||
Log.d(TAG, "IdReadCard success, data length: " + length + ", data: " + dataStr);
|
||||
} else {
|
||||
Log.e(TAG, "IdReadCard failed with error code: " + ret);
|
||||
}
|
||||
|
||||
result.success(resultMap);
|
||||
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Error in idReadCard", e);
|
||||
result.error("ERROR", "Failed to read card: " + e.getMessage(), null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取追加住址
|
||||
*/
|
||||
private void handleReadNewAddress(Result result) {
|
||||
try {
|
||||
byte[] address = new byte[256];
|
||||
long ret = JniCommonInterface.IdReadNewAddress(address);
|
||||
|
||||
// 根据接口文档,返回值0表示成功;非0表示失败
|
||||
if (ret == 0) {
|
||||
String addressStr = new String(address, "GBK").trim();
|
||||
result.success(addressStr);
|
||||
} else {
|
||||
result.error("READ_failed", "Failed to read new address, error code: " + ret, null);
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Error reading new address", e);
|
||||
result.error("ERROR", "Failed to read new address: " + e.getMessage(), null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取SAM模块状态
|
||||
*/
|
||||
private void handleGetSamStatus(Result result) {
|
||||
try {
|
||||
long status = JniCommonInterface.GetSamStatus();
|
||||
// 根据接口文档,返回值0表示成功;非0表示失败
|
||||
if (status == 0) {
|
||||
result.success(0); // 成功时返回0
|
||||
} else {
|
||||
result.error("SAM_STATUS_ERROR", "SAM module status error, code: " + status, null);
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Error getting SAM status", e);
|
||||
result.error("ERROR", "Failed to get SAM status: " + e.getMessage(), null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取SAM模块编号字符串
|
||||
*/
|
||||
private void handleGetSamIdStr(Result result) {
|
||||
try {
|
||||
byte[] samId = new byte[64];
|
||||
long ret = JniCommonInterface.GetSamIdStr(samId);
|
||||
|
||||
// 根据接口文档,返回值0表示成功;非0表示失败
|
||||
if (ret == 0) {
|
||||
String samIdStr = new String(samId, "GBK").trim();
|
||||
result.success(samIdStr);
|
||||
} else {
|
||||
result.error("GET_SAM_ID_FAILED", "Failed to get SAM ID string, error code: " + ret, null);
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Error getting SAM ID string", e);
|
||||
result.error("ERROR", "Failed to get SAM ID string: " + e.getMessage(), null);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) {
|
||||
channel.setMethodCallHandler(null);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package com.example.idcard;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.hardware.usb.UsbDevice;
|
||||
import android.hardware.usb.UsbManager;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
|
||||
/**
|
||||
* USB权限处理Activity
|
||||
* 用于处理Android 12+的USB权限请求
|
||||
*/
|
||||
public class UsbPermissionActivity extends Activity {
|
||||
private static final String TAG = "UsbPermissionActivity";
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
Intent intent = getIntent();
|
||||
String action = intent.getAction();
|
||||
|
||||
if (UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(action)) {
|
||||
UsbDevice device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
|
||||
if (device != null) {
|
||||
Log.d(TAG, "USB设备已连接: " + device.getDeviceName());
|
||||
Log.d(TAG, "VID: " + device.getVendorId() + ", PID: " + device.getProductId());
|
||||
|
||||
// 通知插件USB设备已连接
|
||||
Intent broadcastIntent = new Intent("com.example.idcard.USB_DEVICE_ATTACHED");
|
||||
broadcastIntent.putExtra(UsbManager.EXTRA_DEVICE, device);
|
||||
sendBroadcast(broadcastIntent);
|
||||
}
|
||||
}
|
||||
|
||||
// 完成后关闭Activity
|
||||
finish();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,170 @@
|
||||
package com.sdses;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
import android.bluetooth.BluetoothAdapter;
|
||||
import android.bluetooth.BluetoothDevice;
|
||||
import android.bluetooth.BluetoothSocket;
|
||||
|
||||
public class BlueTooth
|
||||
{
|
||||
private static UUID SS_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
|
||||
private static BluetoothAdapter mAdapter = null;
|
||||
private static BluetoothDevice mDevice = null;
|
||||
private static BluetoothSocket mSocket = null;
|
||||
private static InputStream mInputStream = null;
|
||||
private static OutputStream mOutputStream = null;
|
||||
|
||||
public static long BthConnect(String BlueToothName)
|
||||
{
|
||||
mAdapter = BluetoothAdapter.getDefaultAdapter();
|
||||
if (mAdapter == null)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!mAdapter.isEnabled())
|
||||
{
|
||||
return -2;
|
||||
/*
|
||||
mAdapter.enable();
|
||||
if (!mAdapter.isEnabled())
|
||||
{
|
||||
return -2;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
//获得已配对的蓝牙设备列表
|
||||
Set<BluetoothDevice> pairedDevices = mAdapter.getBondedDevices();
|
||||
if(pairedDevices.size() <= 0)
|
||||
{
|
||||
return -3;
|
||||
}
|
||||
|
||||
ArrayList<BluetoothDevice> ALBluetoothDevice = new ArrayList<BluetoothDevice>();
|
||||
for (BluetoothDevice device : pairedDevices)
|
||||
{
|
||||
ALBluetoothDevice.add(device);
|
||||
}
|
||||
|
||||
//mAdapter.cancelDiscovery();
|
||||
|
||||
//查找设备
|
||||
for(int i = 0; i < ALBluetoothDevice.size(); i++)
|
||||
{
|
||||
BluetoothDevice cDevice = (BluetoothDevice)ALBluetoothDevice.get(i);
|
||||
String theBlueToothName = cDevice.getName();
|
||||
if(theBlueToothName.indexOf(BlueToothName) < 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
//开始连接设备
|
||||
mDevice = cDevice;
|
||||
try
|
||||
{
|
||||
mSocket = mDevice.createRfcommSocketToServiceRecord(SS_UUID);
|
||||
mSocket.connect();
|
||||
mInputStream = mSocket.getInputStream();
|
||||
mOutputStream = mSocket.getOutputStream();
|
||||
return 0;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return -4;
|
||||
}
|
||||
}
|
||||
|
||||
return -5; //没有配对设备
|
||||
}
|
||||
|
||||
public static long BthSendSocket(byte[] buffer, int len)
|
||||
{
|
||||
if(mOutputStream == null)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
mOutputStream.write(buffer, 0, len);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
return -2;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
public static long BthRecvSocket(byte[] buffer)
|
||||
{
|
||||
if(mInputStream == null)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// int nAvailable = mInputStream.available();
|
||||
// if(nAvailable <= 0)
|
||||
// {
|
||||
// return 0;
|
||||
// }
|
||||
|
||||
return mInputStream.read(buffer, 0, 4096);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
return -2;
|
||||
}
|
||||
}
|
||||
|
||||
public static void BthDisconnect()
|
||||
{
|
||||
if(mInputStream != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
mInputStream.close();
|
||||
mInputStream = null;
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if(mOutputStream != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
mOutputStream.close();
|
||||
mOutputStream = null;
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if(mSocket != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
mSocket.close();
|
||||
mSocket = null;
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
package com.sdses;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
public class JniCommonInterface
|
||||
{
|
||||
static
|
||||
{
|
||||
System.loadLibrary("WltRS");
|
||||
System.loadLibrary("PortCommunication");
|
||||
System.loadLibrary("TerminalProtocol");
|
||||
System.loadLibrary("CommonInterface");
|
||||
}
|
||||
|
||||
public static long GetUsbPermission(Context ctx, int Vid, int Pid)
|
||||
{
|
||||
return UsbHidPort.GetUsbPermission(ctx, Vid, Pid);
|
||||
}
|
||||
|
||||
public static native long SetLogFileEx(String LogFileName);
|
||||
public static native long SetTerminalLibrary(String LibraryFileName);
|
||||
public static native long GetLibraryInfo(byte[] Version, byte[] Description);
|
||||
public static native long SetAutoPara(String PortType, String PortPara, String ExtendPara, String DllName, int UsingGA467);
|
||||
public static native long OpenDevice(String PortType, String PortPara, String ExtendPara);
|
||||
public static native long SetCurrentDevice(long DevHandle);
|
||||
public static native long GetCurrentDevice();
|
||||
public static native long CloseDevice();
|
||||
public static native long CommandTransmit(long Command, long CmdDataLength, byte[] CmdData, byte[] StatusWords, long[] RecvDataLength, byte[] RecvData, long TimeOut);
|
||||
public static native long GA467Transmit(long Command, long CmdDataLength, byte[] CmdData, byte[] StatusWords, long[] RecvDataLength, byte[] RecvData, long TimeOut);
|
||||
public static native long GetTerminalModel(byte[] TerminalModel);
|
||||
public static native long GetTerminalFirmVersion(byte[] FirmVersion, byte[]HardwareVersion);
|
||||
public static native long GetTerminalSn(byte[] TerminalSn);
|
||||
public static native long TerminalHeartBeat();
|
||||
public static native long LedOnOff(byte LedNo, byte OnOff);
|
||||
public static native long LedBlink(byte LedNo, long OnTimeMs, long OffTimeMs, byte BlinkCount, byte FinalState);
|
||||
public static native long GetLastRecvData(byte[] LastRecvData, long[] LastRecvDataLen);
|
||||
|
||||
public static native long IdFindCard();
|
||||
public static native long IdSelectCard();
|
||||
public static native long IdReadBaseMsg(byte[] pucCHMsg, long[] puiCHMsgLen, byte[] pucPHMsg, long[] puiPHMsgLen);
|
||||
public static native long IdReadBaseFpMsg(byte[] pucCHMsg, long[] puiCHMsgLen, byte[] pucPHMsg, long[] puiPHMsgLen, byte[] pucFPMsg, long[] puiFPMsgLen);
|
||||
public static native long IdReadNewAppMsg(byte[] pucAppMsg, long[] puiAppMsgLen);
|
||||
public static native long IdReadSn(byte[] SN, long[] SNLen);
|
||||
public static native long IdApdu(long SendApduLen, byte[] SendApdu, byte[] RecvApdu, long[] RecvApduLen);
|
||||
public static native long SdtFindCard(byte[] pucManaInfo);
|
||||
public static native long SdtSelectCard(byte[] pucManaMsg);
|
||||
public static native long SdtReadBaseMsg(byte[] pucCHMsg, long[] puiCHMsgLen, byte[] pucPHMsg, long[] puiPHMsgLen);
|
||||
public static native long SdtReadBaseFpMsg(byte[] pucCHMsg, long[] puiCHMsgLen, byte[] pucPHMsg, long[] puiPHMsgLen, byte[] pucFPMsg, long[] puiFPMsgLen);
|
||||
public static native long SdtReadNewAppMsg(byte[] pucAppMsg, long[] puiAppMsgLen);
|
||||
public static native long GetSamStatus();
|
||||
public static native long GetSamId(byte[] SamId, long[] SamIdLen);
|
||||
public static native long GetSamIdStr(byte[] SamIdStr);
|
||||
public static native long SamGetStatus();
|
||||
public static native long SamGetId(byte[] SamId, long[] SamIdLen);
|
||||
public static native long SamGetIdStr(byte[] SamIdStr);
|
||||
public static native long SdtSamGetStatus();
|
||||
public static native long SdtSamGetId(byte[] SamId, long[] SamIdLen);
|
||||
public static native long SdtSamGetIdStr(byte[] SamIdStr);
|
||||
|
||||
public static native long IdReadCard(byte CardType, byte InfoEncoding, byte[] IdCardInfo, long TimeOutMs);
|
||||
public static native long SdtReadCard(byte CardType, byte InfoEncoding, byte[] IdCardInfo, long TimeOutMs);
|
||||
public static native long IdReadNewAddress(byte[] NewAddress);
|
||||
public static native long SdtReadNewAddress(byte[] NewAddress);
|
||||
public static native long IdCardGetName(byte[] Name);
|
||||
public static native long IdCardGetNameEn(byte[] NameEn);
|
||||
public static native long IdCardGetGender(byte[] Gender);
|
||||
public static native long IdCardGetGenderId(byte[] GenderId);
|
||||
public static native long IdCardGetNation(byte[] Nation);
|
||||
public static native long IdCardGetNationId(byte[] NationId);
|
||||
public static native long IdCardGetBirthDate(byte[] BirthDate);
|
||||
public static native long IdCardGetAddress(byte[] Address);
|
||||
public static native long IdCardGetIdNumber(byte[] IdNumber);
|
||||
public static native long IdCardGetSignOrgan(byte[] SignOrgan);
|
||||
public static native long IdCardGetBeginTerm(byte[] BeginTerm);
|
||||
public static native long IdCardGetValidTerm(byte[] ValidTerm);
|
||||
public static native long IdCardGetFPBuffer(byte[] FPBuffer, long[] FPBufferLen);
|
||||
public static native long IdCardGetPhotoFile(String PhotoFile);
|
||||
public static native long IdCardGetPhotoBuffer(byte WltBmpJpg, byte[] PhotoBuffer, long[] PhotoBufferLen);
|
||||
|
||||
public static native long MIdSamGetCert(byte[] Cert, long[] CertLen);
|
||||
public static native long MIdSamEnable(long EnableDataLen, byte[] EnableData);
|
||||
public static native long MIdSamDisable(long DisableDataLen, byte[] DisableData);
|
||||
public static native long MIdSamGetEnableState(byte[] EnableState, long[] RemainNum, byte[] EnableTime, byte[] DisableTime, byte[] SecondCert, long[] SecondCertLen, byte[] EncryptCert, long[] EncryptCertLen, byte[] SignCert, long[] SignCertLen);
|
||||
public static native long MIdSamAuthRequest(byte[] RequestData56);
|
||||
public static native long MIdSamAuthConfirm(byte[] ConfirmData89);
|
||||
public static native long MIdReadChkData(byte[] Random16, byte[] RemainAuthNum, byte[] SamId22, byte[] BeginAndValidTerm32, byte[] ShortCode16, byte[] CheckData, long[] CheckDataLen, byte[] Sign64);
|
||||
public static native long MIdReadChkDataPF(byte[] Random16, byte[] RemainAuthNum, byte[] SamId22, byte[] BeginAndValidTerm32, byte[] ShortCode16, byte[] CheckData, long[] CheckDataLen, byte[] Hash32, byte[] Sign64, byte[] PH, long[] PHLen, byte[] FP, long[] FPLen);
|
||||
public static native long MIdCheckShortLongCode(byte[] Random16, byte ShortCodeCount, byte[] ShortCode, byte LongCodeCount, byte[] LongCode, byte[] RemainAuthNum, byte[] SamId22, byte[] BeginAndValidTerm32, byte[] MatchCode, byte[] MatchCodeLen, byte[] CheckData, long[] CheckDataLen, byte[] Sign64);
|
||||
public static native long MIdCheckShortLongCodePF(byte[] Random16, byte ShortCodeCount, byte[] ShortCode, byte LongCodeCount, byte[] LongCode, byte[] RemainAuthNum, byte[] SamId22,byte[] BeginAndValidTerm32, byte[] MatchCode, byte[] MatchCodeLen, byte[] CheckData, long[] CheckDataLen, byte[] Hash32, byte[] Sign64, byte[] PH, long[] PHLen, byte[] FP, long[] FPLen);
|
||||
public static native long MIdCheckProperty(byte[] Random16, byte PropertyCode, byte PropertyValLen, byte[] PropertyVal, byte[] RemainAuthNum, byte[] SamId22, byte[] CheckResult, byte[] CheckData, long[] CheckDataLen, byte[] Sign64);
|
||||
|
||||
public static native long MagRead(byte Tracks, byte[] TrackData1, byte[] TrackData2, byte[] TrackData3, byte TimeOutSec);
|
||||
public static native long MagWrite(byte Tracks, String TrackData1, String TrackData2, String TrackData3, byte TimeOutSec);
|
||||
|
||||
public static native long QrRead(byte[] QrData, byte TimeOutSec);
|
||||
public static native long QrCancel();
|
||||
public static native long QrAsynEnable(byte TimeOutSec);
|
||||
public static native long QrAsynRead(byte[] QrData);
|
||||
public static native long QrAsynDisable();
|
||||
|
||||
public static native long M1FindCard(byte[] UID, long[] UIDLen);
|
||||
public static native long M1Authentication(byte KeyType, byte SecAddr, byte[] Key, byte[] UID);
|
||||
public static native long M1ReadBlock(byte BlockAddr, byte[] BlockData, long[] BlockDataLen);
|
||||
public static native long M1WriteBlock(byte BlockAddr, long BlockDataLen, byte[] BlockData);
|
||||
public static native long M1Halt();
|
||||
|
||||
public static native long FpCapFeature(byte[] Feature, long[] FeatureLen);
|
||||
public static native long FpMatchFeature(long FeatureLen1, byte[] Feature1, long FeatureLen2, byte[] Feature2, long[] Score);
|
||||
|
||||
public static native long SsseReadCard(int iType, byte[] SSCardInfo, byte[] SSErrorInfo);
|
||||
public static native long SsseReadCard2(int iType, byte[] SSCardInfo, byte[] SSErrorInfo);
|
||||
public static native long SsseGetCardInfo(String Tag, byte[] SSCardInfo);
|
||||
|
||||
public static native long CpuPowerOn(byte Slot, byte[] ATRS, long[] ATRSLen);
|
||||
public static native long CpuApdu(byte Slot, long SendApduLen, byte[] SendApdu, byte[] RecvApdu, long[] RecvApduLen);
|
||||
public static native long CpuPowerOff(byte Slot);
|
||||
|
||||
public static native long IccGetCardInfo(int ICtype, String AIDList, String TagList, byte[] IcCardInfo);
|
||||
public static native long IccGetARQC(int ICtype, String trData, String AIDList, byte[] ARQC, byte[] trAppData);
|
||||
public static native long IccARPCExeScript(int ICtype, String trData, String ARPC, String trAppData, byte[] ScriptResult, byte[] TC);
|
||||
public static native long IccGetTrDetail(int ICtype, String AIDList, byte[] TrDetail);
|
||||
public static native long IccGetLoadDetail(int ICtype, String AIDList, byte[] LoadDetail);
|
||||
|
||||
public static native long HexToAsc(byte[] Hex, long HexLength, byte[] Asc);
|
||||
public static native long AscToHex(String Asc, long HexLength, byte[] Hex);
|
||||
}
|
||||
@@ -0,0 +1,300 @@
|
||||
package com.sdses;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
|
||||
import android.app.PendingIntent;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.hardware.usb.UsbConstants;
|
||||
import android.hardware.usb.UsbDevice;
|
||||
import android.hardware.usb.UsbDeviceConnection;
|
||||
import android.hardware.usb.UsbEndpoint;
|
||||
import android.hardware.usb.UsbInterface;
|
||||
import android.hardware.usb.UsbManager;
|
||||
import android.os.Build;
|
||||
|
||||
public class UsbHidPort
|
||||
{
|
||||
private static final String ACTION_USB_PERMISSION = "com.sdses.JniCommonInterface.USB_PERMISSION";
|
||||
|
||||
private static final BroadcastReceiver mUsbReceiver = new BroadcastReceiver()
|
||||
{
|
||||
public void onReceive(Context context, Intent intent)
|
||||
{
|
||||
String action = intent.getAction();
|
||||
if (action.equals(ACTION_USB_PERMISSION))
|
||||
{
|
||||
synchronized (this)
|
||||
{
|
||||
UsbDevice device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
|
||||
if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false))
|
||||
{
|
||||
if (device != null)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
public static UsbManager usbManager = null;
|
||||
public static UsbDevice usbDevice = null;
|
||||
public static UsbInterface usbInterface = null;
|
||||
public static UsbDeviceConnection usbConnection = null;
|
||||
public static UsbEndpoint epOut;
|
||||
public static UsbEndpoint epIn;
|
||||
public static int SendBlockSize = 0;
|
||||
public static int RecvBlockSize = 0;
|
||||
|
||||
public static synchronized long GetUsbPermission(Context ctx, int Vid, int Pid)
|
||||
{
|
||||
try
|
||||
{
|
||||
usbManager = (UsbManager)ctx.getSystemService(Context.USB_SERVICE);
|
||||
HashMap<String, UsbDevice> deviceList = usbManager.getDeviceList();
|
||||
Iterator<UsbDevice> deviceIterator = deviceList.values().iterator();
|
||||
|
||||
usbDevice = null;
|
||||
while (deviceIterator.hasNext())
|
||||
{
|
||||
UsbDevice device = deviceIterator.next();
|
||||
if ((device.getVendorId() == Vid) && (device.getProductId() == Pid))
|
||||
{
|
||||
usbDevice = device;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (usbDevice == null)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(usbDevice.getInterfaceCount() <= 0)
|
||||
{
|
||||
return -2;
|
||||
}
|
||||
|
||||
usbInterface = usbDevice.getInterface(0);
|
||||
if(usbInterface == null)
|
||||
{
|
||||
return -2;
|
||||
}
|
||||
|
||||
// 判断是否有权限
|
||||
if(!usbManager.hasPermission(usbDevice))
|
||||
{
|
||||
// Android 12+ 需要明确指定 PendingIntent 的 flag
|
||||
int flags = 0;
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||
flags = PendingIntent.FLAG_IMMUTABLE;
|
||||
}
|
||||
PendingIntent mPermissionIntent = PendingIntent.getBroadcast(ctx, 0, new Intent(ACTION_USB_PERMISSION), flags);
|
||||
IntentFilter permissionFilter = new IntentFilter(ACTION_USB_PERMISSION);
|
||||
ctx.registerReceiver(mUsbReceiver, permissionFilter);
|
||||
usbManager.requestPermission(usbDevice, mPermissionIntent);
|
||||
System.out.print("Requesting Usb Permission");
|
||||
|
||||
// 等待权限授权,最多等待10秒
|
||||
int waitCount = 0;
|
||||
while(!usbManager.hasPermission(usbDevice) && waitCount < 100)
|
||||
{
|
||||
try {
|
||||
Thread.sleep(100); // 等待100ms
|
||||
waitCount++;
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 清理广播接收器
|
||||
try {
|
||||
ctx.unregisterReceiver(mUsbReceiver);
|
||||
} catch (Exception e) {
|
||||
// 忽略取消注册时的异常
|
||||
}
|
||||
|
||||
// 检查是否获得权限
|
||||
if (!usbManager.hasPermission(usbDevice)) {
|
||||
return -3; // 权限请求失败或超时
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
ex.printStackTrace();
|
||||
return -99;
|
||||
}
|
||||
}
|
||||
|
||||
public static long UsbOpenPort(int Vid, int Pid)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (usbDevice == null)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
usbConnection = usbManager.openDevice(usbDevice);
|
||||
if(usbConnection == null)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(usbInterface == null)
|
||||
{
|
||||
return -2;
|
||||
}
|
||||
|
||||
if(!usbConnection.claimInterface(usbInterface, true))
|
||||
{
|
||||
usbConnection.close();
|
||||
usbConnection = null;
|
||||
return -2;
|
||||
}
|
||||
|
||||
for(int i = 0; i < usbInterface.getEndpointCount(); i++)
|
||||
{
|
||||
UsbEndpoint endPoint = usbInterface.getEndpoint(i);
|
||||
switch(endPoint.getType())
|
||||
{
|
||||
case UsbConstants.USB_ENDPOINT_XFER_BULK:
|
||||
case UsbConstants.USB_ENDPOINT_XFER_INT:
|
||||
{
|
||||
switch(endPoint.getDirection())
|
||||
{
|
||||
case UsbConstants.USB_DIR_OUT:
|
||||
{
|
||||
epOut = endPoint;
|
||||
break;
|
||||
}
|
||||
case UsbConstants.USB_DIR_IN:
|
||||
{
|
||||
epIn = endPoint;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case UsbConstants.USB_ENDPOINT_XFER_CONTROL:
|
||||
{
|
||||
epOut = endPoint;
|
||||
epIn = endPoint;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SendBlockSize = epOut.getMaxPacketSize();
|
||||
RecvBlockSize = epIn.getMaxPacketSize();
|
||||
|
||||
return SendBlockSize;
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
ex.printStackTrace();
|
||||
return -99;
|
||||
}
|
||||
}
|
||||
|
||||
public static long UsbWrite(byte[] buffer, int len, int timeout)
|
||||
{
|
||||
try
|
||||
{
|
||||
return usbConnection.bulkTransfer(epOut, buffer, SendBlockSize, timeout);
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
ex.printStackTrace();
|
||||
return -99;
|
||||
}
|
||||
}
|
||||
|
||||
public static long UsbRead(byte[] buffer, int timeout)
|
||||
{
|
||||
/*
|
||||
try
|
||||
{
|
||||
Thread.sleep(10);
|
||||
}
|
||||
catch (InterruptedException e)
|
||||
{
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
*/
|
||||
|
||||
try
|
||||
{
|
||||
return usbConnection.bulkTransfer(epIn, buffer, RecvBlockSize, timeout);
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
ex.printStackTrace();
|
||||
return -99;
|
||||
}
|
||||
}
|
||||
|
||||
public static long UsbCtrlWrite(byte[] buffer, int len, int timeout)
|
||||
{
|
||||
try
|
||||
{
|
||||
return usbConnection.controlTransfer(0x21, 0x09, 0x0200, 0x0000, buffer, SendBlockSize, timeout);
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
ex.printStackTrace();
|
||||
return -99;
|
||||
}
|
||||
}
|
||||
|
||||
public static long UsbCtrlRead(byte[] buffer, int timeout)
|
||||
{
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
Thread.sleep(10);
|
||||
}
|
||||
catch (InterruptedException e)
|
||||
{
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return usbConnection.controlTransfer(0xA1, 0x01, 0x0100, 0x0000, buffer, RecvBlockSize, timeout);
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
ex.printStackTrace();
|
||||
return -99;
|
||||
}
|
||||
}
|
||||
|
||||
public static void UsbClosePort()
|
||||
{
|
||||
try
|
||||
{
|
||||
usbConnection.releaseInterface(usbInterface);
|
||||
usbConnection.close();
|
||||
usbConnection = null;
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<!-- 身份证读卡器设备过滤器 -->
|
||||
<!-- 可以根据实际设备的VID/PID进行配置 -->
|
||||
<usb-device vendor-id="1234" product-id="5678" />
|
||||
|
||||
<!-- 通用HID设备过滤器 -->
|
||||
<usb-device class="3" subclass="0" protocol="0" />
|
||||
|
||||
<!-- 如果知道具体的设备VID/PID,可以添加更多配置 -->
|
||||
|
||||
<usb-device vendor-id="1024" product-id="50010" />
|
||||
|
||||
</resources>
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.example.idcard;
|
||||
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import io.flutter.plugin.common.MethodCall;
|
||||
import io.flutter.plugin.common.MethodChannel;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* This demonstrates a simple unit test of the Java portion of this plugin's implementation.
|
||||
*
|
||||
* Once you have built the plugin's example app, you can run these tests from the command
|
||||
* line by running `./gradlew testDebugUnitTest` in the `example/android/` directory, or
|
||||
* you can run them directly from IDEs that support JUnit such as Android Studio.
|
||||
*/
|
||||
|
||||
public class IdcardPluginTest {
|
||||
@Test
|
||||
public void onMethodCall_getPlatformVersion_returnsExpectedValue() {
|
||||
IdcardPlugin plugin = new IdcardPlugin();
|
||||
|
||||
final MethodCall call = new MethodCall("getPlatformVersion", null);
|
||||
MethodChannel.Result mockResult = mock(MethodChannel.Result.class);
|
||||
plugin.onMethodCall(call, mockResult);
|
||||
|
||||
verify(mockResult).success("Android " + android.os.Build.VERSION.RELEASE);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user