This commit is contained in:
2026-04-13 16:03:06 +08:00
parent e9f4844352
commit dc30881d38
4 changed files with 115 additions and 16 deletions

View File

@@ -15,6 +15,7 @@ import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel; import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.common.MethodChannel.MethodCallHandler; import io.flutter.plugin.common.MethodChannel.MethodCallHandler;
import io.flutter.plugin.common.MethodChannel.Result; import io.flutter.plugin.common.MethodChannel.Result;
import io.flutter.plugin.common.EventChannel;
import android.os.SystemClock; import android.os.SystemClock;
@@ -32,6 +33,7 @@ public class ZhiwenPlugin implements FlutterPlugin, MethodCallHandler, ActivityA
// 常量定义 // 常量定义
private static final String TAG = "ZhiwenPlugin"; private static final String TAG = "ZhiwenPlugin";
private static final String CHANNEL_NAME = "zhiwen"; private static final String CHANNEL_NAME = "zhiwen";
private static final String EVENT_CHANNEL_NAME = "zhiwen_progress";
private static final int DEFAULT_MAX_FP_COUNT = 3000; private static final int DEFAULT_MAX_FP_COUNT = 3000;
private static final int ENROLL_STEP_COUNT = 3; private static final int ENROLL_STEP_COUNT = 3;
private static final int IMAGE_BUFFER_SIZE = 1024 * 100; private static final int IMAGE_BUFFER_SIZE = 1024 * 100;
@@ -45,6 +47,10 @@ public class ZhiwenPlugin implements FlutterPlugin, MethodCallHandler, ActivityA
/// 用于注册插件到Flutter引擎并在Activity分离时注销 /// 用于注册插件到Flutter引擎并在Activity分离时注销
private MethodChannel channel; private MethodChannel channel;
/// 进度事件通道用于向Flutter发送指纹录入进度
private EventChannel progressEventChannel;
private EventChannel.EventSink progressEventSink;
// 设备通信对象使用static确保全局唯一 // 设备通信对象使用static确保全局唯一
private static DevComm m_devComm; private static DevComm m_devComm;
@@ -60,12 +66,28 @@ public class ZhiwenPlugin implements FlutterPlugin, MethodCallHandler, ActivityA
/** /**
* 插件附加到Flutter引擎时的回调 * 插件附加到Flutter引擎时的回调
* 初始化MethodChannel并设置方法调用处理器 * 初始化MethodChannel和EventChannel并设置方法调用处理器
*/ */
@Override @Override
public void onAttachedToEngine(@NonNull FlutterPluginBinding flutterPluginBinding) { public void onAttachedToEngine(@NonNull FlutterPluginBinding flutterPluginBinding) {
channel = new MethodChannel(flutterPluginBinding.getBinaryMessenger(), CHANNEL_NAME); channel = new MethodChannel(flutterPluginBinding.getBinaryMessenger(), CHANNEL_NAME);
channel.setMethodCallHandler(this); channel.setMethodCallHandler(this);
// 初始化进度事件通道
progressEventChannel = new EventChannel(flutterPluginBinding.getBinaryMessenger(), EVENT_CHANNEL_NAME);
progressEventChannel.setStreamHandler(new EventChannel.StreamHandler() {
@Override
public void onListen(Object arguments, EventChannel.EventSink events) {
progressEventSink = events;
Log.d(TAG, "进度事件监听已启动");
}
@Override
public void onCancel(Object arguments) {
progressEventSink = null;
Log.d(TAG, "进度事件监听已取消");
}
});
// 注意这里不应该从ApplicationContext获取Activity应该等待onAttachedToActivity回调 // 注意这里不应该从ApplicationContext获取Activity应该等待onAttachedToActivity回调
} }
@@ -292,22 +314,27 @@ public class ZhiwenPlugin implements FlutterPlugin, MethodCallHandler, ActivityA
final int[] imageHeight = new int[1]; final int[] imageHeight = new int[1];
try { try {
// 发送开始录入进度事件
sendProgressEvent(0, ENROLL_STEP_COUNT, "请准备放置手指");
// 录入指定次数的指纹 // 录入指定次数的指纹
while (enrollStep < ENROLL_STEP_COUNT) { while (enrollStep < ENROLL_STEP_COUNT) {
Log.d(TAG, String.format("请放置手指进行第%d次录入", enrollStep + 1)); Log.d(TAG, String.format("请放置手指进行第%d次录入", enrollStep + 1));
// 显示提示信息 // 发送进度事件到Flutter
showToastOnMainThread(String.format("请放置手指 (%d/%d)", enrollStep + 1, ENROLL_STEP_COUNT)); sendProgressEvent(enrollStep + 1, ENROLL_STEP_COUNT,
String.format("请放置手指 (%d/%d)", enrollStep + 1, ENROLL_STEP_COUNT));
// 采集指纹图像 // 采集指纹图像
if (captureFingerprint() < 0) { if (captureFingerprint() < 0) {
sendProgressEvent(-1, ENROLL_STEP_COUNT, "指纹采集失败");
Map<String, Object> errorResult = createErrorResponse("指纹采集失败"); Map<String, Object> errorResult = createErrorResponse("指纹采集失败");
mainHandler.post(() -> result.success(errorResult)); mainHandler.post(() -> result.success(errorResult));
return; return;
} }
Log.d(TAG, "请移开手指"); Log.d(TAG, "请移开手指");
showToastOnMainThread("请移开手指"); sendProgressEvent(enrollStep + 1, ENROLL_STEP_COUNT, "请移开手指");
// 上传指纹图像仅USB模式 // 上传指纹图像仅USB模式
if (m_devComm.m_nConnected == 2) { if (m_devComm.m_nConnected == 2) {
@@ -315,6 +342,7 @@ public class ZhiwenPlugin implements FlutterPlugin, MethodCallHandler, ActivityA
if (uploadResult != DevComm.ERR_SUCCESS) { if (uploadResult != DevComm.ERR_SUCCESS) {
String errorMsg = GetErrorMsg(uploadResult); String errorMsg = GetErrorMsg(uploadResult);
Log.e(TAG, "上传指纹图像失败: " + errorMsg); Log.e(TAG, "上传指纹图像失败: " + errorMsg);
sendProgressEvent(-1, ENROLL_STEP_COUNT, "上传图像失败: " + errorMsg);
Map<String, Object> errorResult = createErrorResponse(errorMsg); Map<String, Object> errorResult = createErrorResponse(errorMsg);
mainHandler.post(() -> result.success(errorResult)); mainHandler.post(() -> result.success(errorResult));
return; return;
@@ -326,11 +354,12 @@ public class ZhiwenPlugin implements FlutterPlugin, MethodCallHandler, ActivityA
if (generateResult != DevComm.ERR_SUCCESS) { if (generateResult != DevComm.ERR_SUCCESS) {
if (generateResult == DevComm.ERR_BAD_QUALITY) { if (generateResult == DevComm.ERR_BAD_QUALITY) {
Log.w(TAG, "指纹质量不佳,请重试"); Log.w(TAG, "指纹质量不佳,请重试");
showToastOnMainThread("指纹质量不佳,请重试"); sendProgressEvent(enrollStep + 1, ENROLL_STEP_COUNT, "指纹质量不佳,请重试");
continue; // 重试当前步骤 continue; // 重试当前步骤
} else { } else {
String errorMsg = GetErrorMsg(generateResult); String errorMsg = GetErrorMsg(generateResult);
Log.e(TAG, "生成指纹特征失败: " + errorMsg); Log.e(TAG, "生成指纹特征失败: " + errorMsg);
sendProgressEvent(-1, ENROLL_STEP_COUNT, "生成特征失败: " + errorMsg);
Map<String, Object> errorResult = createErrorResponse(errorMsg); Map<String, Object> errorResult = createErrorResponse(errorMsg);
mainHandler.post(() -> result.success(errorResult)); mainHandler.post(() -> result.success(errorResult));
return; return;
@@ -340,18 +369,25 @@ public class ZhiwenPlugin implements FlutterPlugin, MethodCallHandler, ActivityA
enrollStep++; enrollStep++;
} }
// 发送合并进度事件
sendProgressEvent(ENROLL_STEP_COUNT, ENROLL_STEP_COUNT, "正在合并指纹特征...");
// 合并多次录入的特征如果录入次数大于1 // 合并多次录入的特征如果录入次数大于1
if (ENROLL_STEP_COUNT > 1) { if (ENROLL_STEP_COUNT > 1) {
int mergeResult = m_devComm.Run_Merge(0, ENROLL_STEP_COUNT); int mergeResult = m_devComm.Run_Merge(0, ENROLL_STEP_COUNT);
if (mergeResult != DevComm.ERR_SUCCESS) { if (mergeResult != DevComm.ERR_SUCCESS) {
String errorMsg = GetErrorMsg(mergeResult); String errorMsg = GetErrorMsg(mergeResult);
Log.e(TAG, "合并指纹特征失败: " + errorMsg); Log.e(TAG, "合并指纹特征失败: " + errorMsg);
sendProgressEvent(-1, ENROLL_STEP_COUNT, "合并失败: " + errorMsg);
Map<String, Object> errorResult = createErrorResponse(errorMsg); Map<String, Object> errorResult = createErrorResponse(errorMsg);
mainHandler.post(() -> result.success(errorResult)); mainHandler.post(() -> result.success(errorResult));
return; return;
} }
} }
// 发送存储进度事件
sendProgressEvent(ENROLL_STEP_COUNT, ENROLL_STEP_COUNT, "正在存储指纹模板...");
// 存储指纹模板 // 存储指纹模板
int storeResult = m_devComm.Run_StoreChar(userId, 0, duplicateId); int storeResult = m_devComm.Run_StoreChar(userId, 0, duplicateId);
if (storeResult != DevComm.ERR_SUCCESS) { if (storeResult != DevComm.ERR_SUCCESS) {
@@ -362,6 +398,7 @@ public class ZhiwenPlugin implements FlutterPlugin, MethodCallHandler, ActivityA
errorMsg = GetErrorMsg(storeResult); errorMsg = GetErrorMsg(storeResult);
} }
Log.e(TAG, "存储指纹模板失败: " + errorMsg); Log.e(TAG, "存储指纹模板失败: " + errorMsg);
sendProgressEvent(-1, ENROLL_STEP_COUNT, "存储失败: " + errorMsg);
Map<String, Object> errorResult = createErrorResponse(errorMsg); Map<String, Object> errorResult = createErrorResponse(errorMsg);
mainHandler.post(() -> result.success(errorResult)); mainHandler.post(() -> result.success(errorResult));
return; return;
@@ -369,15 +406,16 @@ public class ZhiwenPlugin implements FlutterPlugin, MethodCallHandler, ActivityA
// 录入成功 // 录入成功
Log.i(TAG, String.format("指纹录入成功用户ID: %d", userId)); Log.i(TAG, String.format("指纹录入成功用户ID: %d", userId));
sendProgressEvent(ENROLL_STEP_COUNT, ENROLL_STEP_COUNT, "指纹录入成功");
Map<String, Object> successResult = createSuccessResponse("指纹录入成功"); Map<String, Object> successResult = createSuccessResponse("指纹录入成功");
successResult.put("userId", userId); successResult.put("userId", userId);
mainHandler.post(() -> { mainHandler.post(() -> {
showToastOnMainThread("指纹录入成功");
result.success(successResult); result.success(successResult);
}); });
} catch (Exception e) { } catch (Exception e) {
Log.e(TAG, "指纹录入过程中发生异常: " + e.getMessage(), e); Log.e(TAG, "指纹录入过程中发生异常: " + e.getMessage(), e);
sendProgressEvent(-1, ENROLL_STEP_COUNT, "录入异常: " + e.getMessage());
Map<String, Object> errorResult = createErrorResponse("录入过程发生异常: " + e.getMessage()); Map<String, Object> errorResult = createErrorResponse("录入过程发生异常: " + e.getMessage());
mainHandler.post(() -> result.success(errorResult)); mainHandler.post(() -> result.success(errorResult));
} finally { } finally {
@@ -811,6 +849,30 @@ public class ZhiwenPlugin implements FlutterPlugin, MethodCallHandler, ActivityA
} }
} }
/**
* 发送进度事件到Flutter端
* @param step 当前步骤1-3
* @param totalSteps 总步骤数3
* @param message 进度消息
*/
private void sendProgressEvent(int step, int totalSteps, String message) {
if (progressEventSink != null) {
mainHandler.post(() -> {
try {
Map<String, Object> progressData = new HashMap<>();
progressData.put("step", step);
progressData.put("totalSteps", totalSteps);
progressData.put("progress", (double) step / totalSteps);
progressData.put("message", message);
progressEventSink.success(progressData);
Log.d(TAG, "发送进度事件: step=" + step + "/" + totalSteps + ", message=" + message);
} catch (Exception e) {
Log.w(TAG, "发送进度事件失败: " + e.getMessage());
}
});
}
}
/** /**
* 采集指纹图像重命名原Capturing方法 * 采集指纹图像重命名原Capturing方法
* @return 采集结果0表示成功负数表示失败 * @return 采集结果0表示成功负数表示失败
@@ -823,7 +885,14 @@ public class ZhiwenPlugin implements FlutterPlugin, MethodCallHandler, ActivityA
public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) { public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) {
Log.d(TAG, "插件从引擎分离"); Log.d(TAG, "插件从引擎分离");
// 清理资源 // 清理进度事件通道
if (progressEventChannel != null) {
progressEventChannel.setStreamHandler(null);
progressEventChannel = null;
progressEventSink = null;
}
// 清理方法通道
if (channel != null) { if (channel != null) {
channel.setMethodCallHandler(null); channel.setMethodCallHandler(null);
channel = null; channel = null;

View File

@@ -1,5 +1,6 @@
import 'zhiwen_platform_interface.dart'; import 'zhiwen_platform_interface.dart';
import 'dart:async';
class Zhiwen { class Zhiwen {
Future<String?> getPlatformVersion() { Future<String?> getPlatformVersion() {
@@ -37,4 +38,10 @@ class Zhiwen {
Future<Map<String, dynamic>> getUserCount() { Future<Map<String, dynamic>> getUserCount() {
return ZhiwenPlatform.instance.getUserCount(); return ZhiwenPlatform.instance.getUserCount();
} }
/// 获取指纹录入进度事件流
/// 返回包含 step, totalSteps, progress, message 的 Map
Stream<Map<String, dynamic>> get progressStream {
return ZhiwenPlatform.instance.progressStream;
}
} }

View File

@@ -1,5 +1,6 @@
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'dart:async';
import 'zhiwen_platform_interface.dart'; import 'zhiwen_platform_interface.dart';
@@ -9,6 +10,13 @@ class MethodChannelZhiwen extends ZhiwenPlatform {
@visibleForTesting @visibleForTesting
final methodChannel = const MethodChannel('zhiwen'); final methodChannel = const MethodChannel('zhiwen');
/// The event channel for receiving fingerprint enrollment progress.
@visibleForTesting
final progressEventChannel = const EventChannel('zhiwen_progress');
/// 进度事件流控制器
Stream<Map<String, dynamic>>? _progressStream;
@override @override
Future<String?> getPlatformVersion() async { Future<String?> getPlatformVersion() async {
final version = await methodChannel.invokeMethod<String>('getPlatformVersion'); final version = await methodChannel.invokeMethod<String>('getPlatformVersion');
@@ -64,4 +72,13 @@ class MethodChannelZhiwen extends ZhiwenPlatform {
final result = await methodChannel.invokeMethod('getUserCount'); final result = await methodChannel.invokeMethod('getUserCount');
return Map<String, dynamic>.from(result as Map); return Map<String, dynamic>.from(result as Map);
} }
/// 获取指纹录入进度事件流
@override
Stream<Map<String, dynamic>> get progressStream {
_progressStream ??= progressEventChannel
.receiveBroadcastStream()
.map((event) => Map<String, dynamic>.from(event as Map));
return _progressStream!;
}
} }

View File

@@ -1,4 +1,5 @@
import 'package:plugin_platform_interface/plugin_platform_interface.dart'; import 'package:plugin_platform_interface/plugin_platform_interface.dart';
import 'dart:async';
import 'zhiwen_method_channel.dart'; import 'zhiwen_method_channel.dart';
@@ -24,6 +25,11 @@ abstract class ZhiwenPlatform extends PlatformInterface {
Future<Map<String, dynamic>> deleteOneFingerprint(int userId); Future<Map<String, dynamic>> deleteOneFingerprint(int userId);
Future<Map<String, dynamic>> identifyFingerprint(); Future<Map<String, dynamic>> identifyFingerprint();
Future<Map<String, dynamic>> getUserCount(); Future<Map<String, dynamic>> getUserCount();
/// 获取指纹录入进度事件流
/// 返回包含 step, totalSteps, progress, message 的 Map
Stream<Map<String, dynamic>> get progressStream;
/// Platform-specific implementations should set this with their own /// Platform-specific implementations should set this with their own
/// platform-specific class that extends [ZhiwenPlatform] when /// platform-specific class that extends [ZhiwenPlatform] when
/// they register themselves. /// they register themselves.