Преглед на файлове

Update 优化扫码相关代码

Yue преди 7 часа
родител
ревизия
1bc6fee508

+ 8 - 1
UI/CF.APP/chicken_farm/android/app/src/main/java/com/vber/chicken_farm/rfid/RfidService.java

@@ -62,7 +62,8 @@ public class RfidService extends Service {
     private int power;
     private RfidListener listener;
     private final RfidBinder mBinder = new RfidBinder(this);
-
+    private String curPort = "";
+    private int curBaud = 0;
     // 可配置参数(默认值从常量类读取)
     private int connectRetryTimes = RfidConstants.DEFAULT_CONNECT_RETRY_TIMES;
     private long wakeLockTimeoutMs = RfidConstants.WAKE_LOCK_TIMEOUT_MS;
@@ -290,6 +291,10 @@ public class RfidService extends Service {
                     acquireWakeLock();
                     if (!isConnected) {
                         connect();
+                    } else {
+                        if (listener != null) {
+                            listener.onConnectSuccess(curPort, curBaud);
+                        }
                     }
                     // stopIdleTimeout(); // 恢复读卡后停止空闲计时
                     // Log.d(RfidConstants.TAG, "亮屏恢复RFID读卡成功");
@@ -477,6 +482,8 @@ public class RfidService extends Service {
                         Log.i(RfidConstants.TAG, "RFID设备连接到" + port + ",波率: " + baud + ",结果: " + result);
 
                         if (result == 0) {
+                            curPort = port;
+                            curBaud = baud;
                             // 连接成功
                             isConnected = true;
                             connected = true;

+ 3 - 3
UI/CF.APP/chicken_farm/android/app/src/main/java/com/vber/chicken_farm/scan/ScanBinder.java

@@ -3,7 +3,7 @@ package com.vber.chicken_farm.scan;
 import android.os.Binder;
 
 /**
- * 扫服务Binder通信类
+ * 扫服务Binder通信类
  */
 public class ScanBinder extends Binder {
     private final ScanService scanService;
@@ -13,9 +13,9 @@ public class ScanBinder extends Binder {
     }
 
     /**
-     * 获取扫服务实例
+     * 获取扫服务实例
      */
-    public ScanService getScanService() {
+    public ScanService getService() {
         return scanService;
     }
 }

+ 0 - 18
UI/CF.APP/chicken_farm/android/app/src/main/java/com/vber/chicken_farm/scan/ScanCallback.java

@@ -1,18 +0,0 @@
-package com.vber.chicken_farm.scan;
-
-/**
- * 扫描结果回调接口
- */
-public interface ScanCallback {
-    /**
-     * 扫描结果回调
-     * @param result 扫码结果字符串
-     */
-    void onScanResult(String result);
-
-    /**
-     * 扫描错误回调
-     * @param errorMsg 错误信息
-     */
-    void onScanError(String errorMsg);
-}

+ 8 - 2
UI/CF.APP/chicken_farm/android/app/src/main/java/com/vber/chicken_farm/scan/ScanConstants.java

@@ -1,9 +1,12 @@
 package com.vber.chicken_farm.scan;
 
 /**
- * 扫服务常量定义
+ * 扫服务常量定义
  */
 public final class ScanConstants {
+    // 日志TAG
+    public static final String TAG = "ScanService";
+
     // 扫描结果广播Action
     public static final String SCAN_ACTION = "scan.rcv.message";
     // 扫描结果数据
@@ -20,7 +23,7 @@ public final class ScanConstants {
     public static final int LIGHT_MODE_BOTH = 4;        // 同时开启(默认)
     
     // 唤醒锁超时时间(10分钟)
-    public static final long WAKE_LOCK_TIMEOUT = 10 * 60 * 1000L;
+    public static final long WAKE_LOCK_TIMEOUT_MS = 10 * 60 * 1000L;
     
     /**
      * 0-广播模式,通过注册广播获取扫描数据
@@ -31,6 +34,9 @@ public final class ScanConstants {
      */
     public static final int SCAN_OP_MODE_BROADCAST = 0;
     
+    // 默认单次扫码超时时间(毫秒)
+    public static final long DEFAULT_SCAN_TIMEOUT_MS = 5000;
+    
     private ScanConstants() {
         // 禁止实例化
     }

+ 24 - 0
UI/CF.APP/chicken_farm/android/app/src/main/java/com/vber/chicken_farm/scan/ScanListener.java

@@ -0,0 +1,24 @@
+package com.vber.chicken_farm.scan;
+
+/**
+ * 扫描回调监听接口
+ */
+public interface ScanListener {
+    /**
+     * 扫描结果回调
+     * @param result 扫描结果字符串
+     */
+    void onScanResult(String result);
+
+    /**
+     * 扫描错误回调
+     * @param error 错误信息
+     */
+    void onScanError(String error);
+    
+    /**
+     * 扫描头状态变化回调
+     * @param isOpen 扫描头是否打开
+     */
+    default void onScanHeadStateChanged(boolean isOpen) {}
+}

+ 213 - 0
UI/CF.APP/chicken_farm/android/app/src/main/java/com/vber/chicken_farm/scan/ScanManager.java

@@ -0,0 +1,213 @@
+package com.vber.chicken_farm.scan;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.IBinder;
+import android.util.Log;
+
+/**
+ * 扫描服务管理类(外部统一调用入口)
+ * 封装Service绑定、解绑、API调用逻辑,简化外部使用
+ */
+public class ScanManager {
+    private static final String TAG = "ScanManager";
+    private static volatile ScanManager instance;
+    private final Context context;
+
+    // Service相关
+    private ScanService scanService;
+    private boolean isBound = false;
+    private ScanListener listener;
+
+    // 服务连接回调
+    private final ServiceConnection serviceConnection = new ServiceConnection() {
+        @Override
+        public void onServiceConnected(ComponentName name, IBinder service) {
+            Log.d(TAG, "扫描服务绑定成功");
+            ScanBinder binder = (ScanBinder) service;
+            scanService = binder.getService();
+            scanService.setListener(listener); // 设置回调监听
+            scanService.openScanHead();
+            isBound = true;
+        }
+
+        @Override
+        public void onServiceDisconnected(ComponentName name) {
+            Log.w(TAG, "扫描服务意外断开连接");
+            scanService = null;
+            isBound = false;
+            if (listener != null) {
+                listener.onScanError("扫描服务断开连接");
+            }
+        }
+    };
+
+    /**
+     * 单例初始化
+     */
+    private ScanManager(Context context) {
+        this.context = context.getApplicationContext();
+    }
+
+    /**
+     * 获取单例实例
+     */
+    public static ScanManager getInstance(Context context, ScanListener listener) {
+        if (instance == null) {
+            synchronized (ScanManager.class) {
+                if (instance == null) {
+                    instance = new ScanManager(context);
+                    instance.setListener(listener);
+                }
+            }
+        }
+        return instance;
+    }
+
+    /**
+     * 绑定扫描服务
+     */
+    public void bindService() {
+        if (isBound) {
+            Log.w(TAG, "扫描服务已绑定,无需重复绑定");
+            return;
+        }
+        Intent intent = new Intent(context, ScanService.class);
+        context.bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
+        Log.d(TAG, "发起扫描服务绑定请求");
+    }
+
+    /**
+     * 解绑扫描服务
+     */
+    public void unbindService() {
+        if (!isBound) {
+            Log.w(TAG, "扫描服务未绑定,无需解绑");
+            return;
+        }
+        context.unbindService(serviceConnection);
+        scanService = null;
+        isBound = false;
+        Log.d(TAG, "扫描服务已解绑");
+    }
+
+    /**
+     * 设置回调监听
+     */
+    public void setListener(ScanListener listener) {
+        this.listener = listener;
+        if (scanService != null) {
+            scanService.setListener(listener);
+        }
+    }
+
+    // -------------------------- 代理ScanService的核心API --------------------------
+    /**
+     * 打开扫描头
+     */
+    public boolean openScanHead() {
+        checkServiceBound();
+        return scanService.openScanHead();
+    }
+
+    /**
+     * 关闭扫描头
+     */
+    public void closeScanHead() {
+        if (isBound && scanService != null) {
+            scanService.closeScanHead();
+        }
+    }
+
+    /**
+     * 开始扫描
+     */
+    public boolean startScan() {
+        checkServiceBound();
+        return scanService.startScan();
+    }
+
+    /**
+     * 停止扫描
+     */
+    public void stopScan() {
+        if (isBound && scanService != null) {
+            scanService.stopScan();
+        }
+    }
+
+    /**
+     * 重置超时时间
+     */
+    public void resetTimeout() {
+        if (isBound && scanService != null) {
+            scanService.resetTimeout();
+        }
+    }
+
+    /**
+     * 设置灯光模式
+     */
+    public void setLightingMode(int mode) {
+        if (isBound && scanService != null) {
+            scanService.setLightingMode(mode);
+        }
+    }
+
+    /**
+     * 检查是否正在扫描
+     */
+    public boolean isScanning() {
+        return isBound && scanService != null && scanService.isScanning();
+    }
+
+    /**
+     * 检查扫描头是否打开
+     */
+    public boolean isScanHeadOpened() {
+        return isBound && scanService != null && scanService.isScanHeadOpened();
+    }
+
+    /**
+     * 获取绑定的ScanService实例(谨慎使用)
+     */
+    public ScanService getService() {
+        checkServiceBound();
+        return scanService;
+    }
+
+    /**
+     * 检查服务是否已绑定,未绑定则抛出异常
+     */
+    private void checkServiceBound() {
+        if (!isBound || scanService == null) {
+            String errorMsg = "扫描服务未绑定,请先调用bindService()";
+            Log.e(TAG, errorMsg);
+            if (listener != null) {
+                listener.onScanError(errorMsg);
+            }
+            throw new IllegalStateException(errorMsg);
+        }
+    }
+
+    /**
+     * 判断服务是否已绑定
+     */
+    public boolean isBound() {
+        return isBound;
+    }
+
+    /**
+     * 释放资源(建议在应用退出时调用)
+     */
+    public void release() {
+        if (isBound) {
+            unbindService();
+        }
+        // listener = null;
+        // instance = null; // 重置单例
+        Log.d(TAG, "扫描管理器资源已释放");
+    }
+}

+ 218 - 120
UI/CF.APP/chicken_farm/android/app/src/main/java/com/vber/chicken_farm/scan/ScanMethodCallHandler.java

@@ -1,12 +1,14 @@
 package com.vber.chicken_farm.scan;
 
-import android.content.ComponentName;
 import android.content.Context;
-import android.content.Intent;
-import android.content.ServiceConnection;
-import android.os.IBinder;
+import android.os.Handler;
+import android.os.Looper;
 import android.util.Log;
 
+import androidx.annotation.NonNull;
+
+import java.util.Map;
+
 import io.flutter.embedding.engine.plugins.FlutterPlugin;
 import io.flutter.plugin.common.BinaryMessenger;
 import io.flutter.plugin.common.MethodCall;
@@ -15,185 +17,281 @@ import io.flutter.plugin.common.MethodChannel.MethodCallHandler;
 import io.flutter.plugin.common.MethodChannel.Result;
 
 /**
- * Flutter与Android扫码服务的通信桥接类
+ * 扫描 Flutter桥接处理器
+ * 处理Flutter与原生的MethodChannel通信
  */
-public class ScanMethodCallHandler implements MethodCallHandler, ScanCallback {
+public class ScanMethodCallHandler implements MethodCallHandler, ScanListener {
     private static final String TAG = "ScanMethodCallHandler";
-    // Flutter MethodChannel 名称(需与Flutter端一致)
-    public static final String CHANNEL_NAME = "com.vber.chicken_farm/scan";
+    // Channel名称(需与Flutter端保持一致)
+    public static final String METHOD_CHANNEL_NAME = "com.vber.chicken_farm/scan";
 
     private final Context context;
-    private final MethodChannel channel;
-    private ScanService scanService;
-    private boolean isServiceBound = false;
-
-    // 服务连接回调
-    private final ServiceConnection serviceConnection = new ServiceConnection() {
-        @Override
-        public void onServiceConnected(ComponentName name, IBinder service) {
-            Log.d(TAG, "扫码服务绑定成功");
-            ScanBinder binder = (ScanBinder) service;
-            scanService = binder.getScanService();
-            scanService.setScanCallback(ScanMethodCallHandler.this);
-            isServiceBound = true;
-        }
-
-        @Override
-        public void onServiceDisconnected(ComponentName name) {
-            Log.d(TAG, "扫码服务解绑");
-            scanService = null;
-            isServiceBound = false;
-        }
-    };
-
-    // 构造方法
-    public ScanMethodCallHandler(Context context, BinaryMessenger messenger) {
-        this.context = context;
-        this.channel = new MethodChannel(messenger, CHANNEL_NAME);
-        this.channel.setMethodCallHandler(this);
-        // 初始化时绑定服务
-        bindScanService();
-
-        Log.d(TAG, "SCAN Flutter MethodChannel初始化完成");
-
-    }
+    private final ScanManager scanManager;
+    private MethodChannel methodChannel;
+    private final Handler mainHandler; // 主线程Handler,确保Flutter回调在主线程执行
 
     /**
-     * 绑定扫码服务
+     * 构造函数
      */
-    private void bindScanService() {
-        try {
-            Intent intent = new Intent(context, ScanService.class);
-            context.bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
-        } catch (Exception e) {
-            Log.e(TAG, "绑定扫码服务失败", e);
-        }
+    public ScanMethodCallHandler(Context context, BinaryMessenger messenger) {
+        this.context = context.getApplicationContext();
+        this.scanManager = ScanManager.getInstance(this.context, this);
+        this.mainHandler = new Handler(Looper.getMainLooper());
+        methodChannel = new MethodChannel(messenger, METHOD_CHANNEL_NAME);
+        methodChannel.setMethodCallHandler(this);
+        Log.d(TAG, "扫描 Flutter MethodChannel初始化完成");
     }
 
-    /**
-     * 处理Flutter端的方法调用
-     */
+    // -------------------------- MethodChannel实现 --------------------------
     @Override
-    public void onMethodCall(MethodCall call, Result result) {
-        Log.d(TAG, "收到Flutter调用方法:" + call.method);
-        if (!isServiceBound || scanService == null) {
-            result.error("SERVICE_NOT_BOUND", "扫码服务未绑定", null);
-            return;
-        }
-
+    public void onMethodCall(@NonNull MethodCall call, @NonNull Result result) {
+        Log.d(TAG, "收到Flutter方法调用: " + call.method);
         switch (call.method) {
-            // 扫描头管理API
+            case "init":
+                handleBindService(result);
+                break;
             case "openScanHead":
-                boolean openSuccess = scanService.openScanHead();
-                result.success(openSuccess);
+                handleOpenScanHead(result);
                 break;
             case "closeScanHead":
-                scanService.closeScanHead();
-                result.success(true);
+                handleCloseScanHead(result);
                 break;
-            case "resetIdleTimeout":
-                scanService.resetIdleTimeout();
-                result.success(true);
-                break;
-                
-            // 扫码解码API
             case "startScan":
-                boolean scanSuccess = scanService.startScan();
-                result.success(scanSuccess);
+                handleStartScan(result);
+                break;
+            case "stopScan":
+                handleStopScan(result);
+                break;
+            case "resetTimeout":
+                handleResetTimeout(result);
                 break;
-            case "stopSingleScan":
-                scanService.stopSingleScan();
-                result.success(true);
+            case "setLightingMode":
+                handleSetLightingMode(call.argument("mode"), result);
                 break;
-                
-            // 状态查询API
             case "isScanning":
-                result.success(scanService.isScanning());
+                handleIsScanning(result);
                 break;
             case "isScanHeadOpened":
-                result.success(scanService.isScanHeadOpened());
+                handleIsScanHeadOpened(result);
                 break;
-                
-            // 灯光设置API
-            case "setLightingMode":
-                int mode = call.argument("mode");
-                scanService.setLightingMode(mode);
-                result.success("灯光模式已设置为:" + mode);
+            case "releaseResources":
+                handleReleaseResources(result);
                 break;
-                
             default:
                 result.notImplemented();
+                Log.w(TAG, "未实现的方法调用: " + call.method);
                 break;
         }
     }
 
     /**
-     * 获取扫描状态
+     * 处理绑定服务请求
      */
-    private boolean scanServiceIsScanning() {
+    private void handleBindService(Result result) {
         try {
-            // 通过反射获取ScanService的isScanning字段(因为是private)
-            java.lang.reflect.Field field = ScanService.class.getDeclaredField("isScanning");
-            field.setAccessible(true);
-            return (boolean) field.get(scanService);
+            Log.d(TAG, "请求绑定扫描服务");
+            scanManager.bindService();
+            result.success(true);
         } catch (Exception e) {
-            Log.e(TAG, "获取扫描状态失败", e);
-            return false;
+            Log.e(TAG, "绑定服务失败", e);
+            result.error("BIND_FAILED", "绑定扫描服务失败: " + e.getMessage(), null);
         }
     }
 
     /**
-     * 扫描结果回调(转发给Flutter)
+     * 处理打开扫描头请求
      */
-    @Override
-    public void onScanResult(String result) {
-        // 向Flutter发送扫描结果事件
-        channel.invokeMethod("onScanResult", result);
+    private void handleOpenScanHead(Result result) {
+        try {
+            boolean success = scanManager.openScanHead();
+            result.success(success);
+            Log.d(TAG, "打开扫描头请求已处理");
+        } catch (Exception e) {
+            Log.e(TAG, "打开扫描头失败", e);
+            result.error("OPEN_SCAN_HEAD_FAILED", "打开扫描头失败: " + e.getMessage(), null);
+        }
+    }
+
+    /**
+     * 处理关闭扫描头请求
+     */
+    private void handleCloseScanHead(Result result) {
+        try {
+            scanManager.closeScanHead();
+            result.success(true);
+            Log.d(TAG, "关闭扫描头请求已处理");
+        } catch (Exception e) {
+            Log.e(TAG, "关闭扫描头失败", e);
+            result.error("CLOSE_SCAN_HEAD_FAILED", "关闭扫描头失败: " + e.getMessage(), null);
+        }
+    }
+
+    /**
+     * 处理开始扫描请求
+     */
+    private void handleStartScan(Result result) {
+        try {
+            boolean success = scanManager.startScan();
+            result.success(success);
+            if (success) {
+                Log.d(TAG, "开始扫描请求已处理");
+            } else {
+                Log.w(TAG, "开始扫描请求失败");
+            }
+        } catch (Exception e) {
+            Log.e(TAG, "开始扫描失败", e);
+            result.error("START_SCAN_FAILED", "开始扫描失败: " + e.getMessage(), null);
+        }
     }
 
     /**
-     * 扫描错误回调(转发给Flutter)
+     * 处理停止扫描请求
      */
+    private void handleStopScan(Result result) {
+        try {
+            scanManager.stopScan();
+            result.success(null);
+            Log.d(TAG, "停止扫描请求已处理");
+        } catch (Exception e) {
+            Log.e(TAG, "停止扫描失败", e);
+            result.error("STOP_SCAN_FAILED", "停止扫描失败: " + e.getMessage(), null);
+        }
+    }
+
+    /**
+     * 处理重置超时请求
+     */
+    private void handleResetTimeout(Result result) {
+        try {
+            scanManager.resetTimeout();
+            result.success(null);
+            Log.d(TAG, "重置超时请求已处理");
+        } catch (Exception e) {
+            Log.e(TAG, "重置超时失败", e);
+            result.error("RESET_TIMEOUT_FAILED", "重置超时失败: " + e.getMessage(), null);
+        }
+    }
+
+    /**
+     * 处理设置灯光模式请求
+     */
+    private void handleSetLightingMode(Integer mode, Result result) {
+        try {
+            if (mode != null) {
+                scanManager.setLightingMode(mode);
+                result.success(null);
+                Log.d(TAG, "设置灯光模式: " + mode);
+            } else {
+                result.error("INVALID_ARGUMENT", "灯光模式参数不能为空", null);
+            }
+        } catch (Exception e) {
+            Log.e(TAG, "设置灯光模式失败", e);
+            result.error("SET_LIGHTING_MODE_FAILED", "设置灯光模式失败: " + e.getMessage(), null);
+        }
+    }
+
+    /**
+     * 处理检查是否正在扫描请求
+     */
+    private void handleIsScanning(Result result) {
+        try {
+            boolean isScanning = scanManager.isScanning();
+            result.success(isScanning);
+            Log.d(TAG, "检查扫描状态成功: " + isScanning);
+        } catch (Exception e) {
+            Log.e(TAG, "检查扫描状态失败", e);
+            result.error("CHECK_SCANNING_FAILED", "检查扫描状态失败: " + e.getMessage(), null);
+        }
+    }
+
+    /**
+     * 处理检查扫描头是否打开请求
+     */
+    private void handleIsScanHeadOpened(Result result) {
+        try {
+            boolean isOpened = scanManager.isScanHeadOpened();
+            result.success(isOpened);
+            Log.d(TAG, "检查扫描头状态成功: " + isOpened);
+        } catch (Exception e) {
+            Log.e(TAG, "检查扫描头状态失败", e);
+            result.error("CHECK_SCAN_HEAD_OPENED_FAILED", "检查扫描头状态失败: " + e.getMessage(), null);
+        }
+    }
+
+    /**
+     * 处理释放资源请求
+     */
+    private void handleReleaseResources(Result result) {
+        try {
+            scanManager.release();
+            result.success(null);
+            Log.d(TAG, "释放资源请求已处理");
+        } catch (Exception e) {
+            Log.e(TAG, "释放资源失败", e);
+            result.error("RELEASE_RESOURCES_FAILED", "释放资源失败: " + e.getMessage(), null);
+        }
+    }
+
+    // -------------------------- ScanListener回调实现 --------------------------
     @Override
-    public void onScanError(String errorMsg) {
-        // 向Flutter发送错误事件
-        channel.invokeMethod("onScanError", errorMsg);
+    public void onScanResult(String result) {
+        mainHandler.post(() -> {
+            methodChannel.invokeMethod("onScanResult", result);
+        });
+    }
+
+    @Override
+    public void onScanError(String error) {
+        mainHandler.post(() -> {
+            methodChannel.invokeMethod("onScanError", error);
+        });
+    }
+
+    @Override
+    public void onScanHeadStateChanged(boolean isOpen) {
+        mainHandler.post(() -> {
+            methodChannel.invokeMethod("onScanHeadStateChanged", isOpen);
+        });
     }
 
-    // 处理按键事件并通知Flutter
+    /**
+     * 处理按键事件并通知Flutter
+     */
     public void onKeyEvent(int keyCode) {
         if (keyCode == 622) {
             // 向Flutter发送按键622事件
-            channel.invokeMethod("onKeyPress", "KEY_622");
+            mainHandler.post(() -> {
+                methodChannel.invokeMethod("onKeyPress", "KEY_622");
+            });
         } else if (keyCode == 623) {
             // 向Flutter发送按键623事件
-            channel.invokeMethod("onKeyPress", "KEY_623");
+            mainHandler.post(() -> {
+                methodChannel.invokeMethod("onKeyPress", "KEY_623");
+            });
         }
     }
 
-    // 处理按键事件并通知Flutter
+    /**
+     * 处理双击按键事件并通知Flutter
+     */
     public void onDoubleKeyEvent(int keyCode) {
         if (keyCode == 619) {
             // 向Flutter发送按键619事件
             Log.d(TAG, "双击按键619事件");
-            channel.invokeMethod("onDoubleKeyPress", "KEY_619");
+            mainHandler.post(() -> {
+                methodChannel.invokeMethod("onDoubleKeyPress", "KEY_619");
+            });
         }
     }
 
     /**
-     * 释放资源(Flutter插件销毁时调用)
+     * 释放资源
      */
     public void dispose() {
-        Log.d(TAG, "释放扫码桥接资源");
-        // 解绑服务
-        if (isServiceBound) {
-            if (scanService != null) {
-                scanService.stopSingleScan();
-            }
-            context.unbindService(serviceConnection);
-            isServiceBound = false;
+        if (methodChannel != null) {
+            methodChannel.setMethodCallHandler(null);
         }
-        // 清空MethodChannel
-        channel.setMethodCallHandler(null);
+        scanManager.release();
+        Log.d(TAG, "扫描桥接处理器资源已释放");
     }
 }

+ 375 - 362
UI/CF.APP/chicken_farm/android/app/src/main/java/com/vber/chicken_farm/scan/ScanService.java

@@ -13,81 +13,82 @@ import android.bld.scan.configuration.DecoderConfigValues;
 import android.util.Log;
 
 /**
- * 扫码核心服务(扫描头独立管理+双超时+低功耗)
- * 适配场景:
- * 1. 打开扫描头(进入场景时),扫码时直接复用,提升响应速度;
- * 2. 单次扫码超时(5秒):停止解码,保留扫描头;
- * 3. 闲置超时(5分钟):无新扫码请求则关闭扫描头+注销广播;
- * 4. 离开场景可手动关闭扫描头,立即释放资源;
- * 5. 默认仅开启瞄准灯,降低功耗。
+ * 扫描核心服务
+ * 特性:
+ * 1. 屏幕状态自动管理扫描头(息屏关闭,亮屏打开)
+ * 2. 页面离开时释放资源
+ * 3. 移除了闲置超时机制
+ * 4. 提供完整的API供外部调用
  */
 public class ScanService extends Service {
-    private static final String TAG = "ScanService";
-    
-    // -------------------------- 可配置常量 --------------------------
-    /** 单次扫码超时时间(毫秒):无结果则停止解码,保留扫描头 */
-    public static final long SCAN_SINGLE_TIMEOUT_MS = 5000;
-    /** 扫描头闲置超时时间(毫秒):打开后无扫码请求则关闭 */
-    public static final long SCAN_IDLE_TIMEOUT_MS = 120 * 60 * 1000L; // 120分钟
-    /** 默认灯光模式:开启照明+瞄准 */
-    public static final int DEFAULT_LIGHT_MODE = ScanConstants.LIGHT_MODE_BOTH;
-    
-    // -------------------------- 核心变量 --------------------------
+    private static final String TAG = ScanConstants.TAG;
+
+    // 核心变量
     private ScanManager scanManager;
-    private ScanCallback scanCallback;
+    private ScanListener listener;
     private PowerManager.WakeLock wakeLock;
-    private boolean isScanning = false; // 是否正在解码
-    private Handler scanHandler; // 统一处理延迟任务
-    private Runnable singleTimeoutRunnable; // 单次扫码超时任务
-    private Runnable idleTimeoutRunnable; // 扫描头闲置超时任务
-    
-    // 广播接收器(仅扫描头打开时注册)
-    private final BroadcastReceiver screenReceiver = new BroadcastReceiver() {
+    private boolean isScanning = false;
+    private boolean isScreenOn = true; // 屏幕状态标记
+    private Handler scanHandler;
+    private Runnable scanTimeoutRunnable;
+
+    // 广播接收器注册状态跟踪
+    private boolean isScreenReceiverRegistered = false;
+    private boolean isScanReceiverRegistered = false;
+
+    private final ScanBinder binder = new ScanBinder(this);
+
+    // 屏幕状态广播接收器(处理息屏/亮屏)
+    private final BroadcastReceiver screenStateReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
-            if (intent == null || intent.getAction() == null) return;
-            
-            switch (intent.getAction()) {
-                case Intent.ACTION_SCREEN_ON:
-                    // 屏幕亮起 - 重新打开扫描头
-                    Log.d(TAG, "屏幕亮起");
-                    openScanHead();
-                    break;
-                case Intent.ACTION_SCREEN_OFF:
-                    // 屏幕熄灭 - 关闭扫描头
-                    Log.d(TAG, "屏幕熄灭");
-                    closeScanHead();
-                    break;
+            String action = intent.getAction();
+            if (Intent.ACTION_SCREEN_ON.equals(action)) {
+                // 屏幕亮起 - 打开扫描头
+                isScreenOn = true;
+                Log.d(TAG, "屏幕亮起");
+                openScanHead();
+
+            } else if (Intent.ACTION_SCREEN_OFF.equals(action)) {
+                // 屏幕熄灭 - 关闭扫描头
+                isScreenOn = false;
+                Log.d(TAG, "屏幕熄灭");
+                closeScanHead();
+
             }
         }
     };
-    
+
     private final BroadcastReceiver scanReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
-            if (intent == null || scanCallback == null || !isScanning) return;
-            
+            if (intent == null || listener == null || !isScanning)
+                return;
+
             try {
                 byte[] barcode = intent.getByteArrayExtra(ScanConstants.SCAN_RESULT_DATA);
                 int barcodeLen = intent.getIntExtra("length", 0);
-                
+
                 if (barcode != null && barcodeLen > 0) {
                     String barcodeStr = new String(barcode, 0, barcodeLen);
-                    scanCallback.onScanResult(barcodeStr);
+                    if (listener != null) {
+                        listener.onScanResult(barcodeStr);
+                    }
                     Log.d(TAG, "扫描成功:" + barcodeStr);
-                    stopSingleScan(); // 单次扫码完成,停止解码(保留扫描头)
+                    stopScan(); // 单次扫码完成,停止解码
                 } else {
-                    scanCallback.onScanError("扫描结果为空");
+                    if (listener != null) {
+                        listener.onScanError("扫描结果为空");
+                    }
                 }
             } catch (Exception e) {
-                scanCallback.onScanError("解析扫描结果失败:" + e.getMessage());
+                if (listener != null) {
+                    listener.onScanError("解析扫描结果失败:" + e.getMessage());
+                }
                 Log.e(TAG, "解析扫描结果失败", e);
             }
         }
     };
-    
-    // Binder实例
-    private final ScanBinder binder = new ScanBinder(this);
 
     @Override
     public IBinder onBind(Intent intent) {
@@ -97,175 +98,247 @@ public class ScanService extends Service {
     @Override
     public void onCreate() {
         super.onCreate();
-        Log.d(TAG, "扫码服务创建");
-        scanHandler = new Handler(getMainLooper());
-        acquireWakeLock(); // 仅轻量级唤醒锁,不初始化扫描硬件
+        Log.d(TAG, "扫描服务创建");
+        scanHandler = new Handler();
+        initWakeLock();
+        registerScreenStateReceiver();
     }
 
-    // -------------------------- 懒加载初始化 --------------------------
-    private void lazyInitScanManager() {
-        if (scanManager == null) {
-            scanManager = ScanManager.getDefaultInstance(this);
-            if (scanManager == null) {
-                Log.e(TAG, "获取ScanManager实例失败");
-                if (scanCallback != null) {
-                    scanCallback.onScanError("扫描硬件初始化失败");
-                }
-                return;
-            }
-            
-            Log.d(TAG, "扫描管理器懒加载初始化成功");
+    /**
+     * 初始化唤醒锁
+     */
+    private void initWakeLock() {
+        PowerManager pm = (PowerManager) getSystemService(POWER_SERVICE);
+        if (pm != null) {
+            wakeLock = pm.newWakeLock(
+                    PowerManager.PARTIAL_WAKE_LOCK | PowerManager.ON_AFTER_RELEASE,
+                    ScanConstants.WAKE_LOCK_TAG);
+            wakeLock.setReferenceCounted(false);
+        } else {
+            Log.e(TAG, "获取PowerManager失败,无法初始化唤醒锁");
         }
     }
 
-    private void registerScanReceivers() {
+    /**
+     * 注册屏幕状态广播
+     */
+    private void registerScreenStateReceiver() {
+        if (isScreenReceiverRegistered) {
+            Log.w(TAG, "屏幕状态广播已注册,无需重复注册");
+            return;
+        }
+
         try {
-            IntentFilter screenFilter = new IntentFilter();
-            screenFilter.addAction(Intent.ACTION_SCREEN_ON);
-            screenFilter.addAction(Intent.ACTION_SCREEN_OFF);
-            registerReceiver(screenReceiver, screenFilter);
-            
-            IntentFilter scanFilter = new IntentFilter(ScanConstants.SCAN_ACTION);
-            registerReceiver(scanReceiver, scanFilter);
-            
-            Log.d(TAG, "广播接收器注册完成");
+            IntentFilter filter = new IntentFilter();
+            filter.addAction(Intent.ACTION_SCREEN_ON);
+            filter.addAction(Intent.ACTION_SCREEN_OFF);
+            registerReceiver(screenStateReceiver, filter);
+            isScreenReceiverRegistered = true;
+            Log.d(TAG, "屏幕状态广播已注册");
         } catch (Exception e) {
-            Log.e(TAG, "注册广播接收器失败", e);
-            if (scanCallback != null) {
-                scanCallback.onScanError("注册扫描广播失败:" + e.getMessage());
+            Log.e(TAG, "注册屏幕状态广播失败", e);
+        }
+    }
+
+    /**
+     * 注册扫描结果广播
+     */
+    private void registerScanReceiver() {
+        if (isScanReceiverRegistered) {
+            Log.w(TAG, "扫描结果广播已注册,无需重复注册");
+            return;
+        }
+
+        try {
+            IntentFilter filter = new IntentFilter(ScanConstants.SCAN_ACTION);
+            registerReceiver(scanReceiver, filter);
+            isScanReceiverRegistered = true;
+            Log.d(TAG, "扫描结果广播已注册");
+        } catch (Exception e) {
+            Log.e(TAG, "注册扫描结果广播失败", e);
+            if (listener != null) {
+                listener.onScanError("注册扫描结果广播失败:" + e.getMessage());
             }
         }
     }
 
-    private void unregisterScanReceivers() {
+    /**
+     * 注销扫描结果广播
+     */
+    private void unregisterScanReceiver() {
+        if (!isScanReceiverRegistered) {
+            Log.w(TAG, "扫描结果广播未注册,无需注销");
+            return;
+        }
+
         try {
-            unregisterReceiver(screenReceiver);
             unregisterReceiver(scanReceiver);
-            Log.d(TAG, "广播接收器已注销");
+            isScanReceiverRegistered = false;
+            Log.d(TAG, "扫描结果广播已注销");
         } catch (Exception e) {
-            Log.e(TAG, "注销广播接收器失败", e);
+            Log.e(TAG, "注销扫描结果广播失败", e);
         }
     }
 
-    // -------------------------- 扫描头独立管理API(给Flutter调用) --------------------------
     /**
-     * 打开扫描头(进入场景时调用)
-     * 逻辑:初始化扫描硬件+注册广播+启动闲置超时+默认开启瞄准灯
+     * 注销屏幕状态广播
+     */
+    private void unregisterScreenStateReceiver() {
+        if (!isScreenReceiverRegistered) {
+            Log.w(TAG, "屏幕状态广播未注册,无需注销");
+            return;
+        }
+
+        try {
+            unregisterReceiver(screenStateReceiver);
+            isScreenReceiverRegistered = false;
+            Log.d(TAG, "屏幕状态广播已注销");
+        } catch (Exception e) {
+            Log.e(TAG, "注销屏幕状态广播失败", e);
+        }
+    }
+
+    // -------------------------- 对外暴露的核心API --------------------------
+    /**
+     * 设置回调监听
+     */
+    public void setListener(ScanListener listener) {
+        this.listener = listener;
+    }
+
+    /**
+     * 打开扫描头
      */
     public boolean openScanHead() {
-        // 1. 懒加载初始化扫描管理器
-        lazyInitScanManager();
+        // 初始化扫描管理器
         if (scanManager == null) {
-            return false;
+            scanManager = ScanManager.getDefaultInstance(this);
+            if (scanManager == null) {
+                Log.e(TAG, "获取ScanManager实例失败");
+                if (listener != null) {
+                    listener.onScanError("扫描硬件初始化失败");
+                }
+                return false;
+            }
+            Log.d(TAG, "扫描管理器初始化成功");
         }
+
         try {
             setDefaultParams();
-            // 2. 打开扫描头硬件
+            // 打开扫描头硬件
             scanManager.openScanner();
             int retryCount = 0;
             while (!scanManager.isScannerOpen() && retryCount < 10) {
-                Thread.sleep(50);
+                try {
+                    Thread.sleep(50);
+                } catch (InterruptedException e) {
+                    Thread.currentThread().interrupt();
+                    Log.e(TAG, "等待扫描头打开时被中断", e);
+                    break;
+                }
                 retryCount++;
             }
             if (!scanManager.isScannerOpen()) {
                 Log.e(TAG, "扫描头打开超时");
                 return false;
             }
-            // 3. 设置默认灯光(照明+瞄准)
-            setLightingMode(DEFAULT_LIGHT_MODE);
-            // 4. 设置广播模式
+
+            // 设置默认灯光(照明+瞄准)
+            setLightingMode(ScanConstants.LIGHT_MODE_BOTH);
+            // 设置广播模式
             scanManager.setOPMode(ScanConstants.SCAN_OP_MODE_BROADCAST);
-            // 5. 注册广播接收器(只在第一次打开时注册)
-            if (screenReceiver != null && scanReceiver != null) {
-                try {
-                    unregisterReceiver(screenReceiver);
-                    unregisterReceiver(scanReceiver);
-                } catch (Exception e) {
-                    // 忽略注销异常
-                }
-                registerScanReceivers();
+
+            // 注册扫描结果广播
+            registerScanReceiver();
+
+            // 通知监听器扫描头已打开
+            if (listener != null) {
+                listener.onScanHeadStateChanged(true);
             }
-            
-            // 6. 启动扫描头闲置超时(核心调整:打开扫描头就启动)
-            startIdleTimeout();
-            Log.d(TAG, "扫描头已打开(闲置超时:" + SCAN_IDLE_TIMEOUT_MS + "ms)");
+
+            Log.d(TAG, "扫描头已打开");
             return true;
         } catch (Exception e) {
             Log.e(TAG, "打开扫描头失败", e);
-            if (scanCallback != null) {
-                scanCallback.onScanError("打开扫描头失败:" + e.getMessage());
+            if (listener != null) {
+                listener.onScanError("打开扫描头失败:" + e.getMessage());
             }
             return false;
         }
     }
 
-    public void setDefaultParams() { 
-        /**
-         * 自定义广播 action 以接收数据
-         */
-        scanManager.setBroadcastAction(ScanConstants.SCAN_ACTION);
-        /**
-         * 自定义广播 key 以接收数据
-         */
-        scanManager.setBroadcastKey(ScanConstants.SCAN_RESULT_DATA);
-        /**
-         * 0-广播模式,通过注册广播获取扫描数据
-         * 1-输入框模式,在此模式下,任何输入框都可以填充扫描条形码
-         * 2-键盘模式,模拟键盘输入
-         * 3-单输入框模式,任何输入框均可填充扫描条形码,无重复
-         * 4-剪贴板,将扫描的条形码放在剪贴板上,用户可以将其粘贴到任何地方
-         */
-        // scanManager.setOPMode(0);
-        /**
-         * 0 - none
-         * 1 - Enter
-         * 2 - Tab
-         */
-        scanManager.setEndMark(0);
-        /**
-         * 是否启用手柄按钮
-         */
-        scanManager.setHandleKey(false);
-        /**
-         * 是否播放声音
-        */
-        scanManager.setPlaySound(true);
-        /**
-         * 是否震动
-         */
-        scanManager.setVibrate(true);
-        /**
-         * 前缀
-         */
-        scanManager.setPrefix("");
-        /**
-         * 后缀
-         */
-        scanManager.setSuffix("");
-        /**
-         * 设置连续扫描 (设置为禁用时为 true,允许为 false)
-         */
-        scanManager.setContinueScan(false);
-        /**
-         * 是否启用所有一维码(true-启用; false-不启用)
-         */
-        scanManager.enableSYM1D(true);
-        /**
-         * 是否启用所有二维码(true-启用; false-不启用)
-         */
-        scanManager.enableSYM2D(true);
-        
+    /**
+     * 设置默认参数
+     */
+    private void setDefaultParams() {
+        try {
+            /**
+             * 自定义广播 action 以接收数据
+             */
+            scanManager.setBroadcastAction(ScanConstants.SCAN_ACTION);
+            /**
+             * 自定义广播 key 以接收数据
+             */
+            scanManager.setBroadcastKey(ScanConstants.SCAN_RESULT_DATA);
+            /**
+             * 0-广播模式,通过注册广播获取扫描数据
+             * 1-输入框模式,在此模式下,任何输入框都可以填充扫描条形码
+             * 2-键盘模式,模拟键盘输入
+             * 3-单输入框模式,任何输入框均可填充扫描条形码,无重复
+             * 4-剪贴板,将扫描的条形码放在剪贴板上,用户可以将其粘贴到任何地方
+             */
+            scanManager.setOPMode(0);
+            /**
+             * 0 - none
+             * 1 - Enter
+             * 2 - Tab
+             */
+            scanManager.setEndMark(0);
+            /**
+             * 是否启用手柄按钮
+             */
+            scanManager.setHandleKey(false);
+            /**
+             * 是否播放声音
+             */
+            scanManager.setPlaySound(true);
+            /**
+             * 是否震动
+             */
+            scanManager.setVibrate(true);
+            /**
+             * 前缀
+             */
+            scanManager.setPrefix("");
+            /**
+             * 后缀
+             */
+            scanManager.setSuffix("");
+            /**
+             * 设置连续扫描 (设置为禁用时为 true,允许为 false)
+             */
+            scanManager.setContinueScan(false);
+            /**
+             * 是否启用所有一维码(true-启用; false-不启用)
+             */
+            scanManager.enableSYM1D(true);
+            /**
+             * 是否启用所有二维码(true-启用; false-不启用)
+             */
+            scanManager.enableSYM2D(true);
+        } catch (Exception e) {
+            Log.e(TAG, "设置默认参数失败", e);
+        }
     }
 
     /**
-     * 手动关闭扫描头(离开场景时调用)
-     * 逻辑:停止解码+关闭硬件+注销广播+取消所有超时
+     * 关闭扫描头
      */
     public void closeScanHead() {
-        // 1. 取消所有超时任务
-        cancelAllTimeouts();
+        // 取消扫描超时任务
+        cancelScanTimeout();
 
-        // 2. 停止解码(若正在扫码)
+        // 停止解码
         if (scanManager != null && isScanning) {
             try {
                 scanManager.stopDecode();
@@ -274,304 +347,244 @@ public class ScanService extends Service {
             }
         }
 
-        // 3. 关闭扫描头硬件
-        if (scanManager != null && isScanHeadOpened()) {
+        // 关闭扫描头硬件
+        if (scanManager != null && scanManager.isScannerOpen()) {
             try {
                 scanManager.closeScanner();
-                Log.d(TAG, "扫描头已手动关闭");
+                Log.d(TAG, "扫描头已关闭");
             } catch (Exception e) {
                 Log.e(TAG, "关闭扫描头失败", e);
             }
         }
 
-        // 4. 更新状态
+        // 注销扫描结果广播
+        unregisterScanReceiver();
+
         isScanning = false;
+
+        // 通知监听器扫描头已关闭
+        if (listener != null) {
+            listener.onScanHeadStateChanged(false);
+        }
     }
 
-    // -------------------------- 扫码解码API(给Flutter调用) --------------------------
     /**
-     * 开始单次扫码(扫描头已打开时直接复用,未打开则自动打开)
+     * 开始扫描
      */
     public boolean startScan() {
-        if (isScanning) {
-            Log.w(TAG, "扫码已在进行中,无需重复调用");
-            resetSingleTimeout(); // 重置单次超时
-            return true;
-        }
-
-        // 1. 若扫描头未打开,自动打开
         if (!isScanHeadOpened()) {
-            Log.d(TAG, "自动打开扫描头");
-            boolean openSuccess = openScanHead();
-            if (!openSuccess) {
+            boolean opened = openScanHead();
+            if (!opened) {
+                return false;
+            }
+            int retryCount = 0;
+            while (!isScanHeadOpened() && retryCount < 10) {
+                retryCount++;
+                try {
+                    Thread.sleep(100);
+                } catch (InterruptedException e) {
+                    Thread.currentThread().interrupt();
+                    Log.e(TAG, "等待扫描头打开时被中断", e);
+                    break;
+                }
+            }
+            if (!isScanHeadOpened()) {
+                Log.e(TAG, "打开扫描头超时");
                 return false;
             }
         }
 
+        if (isScanning) {
+            Log.w(TAG, "扫描已在进行中");
+            return true;
+        }
+
         try {
-            // 2. 开始解码(复用已打开的扫描头)
+            // 开始解码
             scanManager.startDecode();
             isScanning = true;
-            // 3. 启动单次扫码超时
-            startSingleTimeout();
-            // 4. 重置闲置超时(扫码行为刷新闲置计时)
-            resetIdleTimeout();
-            Log.d(TAG, "开始单次扫码(超时:" + SCAN_SINGLE_TIMEOUT_MS + "ms)");
+
+            // 启动扫描超时
+            startScanTimeout();
+
+            Log.d(TAG, "开始扫描");
             return true;
         } catch (Exception e) {
-            Log.e(TAG, "开始扫失败", e);
+            Log.e(TAG, "开始扫失败", e);
             isScanning = false;
-            if (scanCallback != null) {
-                scanCallback.onScanError("开始扫码失败:" + e.getMessage());
+            if (listener != null) {
+                listener.onScanError("开始扫描失败:" + e.getMessage());
             }
             return false;
         }
     }
 
     /**
-     * 停止单次扫码(仅停止解码,保留扫描头)
+     * 停止扫描
      */
-    public void stopSingleScan() {
-        // 1. 取消单次扫码超时
-        cancelSingleTimeout();
+    public void stopScan() {
+        // 取消扫描超时任务
+        cancelScanTimeout();
 
-        // 2. 停止解码
+        // 停止解码
         if (scanManager != null && isScanning) {
             try {
                 scanManager.stopDecode();
-                Log.d(TAG, "单次扫码停止(保留扫描头)");
+                Log.d(TAG, "扫描已停止");
             } catch (Exception e) {
-                Log.e(TAG, "停止解码失败", e);
+                Log.e(TAG, "停止扫描失败", e);
             }
         }
 
         isScanning = false;
-        // 闲置超时仍在运行,到期自动关闭扫描头
     }
 
-    // -------------------------- 超时任务管理(核心调整) --------------------------
     /**
-     * 启动扫描头闲置超时(打开扫描头时调用)
+     * 启动扫描超时
      */
-    private void startIdleTimeout() {
-        cancelIdleTimeout(); // 先取消旧任务
-        idleTimeoutRunnable = () -> {
-            if (isScanHeadOpened() && !isScanning) {
-                Log.d(TAG, "扫描头闲置超时(" + SCAN_IDLE_TIMEOUT_MS + "ms),自动关闭");
-                closeScanHead(); // 关闭扫描头+注销广播
-                if (scanCallback != null) {
-                    scanCallback.onScanError("扫描头闲置超时已自动关闭");
+    private void startScanTimeout() {
+        cancelScanTimeout(); // 先取消旧任务
+        scanTimeoutRunnable = () -> {
+            if (isScanning) {
+                Log.d(TAG, "扫描超时,自动停止");
+                stopScan();
+                if (listener != null) {
+                    listener.onScanError("扫描超时,未检测到条码");
                 }
             }
         };
-        scanHandler.postDelayed(idleTimeoutRunnable, SCAN_IDLE_TIMEOUT_MS);
+        scanHandler.postDelayed(scanTimeoutRunnable, ScanConstants.DEFAULT_SCAN_TIMEOUT_MS);
     }
 
     /**
-     * 重置扫描头闲置超时(扫码/手动刷新时调用)
+     * 取消扫描超时
      */
-    public void resetIdleTimeout() {
-        if (isScanHeadOpened() && idleTimeoutRunnable != null) {
-            scanHandler.removeCallbacks(idleTimeoutRunnable);
-            scanHandler.postDelayed(idleTimeoutRunnable, SCAN_IDLE_TIMEOUT_MS);
-            Log.d(TAG, "扫描头闲置超时已重置");
+    private void cancelScanTimeout() {
+        if (scanTimeoutRunnable != null) {
+            scanHandler.removeCallbacks(scanTimeoutRunnable);
+            scanTimeoutRunnable = null;
         }
     }
 
     /**
-     * 启动单次扫码超时(扫码时调用)
+     * 重置超时时间
      */
-    private void startSingleTimeout() {
-        cancelSingleTimeout(); // 先取消旧任务
-        singleTimeoutRunnable = () -> {
-            if (isScanning) {
-                Log.d(TAG, "单次扫码超时(" + SCAN_SINGLE_TIMEOUT_MS + "ms),停止解码");
-                stopSingleScan();
-                if (scanCallback != null) {
-                    scanCallback.onScanError("单次扫码超时,未检测到条码");
-                }
-            }
-        };
-        scanHandler.postDelayed(singleTimeoutRunnable, SCAN_SINGLE_TIMEOUT_MS);
+    public void resetTimeout() {
+        if (isScanning && scanTimeoutRunnable != null) {
+            scanHandler.removeCallbacks(scanTimeoutRunnable);
+            scanHandler.postDelayed(scanTimeoutRunnable, ScanConstants.DEFAULT_SCAN_TIMEOUT_MS);
+            Log.d(TAG, "扫描超时已重置");
+        }
     }
 
     /**
-     * 重置单次扫码超时(屏幕亮起时调用)
+     * 设置灯光模式
      */
-    private void resetSingleTimeout() {
-        if (singleTimeoutRunnable != null) {
-            scanHandler.removeCallbacks(singleTimeoutRunnable);
-            scanHandler.postDelayed(singleTimeoutRunnable, SCAN_SINGLE_TIMEOUT_MS);
-            Log.d(TAG, "单次扫码超时已重置");
+    public void setLightingMode(int mode) {
+        if (scanManager != null && isScanHeadOpened()) {
+            try {
+                int[] paramIDList = { DecoderConfigValues.ParamID.LIGHTS_MODE };
+                int[] symValue = { mode };
+                scanManager.setSYMValueInts(paramIDList, symValue);
+                Log.d(TAG, "灯光模式设置为:" + mode);
+            } catch (Exception e) {
+                Log.e(TAG, "设置灯光模式失败", e);
+                if (listener != null) {
+                    listener.onScanError("设置灯光模式失败:" + e.getMessage());
+                }
+            }
+        } else {
+            if (listener != null) {
+                listener.onScanError("扫描头未打开,无法设置灯光");
+            }
         }
     }
 
-    /**
-     * 取消单次扫码超时
-     */
-    private void cancelSingleTimeout() {
-        if (singleTimeoutRunnable != null) {
-            scanHandler.removeCallbacks(singleTimeoutRunnable);
-            singleTimeoutRunnable = null;
-        }
+    // -------------------------- 状态查询API --------------------------
+    public boolean isScanning() {
+        return isScanning;
     }
 
-    /**
-     * 取消闲置超时
-     */
-    private void cancelIdleTimeout() {
-        if (idleTimeoutRunnable != null) {
-            scanHandler.removeCallbacks(idleTimeoutRunnable);
-            idleTimeoutRunnable = null;
+    public boolean isScanHeadOpened() {
+        if (scanManager == null) {
+            return false;
         }
+        return scanManager.isScannerOpen();
     }
 
-    /**
-     * 取消所有超时任务
-     */
-    private void cancelAllTimeouts() {
-        cancelSingleTimeout();
-        cancelIdleTimeout();
+    public boolean isScreenOn() {
+        return isScreenOn;
     }
 
-    // -------------------------- 辅助方法 --------------------------
     /**
-     * 暂停扫码(屏幕熄灭时):仅停止解码,保留扫描头
+     * 获取唤醒锁
      */
-    private void pauseScan() {
-        if (scanManager != null && isScanning) {
+    private void acquireWakeLock() {
+        if (wakeLock != null && !wakeLock.isHeld()) {
             try {
-                scanManager.stopDecode();
-                Log.d(TAG, "扫码已暂停(屏幕熄灭)");
+                wakeLock.acquire(ScanConstants.WAKE_LOCK_TIMEOUT_MS);
+                Log.d(TAG, "唤醒锁已获取");
             } catch (Exception e) {
-                Log.e(TAG, "暂停扫码失败", e);
+                Log.e(TAG, "获取唤醒锁失败", e);
             }
         }
-        // 确保在暂停后将扫描状态设置为false,以便在屏幕亮起后能重新开始扫描
-        isScanning = false;
     }
 
     /**
-     * 恢复扫码(屏幕亮起时):重新解码+重置单次超时
+     * 释放唤醒锁
      */
-    private void resumeScan() {
-        if (scanManager != null && isScanHeadOpened()) {
+    private void releaseWakeLock() {
+        if (wakeLock != null && wakeLock.isHeld()) {
             try {
-                scanManager.startDecode();
-                Log.d(TAG, "扫码已恢复(屏幕亮起)");
+                wakeLock.release();
+                Log.d(TAG, "唤醒锁已释放");
             } catch (Exception e) {
-                Log.e(TAG, "恢复扫码失败", e);
-                // 出错时重置扫描状态,以便下次可以重新开始扫描
-                isScanning = false;
+                Log.e(TAG, "释放唤醒锁失败", e);
             }
-        } else {
-            // 如果扫描头未打开,重置状态
-            isScanning = false;
         }
     }
 
+    /**
+     * 释放资源(页面离开时调用)
+     */
+    public void releaseResources() {
+        Log.d(TAG, "释放扫描服务资源");
 
-    private String getLightModeDesc(int mode) {
-        switch (mode) {
-            case ScanConstants.LIGHT_MODE_OFF: return "关闭";
-            case ScanConstants.LIGHT_MODE_AIM_ONLY: return "仅瞄准";
-            case ScanConstants.LIGHT_MODE_ILLUM_ONLY: return "仅照明";
-            case ScanConstants.LIGHT_MODE_ALTERNATE: return "交替";
-            case ScanConstants.LIGHT_MODE_BOTH: return "瞄准+照明";
-            default: return "未知模式(" + mode + ")";
-        }
-    }
+        // 停止扫描
+        stopScan();
 
-    // -------------------------- 基础方法 --------------------------
-    private void acquireWakeLock() {
-        try {
-            PowerManager powerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
-            if (powerManager != null) {
-                wakeLock = powerManager.newWakeLock(
-                        PowerManager.PARTIAL_WAKE_LOCK,
-                        ScanConstants.WAKE_LOCK_TAG
-                );
-                // 唤醒锁时长适配最长闲置时间+单次扫码时间
-                wakeLock.acquire(SCAN_IDLE_TIMEOUT_MS + SCAN_SINGLE_TIMEOUT_MS);
-                Log.d(TAG, "唤醒锁已获取(适配闲置超时)");
-            }
-        } catch (Exception e) {
-            Log.e(TAG, "获取唤醒锁失败", e);
-            if (scanCallback != null) {
-                scanCallback.onScanError("获取唤醒锁失败:" + e.getMessage());
-            }
-        }
-    }
+        // 关闭扫描头
+        closeScanHead();
 
-    // -------------------------- 对外暴露的状态/回调 --------------------------
-    public void setScanCallback(ScanCallback callback) {
-        this.scanCallback = callback;
-    }
+        // 注销屏幕状态广播
+        unregisterScreenStateReceiver();
 
-    public boolean isScanning() {
-        return isScanning;
-    }
+        // 释放唤醒锁
+        releaseWakeLock();
 
-    public boolean isScanHeadOpened() {
-        if (scanManager == null) {
-            return false;
-        }
-        return scanManager.isScannerOpen();
-    }
-    
-    /**
-     * 设置灯光模式
-     */
-    public void setLightingMode(int mode) {
-        if (scanManager != null && isScanHeadOpened()) {
-            try {
-                // {DecoderConfigValues.ParamID.CODE128_ENABLE} 条码模式
-                // {DecoderConfigValues.ParamID.LIGHTS_MODE} 灯光模式
-                int[] paramIDList = {DecoderConfigValues.ParamID.LIGHTS_MODE};
-                int[] symValue = {mode};
-                scanManager.setSYMValueInts(paramIDList, symValue);
-                Log.d(TAG, "灯光模式设置为:" + getLightModeDesc(mode));
-            } catch (Exception e) {
-                Log.e(TAG, "设置灯光模式失败", e);
-                if (scanCallback != null) {
-                    scanCallback.onScanError("设置灯光模式失败:" + e.getMessage());
-                }
-            }
-        } else {
-            if (scanCallback != null) {
-                scanCallback.onScanError("扫描头未打开,无法设置灯光");
-            }
-        }
+        scanManager = null;
+        listener = null;
     }
 
     // -------------------------- 生命周期 --------------------------
     @Override
     public void onDestroy() {
         super.onDestroy();
-        Log.d(TAG, "扫服务销毁");
-        
-        // 彻底关闭扫描头
-        closeScanHead();
-        
+        Log.d(TAG, "扫描服务销毁");
+
+        // 释放资源
+        releaseResources();
+
         // 释放Handler
         if (scanHandler != null) {
             scanHandler.removeCallbacksAndMessages(null);
             scanHandler = null;
         }
-        
-        // 释放唤醒锁
-        if (wakeLock != null && wakeLock.isHeld()) {
-            wakeLock.release();
-            Log.d(TAG, "唤醒锁已释放");
-        }
-        
-        scanCallback = null;
-        scanManager = null;
     }
 
     @Override
     public boolean onUnbind(Intent intent) {
-        // 解绑时关闭扫描头(可选,根据业务调整)
+        // 解绑时关闭扫描头
         closeScanHead();
         return true;
     }

+ 3 - 2
UI/CF.APP/chicken_farm/lib/components/vb_electronic_id_field.dart

@@ -49,19 +49,20 @@ class _VberElectronicIdsFieldState extends State<VberElectronicIdsField> {
   @override
   void initState() {
     super.initState();
-    logger.d('初始化RFID识别组件==>');
     RfidManager.instance.registerCallbacks(
       onTagScanned: _handleRfidsScanned,
       onRFIDScanned: _handleRfidScanned,
       onKeyPress: _handleKeyPress,
       onErrorScanned: _handleScanError,
+      onConnectSuccess: () {
+        ToastUtil.show('读卡器连接成功', duration: 1, bgColor: Colors.green);
+      },
     );
     _isMultiple = widget.multipleScan ?? widget.multiple;
   }
 
   @override
   void dispose() {
-    logger.d('释放RFID识别组件==>');
     RfidManager.instance.disposeRfid();
     super.dispose();
   }

+ 12 - 2
UI/CF.APP/chicken_farm/lib/core/services/pda/rfid_manager.dart

@@ -9,6 +9,7 @@ typedef TagScannedCallback = void Function(List<RfidModel> tags);
 typedef RFIDScannedCallback = void Function(String rfId);
 typedef ScannedErrorCallback = void Function(String error);
 typedef ScannOnKeyPress = void Function(String error);
+typedef ScannOnConnectSuccess = void Function();
 
 /// RFID 工具类 (单例模式)
 class RfidManager {
@@ -26,6 +27,7 @@ class RfidManager {
   RFIDScannedCallback? _onRFIDScanned;
   ScannedErrorCallback? _onErrorScanned;
   ScannOnKeyPress? _onKeyPress;
+  ScannOnConnectSuccess? _onConnectSuccess;
 
   // 连接状态检查相关
   Timer? _connectionCheckTimer;
@@ -56,8 +58,9 @@ class RfidManager {
             case RfidEventType.connectSuccess:
               errorCount = 0;
               _stopConnectionChecking();
-              ToastUtil.success("电子编号读卡器连接成功");
+              // ToastUtil.success("电子编号读卡器连接成功");
               logger.i("✅ 设备连接成功: ${event.data}");
+              _onConnectSuccess?.call();
               break;
             case RfidEventType.connectFailed:
               _stopConnectionChecking();
@@ -114,11 +117,17 @@ class RfidManager {
     RFIDScannedCallback? onRFIDScanned,
     ScannedErrorCallback? onErrorScanned,
     ScannOnKeyPress? onKeyPress,
-  }) {
+    ScannOnConnectSuccess? onConnectSuccess,
+  }) async {
+    logger.i("✅ 注册RFID回调函数");
     _onTagScanned = onTagScanned;
     _onRFIDScanned = onRFIDScanned;
     _onErrorScanned = onErrorScanned;
     _onKeyPress = onKeyPress;
+    _onConnectSuccess = onConnectSuccess;
+    // if (await RfidChannel.isConnected()) {
+    //   _onConnectSuccess?.call();
+    // }
   }
 
   void clearCallbacks() {
@@ -126,6 +135,7 @@ class RfidManager {
     _onRFIDScanned = null;
     _onErrorScanned = null;
     _onKeyPress = null;
+    _onConnectSuccess = null;
   }
 
   Future<void> connect() async {

+ 31 - 5
UI/CF.APP/chicken_farm/lib/core/services/pda/scan_channel.dart

@@ -12,6 +12,7 @@ class ScanChannel {
     required Function(String) onScanResult,
     required Function(String) onScanError,
     Function(bool, String)? onKeyPress,
+    Function(bool)? onScanHeadStateChanged,
   }) {
     _channel.setMethodCallHandler((MethodCall call) async {
       switch (call.method) {
@@ -33,12 +34,29 @@ class ScanChannel {
             onKeyPress(true, call.arguments);
           }
           break;
+        case 'onScanHeadStateChanged': // 处理扫描头状态变化事件
+          logger.d("扫描头状态变化:${call.arguments}");
+          if (onScanHeadStateChanged != null) {
+            onScanHeadStateChanged(call.arguments as bool);
+          }
+          break;
         default:
           break;
       }
     });
   }
 
+  /// 初始化扫描服务
+  static Future<bool> init() async {
+    try {
+      final bool result = await _channel.invokeMethod('init');
+      return result;
+    } on PlatformException catch (e) {
+      logger.e('扫描服务初始化失败: ${e.message}');
+      return false;
+    }
+  }
+
   // -------------------------- 扫描头管理API --------------------------
   /// 打开扫描头(进入扫码场景时调用)
   static Future<bool> openScanHead() async {
@@ -63,10 +81,10 @@ class ScanChannel {
   /// 重置扫描头闲置超时(手动刷新闲置计时)
   static Future<bool> resetIdleTimeout() async {
     try {
-      final bool result = await _channel.invokeMethod('resetIdleTimeout');
+      final bool result = await _channel.invokeMethod('resetTimeout');
       return result;
     } on PlatformException catch (e) {
-      throw Exception('重置闲置超时失败:${e.message}');
+      throw Exception('重置超时失败:${e.message}');
     }
   }
 
@@ -82,10 +100,9 @@ class ScanChannel {
   }
 
   /// 停止单次扫码(保留扫描头)
-  static Future<bool> stopSingleScan() async {
+  static Future<void> stopSingleScan() async {
     try {
-      final bool result = await _channel.invokeMethod('stopSingleScan');
-      return result;
+      await _channel.invokeMethod('stopScan');
     } on PlatformException catch (e) {
       throw Exception('停止扫码失败:${e.message}');
     }
@@ -130,4 +147,13 @@ class ScanChannel {
   static void dispose() {
     _channel.setMethodCallHandler(null);
   }
+
+  /// 释放所有资源
+  static Future<void> releaseResources() async {
+    try {
+      await _channel.invokeMethod('releaseResources');
+    } on PlatformException catch (e) {
+      logger.e('释放资源失败: ${e.message}');
+    }
+  }
 }

+ 216 - 0
UI/CF.APP/chicken_farm/lib/core/services/pda/scan_manager.dart

@@ -0,0 +1,216 @@
+import 'package:chicken_farm/core/config/app_config.dart';
+import 'package:chicken_farm/core/utils/logger.dart';
+import 'package:chicken_farm/core/utils/toast.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter/widgets.dart';
+import 'scan_channel.dart';
+import 'dart:async';
+
+typedef ScanResultCallback = void Function(String result);
+typedef ScanErrorCallback = void Function(String error);
+typedef ScanKeyPressCallback = void Function(bool isDoubleClick, String key);
+typedef ScanHeadStateChangedCallback = void Function(bool isOpen);
+
+/// 扫描管理类 (单例模式)
+class ScanManager {
+  // 单例实例
+  static final ScanManager _instance = ScanManager._internal();
+
+  factory ScanManager() {
+    _instance.init();
+    return _instance;
+  }
+
+  // 回调函数
+  ScanResultCallback? _onScanResult;
+  ScanErrorCallback? _onScanError;
+  ScanKeyPressCallback? _onKeyPress;
+  ScanHeadStateChangedCallback? _onScanHeadStateChanged;
+
+  // 初始化状态标志
+  bool _isInitialized = false;
+
+  // 私有构造函数
+  ScanManager._internal();
+
+  // 获取单例实例
+  static ScanManager get instance => ScanManager();
+
+  // 初始化
+  Future<void> init() async {
+    if (_isInitialized || !AppConfig.isPda) {
+      return;
+    }
+    _isInitialized = true;
+
+    try {
+      // 初始化监听
+      ScanChannel.initScanListener(
+        onScanResult: (String result) {
+          logger.i("🔍 扫描结果: $result");
+          _onScanResult?.call(result);
+        },
+        onScanError: (String error) {
+          logger.e("❌ 扫描错误: $error");
+          _onScanError?.call(error);
+        },
+        onKeyPress: (bool isDoubleClick, String key) {
+          logger.d("⌨️ 按键事件: $key, 双击: $isDoubleClick");
+          _onKeyPress?.call(isDoubleClick, key);
+        },
+        onScanHeadStateChanged: (bool isOpen) {
+          // logger.d("📡 扫描头状态变化: ${isOpen ? '打开' : '关闭'}");
+
+          _onScanHeadStateChanged?.call(isOpen);
+        },
+      );
+
+      // 初始化扫描服务
+      await ScanChannel.init();
+
+      logger.i("✅ 扫描管理器初始化完成");
+    } catch (e) {
+      logger.e("❌ 扫描管理器初始化错误: $e");
+    }
+  }
+
+  // 注册回调函数
+  void registerCallbacks({
+    ScanResultCallback? onScanResult,
+    ScanErrorCallback? onScanError,
+    ScanKeyPressCallback? onKeyPress,
+    ScanHeadStateChangedCallback? onScanHeadStateChanged,
+  }) {
+    logger.d("✅ 注册扫描回调函数");
+    _onScanResult = onScanResult;
+    _onScanError = onScanError;
+    _onKeyPress = onKeyPress;
+    _onScanHeadStateChanged = onScanHeadStateChanged;
+  }
+
+  void clearCallbacks() {
+    _onScanResult = null;
+    _onScanError = null;
+    _onKeyPress = null;
+    _onScanHeadStateChanged = null;
+  }
+
+  /// 打开扫描头
+  Future<bool> openScanHead() async {
+    try {
+      final bool result = await ScanChannel.openScanHead();
+      if (result) {
+        logger.i("▶️ 扫描头已打开");
+      } else {
+        logger.e("❌ 扫描头打开失败");
+      }
+      return result;
+    } catch (e) {
+      logger.e("❌ 打开扫描头异常: $e");
+      return false;
+    }
+  }
+
+  /// 关闭扫描头
+  Future<bool> closeScanHead() async {
+    try {
+      final bool result = await ScanChannel.closeScanHead();
+      if (result) {
+        logger.i("⏹️ 扫描头已关闭");
+      } else {
+        logger.e("❌ 扫描头关闭失败");
+      }
+      return result;
+    } catch (e) {
+      logger.e("❌ 关闭扫描头异常: $e");
+      return false;
+    }
+  }
+
+  /// 开始扫描
+  Future<bool> startScan() async {
+    try {
+      final bool result = await ScanChannel.startScan();
+      if (result) {
+        logger.i("▶️ 开始扫描");
+      } else {
+        logger.e("❌ 扫描启动失败");
+      }
+      return result;
+    } catch (e) {
+      logger.e("❌ 开始扫描异常: $e");
+      return false;
+    }
+  }
+
+  /// 停止扫描
+  Future<void> stopScan() async {
+    try {
+      await ScanChannel.stopSingleScan();
+    } catch (e) {
+      logger.e("❌ 停止扫描异常: $e");
+    }
+  }
+
+  /// 重置超时
+  Future<bool> resetTimeout() async {
+    try {
+      final bool result = await ScanChannel.resetIdleTimeout();
+      if (result) {
+        logger.i("🔄 超时已重置");
+      } else {
+        logger.e("❌ 重置超时失败");
+      }
+      return result;
+    } catch (e) {
+      logger.e("❌ 重置超时异常: $e");
+      return false;
+    }
+  }
+
+  /// 设置灯光模式
+  Future<String> setLightingMode(int mode) async {
+    try {
+      final String result = await ScanChannel.setLightingMode(mode);
+      logger.i("💡 灯光模式设置为: $mode");
+      return result;
+    } catch (e) {
+      logger.e("❌ 设置灯光模式异常: $e");
+      rethrow;
+    }
+  }
+
+  /// 检查是否正在扫描
+  Future<bool> isScanning() async {
+    try {
+      final bool result = await ScanChannel.isScanning();
+      return result;
+    } catch (e) {
+      logger.e("❌ 检查扫描状态异常: $e");
+      return false;
+    }
+  }
+
+  /// 检查扫描头是否打开
+  Future<bool> isScanHeadOpened() async {
+    try {
+      final bool result = await ScanChannel.isScanHeadOpened();
+      return result;
+    } catch (e) {
+      logger.e("❌ 检查扫描头状态异常: $e");
+      return false;
+    }
+  }
+
+  /// 释放通道资源
+  void disposeScan() {
+    try {
+      _isInitialized = false;
+      ScanChannel.releaseResources();
+      clearCallbacks();
+      logger.i("🔚 扫描通道已释放");
+    } catch (e) {
+      logger.e("❌ 释放扫描资源异常: $e");
+    }
+  }
+}

+ 35 - 105
UI/CF.APP/chicken_farm/lib/pages/breeding/cage_change_page.dart

@@ -1,12 +1,11 @@
 import 'package:chicken_farm/apis/index.dart';
+import 'package:chicken_farm/core/services/pda/scan_manager.dart';
 import 'package:chicken_farm/core/utils/datetime_util.dart';
 import 'package:chicken_farm/core/utils/logger.dart';
 import 'package:flutter/material.dart';
 import 'package:chicken_farm/components/vb_app_bar.dart';
 import 'package:chicken_farm/core/utils/toast.dart';
-import 'package:chicken_farm/core/services/pda/scan_channel.dart';
 import 'package:chicken_farm/components/vb_electronic_id_field.dart';
-import 'package:go_router/go_router.dart';
 
 class CageChangePage extends StatefulWidget {
   const CageChangePage({super.key});
@@ -28,92 +27,47 @@ class _CageChangePageState extends State<CageChangePage> {
 
     _isScanningCode = false;
     _cageController.clear();
-
-    WidgetsBinding.instance.addPostFrameCallback((_) {
-      ScanChannel.openScanHead().then((success) {
-        if (success) {
-          logger.d("扫描头已打开");
+    logger.d("页面初始化");
+    ScanManager.instance.registerCallbacks(
+      onScanResult: (result) {
+        setState(() {
+          logger.d("扫描目标笼号:$result");
+          _cageController.text = result;
+          _isScanningCode = false;
+        });
+        ScanManager.instance.stopScan();
+      },
+      onScanError: (error) {
+        logger.d("扫码错误:$error");
+        setState(() {
+          _isScanningCode = false;
+        });
+      },
+      onKeyPress: (bool isDouble, String keyCode) {
+        if (isDouble && keyCode == "KEY_619") {
+          _cageController.clear();
+          ScanManager.instance.startScan();
         } else {
-          ToastUtil.errorAlert("扫描头打开失败");
-          if (mounted) {
-            context.pop();
-          }
+          logger.d("按键:$isDouble $keyCode");
         }
-      });
-
-      // 初始化监听
-      ScanChannel.initScanListener(
-        onScanResult: (result) {
-          // if (_scanTag == 1) {
-          //   // 源笼号
-          //   setState(() {
-          //     _sourceCageController.text = result;
-          //     _isScanningSource = false;
-          //   });
-          //   if (_targetCageController.text.isEmpty) {
-          //     // 源笼号扫描成功后自动延时扫描目标笼号
-          //     ScanChannel.stopSingleScan();
-          //     logger.d("自动扫描目标笼号");
-          //     _targetCageFocusNode.requestFocus();
-          //     _dealyScanCode(2);
-          //   }
-          // } else if (_scanTag == 2) {
-          //   // 目标笼号
-          //   setState(() {
-          //     _targetCageController.text = result;
-          //     _isScanningTarget = false;
-          //   });
-          // }
-          // // 目标笼号
-          // setState(() {
-          //   logger.d("扫描目标笼号:$result");
-          //   _targetCageController.text = result;
-          //   _isScanningTarget = false;
-          // });
-          setState(() {
-            logger.d("扫描目标笼号:$result");
-            _cageController.text = result;
-            _isScanningCode = false;
-          });
-          // 扫码成功后停止解码(保留扫描头)
-          ScanChannel.stopSingleScan();
-        },
-        onScanError: (error) {
-          logger.d("扫码错误:$error");
-          setState(() {
-            _isScanningCode = false;
-          });
-        },
-        onKeyPress: (bool isDouble, String keyCode) {
-          if (isDouble && keyCode == "KEY_619") {
-            // _sourceCageController.clear();
-            // _targetCageController.clear();
-            _cageController.clear();
-            // _scanTag = 1;
-            ScanChannel.startScan();
-          } else {
-            logger.d("按键:$isDouble $keyCode");
-          }
-        },
-      );
-    });
+      },
+      onScanHeadStateChanged: (bool isOpen) {
+        if (isOpen) {
+          ToastUtil.show("扫描组件已打开", duration: 1, bgColor: Colors.green);
+        } else {
+          ToastUtil.show("扫描组件已关闭", duration: 0.5);
+        }
+        setState(() {});
+      },
+    );
   }
 
   @override
   void dispose() {
-    // 释放TextEditingControllers
-    // _sourceCageController.dispose();
-    // _targetCageController.dispose();
     _cageController.dispose();
 
-    // 释放FocusNode
-    // _sourceCageFocusNode.dispose();
-    // _targetCageFocusNode.dispose();
-
-    // 手动关闭扫描头,立即释放资源
-    ScanChannel.closeScanHead();
     // 释放通道
-    ScanChannel.dispose();
+    ScanManager.instance.disposeScan();
     super.dispose();
   }
 
@@ -295,7 +249,7 @@ class _CageChangePageState extends State<CageChangePage> {
                 IconButton(
                   icon: const Icon(Icons.refresh, size: 20),
                   onPressed: () {
-                    _handleChangeCageCode();
+                    _handleScanCageCode();
                   },
                 ),
               ] else ...[
@@ -358,36 +312,12 @@ class _CageChangePageState extends State<CageChangePage> {
     setState(() {
       _isScanningCode = true;
     });
-    bool success = await ScanChannel.startScan();
+    bool success = await ScanManager.instance.startScan();
     if (!success) {
       ToastUtil.error("扫码失败");
     }
   }
 
-  void _handleChangeCageCode() async {
-    if (!await ScanChannel.isScanHeadOpened()) {
-      logger.w("扫描头未打开,正在重新打开");
-      await ScanChannel.openScanHead().then((success) async {
-        if (success) {
-          success = await ScanChannel.startScan();
-          if (!success) {
-            ToastUtil.error("扫码失败");
-          }
-        } else {
-          ToastUtil.errorAlert("扫描头打开失败");
-          if (mounted) {
-            context.pop();
-          }
-        }
-      });
-    } else {
-      bool success = await ScanChannel.startScan();
-      if (!success) {
-        ToastUtil.error("扫码失败");
-      }
-    }
-  }
-
   // 移除指定索引的电子编号
   void _removeElectronicId(int index) {
     setState(() {