init
This commit is contained in:
32
android/src/main/AndroidManifest.xml
Normal file
32
android/src/main/AndroidManifest.xml
Normal file
@@ -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>
|
||||
642
android/src/main/java/com/example/idcard/IdcardPlugin.java
Normal file
642
android/src/main/java/com/example/idcard/IdcardPlugin.java
Normal file
@@ -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();
|
||||
}
|
||||
}
|
||||
170
android/src/main/java/com/sdses/BlueTooth.java
Normal file
170
android/src/main/java/com/sdses/BlueTooth.java
Normal file
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
126
android/src/main/java/com/sdses/JniCommonInterface.java
Normal file
126
android/src/main/java/com/sdses/JniCommonInterface.java
Normal file
@@ -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);
|
||||
}
|
||||
300
android/src/main/java/com/sdses/UsbHidPort.java
Normal file
300
android/src/main/java/com/sdses/UsbHidPort.java
Normal file
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
BIN
android/src/main/jniLibs/arm64-v8a/libCommonInterface.so
Normal file
BIN
android/src/main/jniLibs/arm64-v8a/libCommonInterface.so
Normal file
Binary file not shown.
BIN
android/src/main/jniLibs/arm64-v8a/libPortCommunication.so
Normal file
BIN
android/src/main/jniLibs/arm64-v8a/libPortCommunication.so
Normal file
Binary file not shown.
BIN
android/src/main/jniLibs/arm64-v8a/libTerminalProtocol.so
Normal file
BIN
android/src/main/jniLibs/arm64-v8a/libTerminalProtocol.so
Normal file
Binary file not shown.
BIN
android/src/main/jniLibs/arm64-v8a/libWltRS.so
Normal file
BIN
android/src/main/jniLibs/arm64-v8a/libWltRS.so
Normal file
Binary file not shown.
BIN
android/src/main/jniLibs/armeabi/libCommonInterface.so
Normal file
BIN
android/src/main/jniLibs/armeabi/libCommonInterface.so
Normal file
Binary file not shown.
BIN
android/src/main/jniLibs/armeabi/libPortCommunication.so
Normal file
BIN
android/src/main/jniLibs/armeabi/libPortCommunication.so
Normal file
Binary file not shown.
BIN
android/src/main/jniLibs/armeabi/libTerminalProtocol.so
Normal file
BIN
android/src/main/jniLibs/armeabi/libTerminalProtocol.so
Normal file
Binary file not shown.
BIN
android/src/main/jniLibs/armeabi/libWltRS.so
Normal file
BIN
android/src/main/jniLibs/armeabi/libWltRS.so
Normal file
Binary file not shown.
14
android/src/main/res/xml/device_filter.xml
Normal file
14
android/src/main/res/xml/device_filter.xml
Normal file
@@ -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