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

View 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>

View 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);
}
}

View File

@@ -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();
}
}

View 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;
}
}
}
}

View 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);
}

View 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();
}
}
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

View 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>

View File

@@ -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);
}
}