瀏覽代碼

Add 添加蓝牙接口(未调试)

Yue 6 天之前
父節點
當前提交
dbb8cae6ee

+ 15 - 1
UI/CF.APP/chicken_farm/android/app/src/main/AndroidManifest.xml

@@ -2,6 +2,12 @@
     <uses-permission android:name="android.permission.CAMERA" />
      <!-- 唤醒锁权限 -->
     <uses-permission android:name="android.permission.WAKE_LOCK" />
+    <!-- 蓝牙权限-->
+    <uses-permission android:name="android.permission.BLUETOOTH" android:maxSdkVersion="30" />
+    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" android:maxSdkVersion="30" />
+    <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
+    <uses-permission android:name="android.permission.BLUETOOTH_SCAN" android:usesPermissionFlags="neverForLocation" />
+    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" android:maxSdkVersion="30" />
 
     <application
         android:label="chicken_farm"
@@ -32,7 +38,11 @@
         <!-- Don't delete the meta-data below.
              This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
 
-        <!-- 注册扫码服务 -->
+        <!-- 蓝牙功能声明 -->
+        <uses-feature android:name="android.hardware.bluetooth" android:required="true" />
+        <uses-feature android:name="android.hardware.bluetooth_le" android:required="false" />
+
+        <!-- 注册服务 -->
         <service
             android:name="com.vber.chicken_farm.scan.ScanService"
             android:exported="true" 
@@ -41,6 +51,10 @@
         <service android:name="com.vber.chicken_farm.rfid.RfidService"
             android:foregroundServiceType="dataSync"
             android:exported="false"/>
+        <service android:name="com.vber.chicken_farm.bluetooth.core.BluetoothSerialService" 
+            android:foregroundServiceType="dataSync"
+            android:exported="false"/>
+    
         <meta-data
             android:name="flutterEmbedding"
             android:value="2" />

+ 266 - 0
UI/CF.APP/chicken_farm/android/app/src/main/java/com/vber/chicken_farm/bluetooth/BluetoothMethodCallHandler.java

@@ -0,0 +1,266 @@
+package com.vber.chicken_farm.bluetooth;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.IBinder;
+import android.util.Log;
+
+import com.vber.chicken_farm.bluetooth.core.BluetoothConstants;
+import com.vber.chicken_farm.bluetooth.core.BluetoothDeviceCallback;
+import com.vber.chicken_farm.bluetooth.core.BluetoothDeviceInfo;
+import com.vber.chicken_farm.bluetooth.core.BluetoothSerialService;
+import com.vber.chicken_farm.bluetooth.scale.BluetoothScale;
+
+import java.util.List;
+
+import io.flutter.embedding.engine.plugins.FlutterPlugin;
+import io.flutter.plugin.common.BinaryMessenger;
+import io.flutter.plugin.common.MethodCall;
+import io.flutter.plugin.common.MethodChannel;
+import io.flutter.plugin.common.MethodChannel.Result;
+
+/**
+ * 通用蓝牙设备Flutter通信处理器
+ * 支持多设备类型扩展 + 蓝牙扫描功能
+ */
+public class BluetoothMethodCallHandler implements MethodCallHandler, BluetoothDeviceCallback {
+    private static final String TAG = "BluetoothHandler";
+    private final Context context;
+    private final MethodChannel channel;
+
+    // 服务相关
+    private BluetoothSerialService serialService;
+    private boolean isServiceBound = false;
+
+    // 业务设备实例
+    private BluetoothScale bluetoothScale;
+
+    // 服务连接回调
+    private final ServiceConnection serviceConnection = new ServiceConnection() {
+        @Override
+        public void onServiceConnected(ComponentName name, IBinder service) {
+            Log.d(TAG, "通用蓝牙串口服务绑定成功");
+            BluetoothSerialService.BluetoothSerialBinder binder = (BluetoothSerialService.BluetoothSerialBinder) service;
+            serialService = binder.getService();
+            serialService.setGlobalCallback(BluetoothMethodCallHandler.this); // 设置扫描回调
+            isServiceBound = true;
+
+            // 初始化蓝牙秤实例
+            bluetoothScale = new BluetoothScale(serialService);
+            bluetoothScale.setCallback(BluetoothMethodCallHandler.this);
+        }
+
+        @Override
+        public void onServiceDisconnected(ComponentName name) {
+            Log.d(TAG, "通用蓝牙串口服务解绑");
+            serialService = null;
+            isServiceBound = false;
+        }
+    };
+
+    // 构造方法
+    public BluetoothMethodCallHandler(Context context, BinaryMessenger messenger) {
+        this.context = context;
+        // 通用蓝牙通道(所有设备共用)
+        this.channel = new MethodChannel(messenger, BluetoothConstants.CHANNEL_PREFIX + "common");
+        this.channel.setMethodCallHandler(this);
+        // 绑定通用蓝牙服务
+        bindSerialService();
+        Log.d(TAG, "通用蓝牙MethodChannel初始化完成");
+    }
+
+    /**
+     * 绑定通用蓝牙串口服务
+     */
+    private void bindSerialService() {
+        try {
+            Intent intent = new Intent(context, BluetoothSerialService.class);
+            context.bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
+        } catch (Exception e) {
+            Log.e(TAG, "绑定通用蓝牙串口服务失败", e);
+        }
+    }
+
+    /**
+     * 处理Flutter方法调用
+     * 格式:
+     *   扫描:scan.start / scan.stop
+     *   设备操作:{deviceType}.{method} → 例如 "scale.connect"
+     */
+    @Override
+    public void onMethodCall(MethodCall call, Result result) {
+        Log.d(TAG, "收到Flutter调用: " + call.method);
+
+        // 校验服务绑定
+        if (!isServiceBound || serialService == null) {
+            result.error(BluetoothConstants.ERROR_SERVICE_NOT_BIND, "蓝牙服务未绑定", null);
+            return;
+        }
+
+        // 优先处理扫描相关方法
+        if (call.method.startsWith("scan.")) {
+            handleScanMethodCall(call.method.substring(5), call, result);
+            return;
+        }
+
+        // 解析设备类型方法
+        String[] methodParts = call.method.split("\\.");
+        if (methodParts.length != 2) {
+            result.notImplemented();
+            return;
+        }
+
+        String deviceType = methodParts[0];
+        String method = methodParts[1];
+
+        // 根据设备类型分发处理
+        switch (deviceType) {
+            case BluetoothConstants.DEVICE_TYPE_SCALE:
+                handleScaleMethodCall(method, call, result);
+                break;
+            case BluetoothConstants.DEVICE_TYPE_PRINTER:
+                // 扩展:蓝牙打印机处理逻辑
+                result.notImplemented();
+                break;
+            case BluetoothConstants.DEVICE_TYPE_SCANNER:
+                // 扩展:蓝牙扫码枪处理逻辑
+                result.notImplemented();
+                break;
+            default:
+                result.notImplemented();
+                break;
+        }
+    }
+
+    // --------------------- 处理扫描方法调用 ---------------------
+    private void handleScanMethodCall(String method, MethodCall call, Result result) {
+        switch (method) {
+            case "start":
+                // 获取扫描时长(默认10秒)
+                long duration = call.argument("duration") != null ?
+                        call.argument("duration") : BluetoothConstants.DEFAULT_SCAN_DURATION_MS;
+                serialService.startScan(duration);
+                result.success(true);
+                break;
+            case "stop":
+                serialService.stopScan();
+                result.success(true);
+                break;
+            default:
+                result.notImplemented();
+                break;
+        }
+    }
+
+    // --------------------- 处理蓝牙秤方法调用 ---------------------
+    private void handleScaleMethodCall(String method, MethodCall call, Result result) {
+        if (bluetoothScale == null) {
+            result.error(BluetoothConstants.ERROR_SERVICE_NOT_BIND, "蓝牙秤实例未初始化", null);
+            return;
+        }
+
+        switch (method) {
+            case "connect":
+                String address = call.argument("address");
+                bluetoothScale.connect(address);
+                result.success(true);
+                break;
+            case "disconnect":
+                bluetoothScale.disconnect();
+                result.success(true);
+                break;
+            case "sendGetWeightCommand":
+                boolean sendSuccess = bluetoothScale.sendGetWeightCommand();
+                result.success(sendSuccess);
+                break;
+            case "sendCommand":
+                String command = call.argument("command");
+                boolean commandSuccess = bluetoothScale.sendStringData(command);
+                result.success(commandSuccess);
+                break;
+            case "getConnectionState":
+                result.success(bluetoothScale.getConnectionState());
+                break;
+            case "isConnected":
+                result.success(bluetoothScale.isConnected());
+                break;
+            default:
+                result.notImplemented();
+                break;
+        }
+    }
+
+    // --------------------- BluetoothDeviceCallback 实现 ---------------------
+    @Override
+    public void onConnectionStateChanged(String deviceType, int state) {
+        channel.invokeMethod(deviceType + ".onConnectionStateChanged", state);
+    }
+
+    @Override
+    public void onRawDataReceived(String deviceType, byte[] data) {
+        // 可选:转发原始数据给Flutter
+        channel.invokeMethod(deviceType + ".onRawDataReceived", new String(data));
+    }
+
+    @Override
+    public void onBusinessDataReceived(String deviceType, String data) {
+        // 转发解析后的业务数据给Flutter
+        channel.invokeMethod(deviceType + ".onBusinessDataReceived", data);
+    }
+
+    @Override
+    public void onError(String deviceType, String errorCode, String errorMsg) {
+        // 转发错误信息给Flutter
+        channel.invokeMethod(deviceType + ".onError", new String[]{errorCode, errorMsg});
+    }
+
+    @Override
+    public void onScanStateChanged(int state) {
+        channel.invokeMethod("scan.onScanStateChanged", state);
+    }
+
+    @Override
+    public void onDeviceDiscovered(BluetoothDeviceInfo device) {
+        channel.invokeMethod("scan.onDeviceDiscovered", device.toJson());
+    }
+
+    @Override
+    public void onScanCompleted(List<BluetoothDeviceInfo> devices) {
+        // 转换为JSON数组
+        StringBuilder jsonArray = new StringBuilder("[");
+        for (int i = 0; i < devices.size(); i++) {
+            jsonArray.append(devices.get(i).toJson());
+            if (i < devices.size() - 1) {
+                jsonArray.append(",");
+            }
+        }
+        jsonArray.append("]");
+        channel.invokeMethod("scan.onScanCompleted", jsonArray.toString());
+    }
+
+    /**
+     * 释放资源
+     */
+    public void dispose() {
+        Log.d(TAG, "释放通用蓝牙通信资源");
+        if (isServiceBound) {
+            if (serialService != null) {
+                serialService.stopScan(); // 停止扫描
+                serialService.releaseAllConnections();
+            }
+            context.unbindService(serviceConnection);
+            isServiceBound = false;
+        }
+        channel.setMethodCallHandler(null);
+    }
+
+    // --------------------- Flutter插件注册 ---------------------
+    public static void registerWith(FlutterPlugin.FlutterPluginBinding binding) {
+        new BluetoothMethodCallHandler(
+                binding.getApplicationContext(),
+                binding.getBinaryMessenger()
+        );
+    }
+}

+ 48 - 0
UI/CF.APP/chicken_farm/android/app/src/main/java/com/vber/chicken_farm/bluetooth/core/BluetoothConstants.java

@@ -0,0 +1,48 @@
+package com.vber.chicken_farm.bluetooth.core;
+
+/**
+ * 通用蓝牙设备通信常量
+ */
+public final class BluetoothConstants {
+    // 通用通道前缀
+    public static final String CHANNEL_PREFIX = "com.vber.chicken_farm/bluetooth_";
+    
+    // 设备类型
+    public static final String DEVICE_TYPE_SCALE = "scale";       // 蓝牙秤
+    public static final String DEVICE_TYPE_PRINTER = "printer";   // 蓝牙打印机
+    public static final String DEVICE_TYPE_SCANNER = "scanner";   // 蓝牙扫码枪
+
+    // 连接状态
+    public static final int STATE_DISCONNECTED = 0;
+    public static final int STATE_CONNECTING = 1;
+    public static final int STATE_CONNECTED = 2;
+
+    // 扫描状态
+    public static final int SCAN_STATE_IDLE = 0;         // 未扫描
+    public static final int SCAN_STATE_SCANNING = 1;     // 扫描中
+    public static final int SCAN_STATE_STOPPED = 2;      // 已停止
+
+    // 通用错误码
+    public static final String ERROR_BLUETOOTH_NOT_SUPPORT = "BLUETOOTH_NOT_SUPPORT";
+    public static final String ERROR_BLUETOOTH_DISABLED = "BLUETOOTH_DISABLED";
+    public static final String ERROR_SCAN_PERMISSION_DENIED = "SCAN_PERMISSION_DENIED";
+    public static final String ERROR_DEVICE_NOT_FOUND = "DEVICE_NOT_FOUND";
+    public static final String ERROR_CONNECTION_FAILED = "CONNECTION_FAILED";
+    public static final String ERROR_DISCONNECT_FAILED = "DISCONNECT_FAILED";
+    public static final String ERROR_SEND_DATA_FAILED = "SEND_DATA_FAILED";
+    public static final String ERROR_READ_DATA_FAILED = "READ_DATA_FAILED";
+    public static final String ERROR_SERVICE_NOT_BIND = "SERVICE_NOT_BIND";
+    public static final String ERROR_SCAN_FAILED = "SCAN_FAILED";
+
+    // 通用超时配置
+    public static final int DEFAULT_CONNECT_TIMEOUT_MS = 10000;
+    public static final int DEFAULT_READ_TIMEOUT_MS = 5000;
+    public static final int DEFAULT_SCAN_DURATION_MS = 10000;    // 默认扫描时长
+
+    // 标准蓝牙串口UUID
+    public static final String UUID_SERIAL_PORT = "00001101-0000-1000-8000-00805F9B34FB";
+
+    private BluetoothConstants() {
+        // 禁止实例化
+    }
+}

+ 62 - 0
UI/CF.APP/chicken_farm/android/app/src/main/java/com/vber/chicken_farm/bluetooth/core/BluetoothDevice.java

@@ -0,0 +1,62 @@
+package com.vber.chicken_farm.bluetooth.core;
+
+/**
+ * 通用蓝牙设备接口
+ * 所有蓝牙设备需实现此接口,统一通信规范
+ */
+public interface BluetoothDevice {
+    /**
+     * 获取设备类型
+     */
+    String getDeviceType();
+
+    /**
+     * 连接设备
+     * @param deviceAddress 蓝牙设备MAC地址
+     */
+    void connect(String deviceAddress);
+
+    /**
+     * 断开连接
+     */
+    void disconnect();
+
+    /**
+     * 发送数据
+     * @param data 发送的字节数据
+     * @return 是否发送成功
+     */
+    boolean sendData(byte[] data);
+
+    /**
+     * 发送字符串数据(默认UTF-8编码)
+     * @param data 字符串数据
+     * @return 是否发送成功
+     */
+    default boolean sendStringData(String data) {
+        return sendData(data.getBytes());
+    }
+
+    /**
+     * 获取当前连接状态
+     */
+    int getConnectionState();
+
+    /**
+     * 是否已连接
+     */
+    boolean isConnected();
+
+    /**
+     * 设置回调
+     * @param callback 回调接口
+     */
+    void setCallback(BluetoothDeviceCallback callback);
+
+    /**
+     * 解析原始数据为业务数据
+     * @param rawData 原始字节数据
+     * @return 解析后的业务数据(JSON字符串)
+     */
+    String parseRawDataToBusinessData(byte[] rawData);
+}

+ 59 - 0
UI/CF.APP/chicken_farm/android/app/src/main/java/com/vber/chicken_farm/bluetooth/core/BluetoothDeviceCallback.java

@@ -0,0 +1,59 @@
+package com.vber.chicken_farm.bluetooth.core;
+
+import android.bluetooth.BluetoothDevice;
+
+import com.vber.chicken_farm.bluetooth.core.BluetoothDeviceInfo;
+
+import java.util.List;
+
+/**
+ * 通用蓝牙设备回调接口
+ */
+public interface BluetoothDeviceCallback {
+    /**
+     * 连接状态变化
+     * @param deviceType 设备类型(参考BluetoothConstants.DEVICE_TYPE_*)
+     * @param state 连接状态(参考BluetoothConstants.STATE_*)
+     */
+    void onConnectionStateChanged(String deviceType, int state);
+
+    /**
+     * 接收数据回调(原始数据)
+     * @param deviceType 设备类型
+     * @param data 原始字节数据
+     */
+    void onRawDataReceived(String deviceType, byte[] data);
+
+    /**
+     * 业务数据回调(解析后)
+     * @param deviceType 设备类型
+     * @param data 解析后的业务数据(JSON字符串/Map)
+     */
+    void onBusinessDataReceived(String deviceType, String data);
+
+    /**
+     * 错误回调
+     * @param deviceType 设备类型
+     * @param errorCode 错误码(参考BluetoothConstants.ERROR_*)
+     * @param errorMsg 错误信息
+     */
+    void onError(String deviceType, String errorCode, String errorMsg);
+
+    /**
+     * 扫描状态变化
+     * @param state 扫描状态(参考BluetoothConstants.SCAN_STATE_*)
+     */
+    void onScanStateChanged(int state);
+
+    /**
+     * 发现蓝牙设备回调
+     * @param device 蓝牙设备信息
+     */
+    void onDeviceDiscovered(BluetoothDeviceInfo device);
+
+    /**
+     * 扫描完成回调(返回所有发现的设备)
+     * @param devices 设备列表
+     */
+    void onScanCompleted(List<BluetoothDeviceInfo> devices);
+}

+ 30 - 0
UI/CF.APP/chicken_farm/android/app/src/main/java/com/vber/chicken_farm/bluetooth/core/BluetoothDeviceInfo.java

@@ -0,0 +1,30 @@
+package com.vber.chicken_farm.bluetooth.core;
+
+/**
+* 蓝牙设备信息封装类
+*/
+public class BluetoothDeviceInfo {
+   private String name;           // 设备名称
+   private String address;        // MAC地址
+   private int rssi;              // 信号强度
+   private boolean isPaired;      // 是否已配对
+
+   public BluetoothDeviceInfo(String name, String address, int rssi, boolean isPaired) {
+       this.name = name;
+       this.address = address;
+       this.rssi = rssi;
+       this.isPaired = isPaired;
+   }
+
+   // Getter & Setter
+   public String getName() { return name == null ? "未知设备" : name; }
+   public String getAddress() { return address; }
+   public int getRssi() { return rssi; }
+   public boolean isPaired() { return isPaired; }
+
+   // 转为JSON字符串(方便Flutter解析)
+   public String toJson() {
+       return "{\"name\":\"" + getName() + "\",\"address\":\"" + address + "\",\"rssi\":" + rssi + ",\"isPaired\":" + isPaired + "}";
+   }
+}
+

+ 573 - 0
UI/CF.APP/chicken_farm/android/app/src/main/java/com/vber/chicken_farm/bluetooth/core/BluetoothSerialService.java

@@ -0,0 +1,573 @@
+package com.vber.chicken_farm.bluetooth.core;
+
+import android.app.Service;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothManager;
+import android.bluetooth.BluetoothSocket;
+import android.bluetooth.le.BluetoothLeScanner;
+import android.bluetooth.le.ScanCallback;
+import android.bluetooth.le.ScanResult;
+import android.bluetooth.le.ScanSettings;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.util.Log;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.UUID;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * 通用蓝牙串口通信服务
+ * 支持多设备类型复用 + 蓝牙扫描功能
+ */
+public class BluetoothSerialService extends Service {
+    private static final String TAG = "BluetoothSerialService";
+    private final IBinder binder = new BluetoothSerialBinder();
+    private final Handler mainHandler = new Handler(Looper.getMainLooper());
+    private BluetoothAdapter bluetoothAdapter;
+    private BluetoothLeScanner bluetoothLeScanner;
+
+    // 设备连接池:key=设备类型,value=设备连接信息
+    private final ConcurrentHashMap<String, DeviceConnection> deviceConnectionMap = new ConcurrentHashMap<>();
+    
+    // 扫描相关
+    private int scanState = BluetoothConstants.SCAN_STATE_IDLE;
+    private final List<BluetoothDeviceInfo> discoveredDevices = new ArrayList<>();
+    private Handler scanTimeoutHandler;
+    private BluetoothDeviceCallback globalCallback; // 扫描回调使用全局回调
+
+    // 绑定器
+    public class BluetoothSerialBinder extends Binder {
+        public BluetoothSerialService getService() {
+            return BluetoothSerialService.this;
+        }
+    }
+
+    /**
+     * 设备连接信息封装
+     */
+    private static class DeviceConnection {
+        BluetoothSocket socket;
+        InputStream inputStream;
+        OutputStream outputStream;
+        ReadThread readThread;
+        int connectionState = BluetoothConstants.STATE_DISCONNECTED;
+        BluetoothDeviceCallback callback;
+        String deviceAddress;
+    }
+
+    @Override
+    public void onCreate() {
+        super.onCreate();
+        Log.d(TAG, "通用蓝牙串口服务创建");
+        // 初始化蓝牙适配器
+        BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
+        if (bluetoothManager != null) {
+            bluetoothAdapter = bluetoothManager.getAdapter();
+        }
+        // 初始化BLE扫描器
+        if (bluetoothAdapter != null) {
+            bluetoothLeScanner = bluetoothAdapter.getBluetoothLeScanner();
+        }
+    }
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        return binder;
+    }
+
+    // --------------------- 扫描相关核心方法 ---------------------
+    /**
+     * 设置全局回调(用于扫描)
+     */
+    public void setGlobalCallback(BluetoothDeviceCallback callback) {
+        this.globalCallback = callback;
+    }
+
+    /**
+     * 开始扫描蓝牙设备
+     * @param scanDuration 扫描时长(毫秒),0表示一直扫描
+     */
+    public void startScan(long scanDuration) {
+        // 1. 校验蓝牙支持
+        if (bluetoothAdapter == null) {
+            notifyScanError(BluetoothConstants.ERROR_BLUETOOTH_NOT_SUPPORT, "设备不支持蓝牙");
+            return;
+        }
+
+        // 2. 校验蓝牙是否开启
+        if (!bluetoothAdapter.isEnabled()) {
+            notifyScanError(BluetoothConstants.ERROR_BLUETOOTH_DISABLED, "蓝牙未开启,请先开启蓝牙");
+            return;
+        }
+
+        // 3. 校验扫描权限
+        if (checkSelfPermission(android.Manifest.permission.BLUETOOTH_SCAN) != PackageManager.PERMISSION_GRANTED) {
+            notifyScanError(BluetoothConstants.ERROR_SCAN_PERMISSION_DENIED, "缺少蓝牙扫描权限");
+            return;
+        }
+
+        // 4. 校验扫描状态
+        if (scanState == BluetoothConstants.SCAN_STATE_SCANNING) {
+            Log.w(TAG, "蓝牙扫描已在进行中");
+            return;
+        }
+
+        // 5. 初始化扫描
+        scanState = BluetoothConstants.SCAN_STATE_SCANNING;
+        discoveredDevices.clear();
+        notifyScanStateChanged(BluetoothConstants.SCAN_STATE_SCANNING);
+        Log.d(TAG, "开始蓝牙扫描,时长:" + scanDuration + "ms");
+
+        // 6. 先获取已配对设备
+        getPairedDevices();
+
+        // 7. 启动BLE扫描(兼容传统蓝牙)
+        ScanSettings scanSettings = new ScanSettings.Builder()
+                .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
+                .build();
+
+        if (bluetoothLeScanner != null) {
+            bluetoothLeScanner.startScan(null, scanSettings, scanCallback);
+        } else {
+            // 兼容传统蓝牙扫描(API < 21)
+            bluetoothAdapter.startDiscovery();
+        }
+
+        // 8. 设置扫描超时
+        if (scanDuration > 0) {
+            if (scanTimeoutHandler == null) {
+                scanTimeoutHandler = new Handler(Looper.getMainLooper());
+            }
+            scanTimeoutHandler.postDelayed(this::stopScan, scanDuration);
+        }
+    }
+
+    /**
+     * 停止蓝牙扫描
+     */
+    public void stopScan() {
+        if (scanState != BluetoothConstants.SCAN_STATE_SCANNING) {
+            return;
+        }
+
+        // 停止扫描
+        if (bluetoothLeScanner != null) {
+            bluetoothLeScanner.stopScan(scanCallback);
+        } else {
+            bluetoothAdapter.cancelDiscovery();
+        }
+
+        // 取消超时
+        if (scanTimeoutHandler != null) {
+            scanTimeoutHandler.removeCallbacksAndMessages(null);
+        }
+
+        // 更新状态
+        scanState = BluetoothConstants.SCAN_STATE_STOPPED;
+        notifyScanStateChanged(BluetoothConstants.SCAN_STATE_STOPPED);
+        notifyScanCompleted();
+        Log.d(TAG, "蓝牙扫描已停止,发现设备数:" + discoveredDevices.size());
+    }
+
+    /**
+     * 获取已配对的蓝牙设备
+     */
+    private void getPairedDevices() {
+        if (bluetoothAdapter == null) return;
+
+        for (BluetoothDevice device : bluetoothAdapter.getBondedDevices()) {
+            BluetoothDeviceInfo deviceInfo = new BluetoothDeviceInfo(
+                    device.getName(),
+                    device.getAddress(),
+                    0,
+                    true
+            );
+            addDiscoveredDevice(deviceInfo);
+        }
+    }
+
+    /**
+     * 添加发现的设备
+     */
+    private void addDiscoveredDevice(BluetoothDeviceInfo deviceInfo) {
+        // 按MAC地址去重
+        for (BluetoothDeviceInfo info : discoveredDevices) {
+            if (info.getAddress().equals(deviceInfo.getAddress())) {
+                return;
+            }
+        }
+        discoveredDevices.add(deviceInfo);
+        // 通知发现设备
+        if (globalCallback != null) {
+            mainHandler.post(() -> globalCallback.onDeviceDiscovered(deviceInfo));
+        }
+    }
+
+    /**
+     * BLE扫描回调
+     */
+    private final ScanCallback scanCallback = new ScanCallback() {
+        @Override
+        public void onScanResult(int callbackType, ScanResult result) {
+            super.onScanResult(callbackType, result);
+            if (result == null || result.getDevice() == null) return;
+
+            BluetoothDevice device = result.getDevice();
+            BluetoothDeviceInfo deviceInfo = new BluetoothDeviceInfo(
+                    device.getName(),
+                    device.getAddress(),
+                    result.getRssi(),
+                    device.getBondState() == BluetoothDevice.BOND_BONDED
+            );
+            addDiscoveredDevice(deviceInfo);
+        }
+
+        @Override
+        public void onScanFailed(int errorCode) {
+            super.onScanFailed(errorCode);
+            String errorMsg = "扫描失败,错误码:" + errorCode;
+            Log.e(TAG, errorMsg);
+            notifyScanError(BluetoothConstants.ERROR_SCAN_FAILED, errorMsg);
+            stopScan();
+        }
+    };
+
+    /**
+     * 通知扫描状态变化
+     */
+    private void notifyScanStateChanged(int state) {
+        if (globalCallback != null) {
+            mainHandler.post(() -> globalCallback.onScanStateChanged(state));
+        }
+    }
+
+    /**
+     * 通知扫描完成
+     */
+    private void notifyScanCompleted() {
+        if (globalCallback != null) {
+            mainHandler.post(() -> globalCallback.onScanCompleted(new ArrayList<>(discoveredDevices)));
+        }
+    }
+
+    /**
+     * 通知扫描错误
+     */
+    private void notifyScanError(String errorCode, String errorMsg) {
+        if (globalCallback != null) {
+            mainHandler.post(() -> globalCallback.onError("", errorCode, errorMsg));
+        }
+    }
+
+    // --------------------- 设备连接相关方法 ---------------------
+    /**
+     * 初始化设备连接(首次连接前调用)
+     * @param deviceType 设备类型
+     * @param callback 回调接口
+     */
+    public void initDeviceConnection(String deviceType, BluetoothDeviceCallback callback) {
+        if (!deviceConnectionMap.containsKey(deviceType)) {
+            DeviceConnection connection = new DeviceConnection();
+            connection.callback = callback;
+            deviceConnectionMap.put(deviceType, connection);
+            Log.d(TAG, "初始化设备连接: " + deviceType);
+        } else {
+            deviceConnectionMap.get(deviceType).callback = callback;
+        }
+    }
+
+    /**
+     * 连接指定类型的蓝牙设备
+     * @param deviceType 设备类型
+     * @param deviceAddress MAC地址
+     */
+    public void connect(String deviceType, String deviceAddress) {
+        // 校验蓝牙适配器
+        if (bluetoothAdapter == null) {
+            notifyError(deviceType, BluetoothConstants.ERROR_BLUETOOTH_NOT_SUPPORT, "设备不支持蓝牙");
+            return;
+        }
+
+        // 校验设备连接
+        DeviceConnection connection = getDeviceConnection(deviceType);
+        if (connection == null) {
+            notifyError(deviceType, BluetoothConstants.ERROR_DEVICE_NOT_FOUND, "设备连接未初始化");
+            return;
+        }
+
+        // 校验重复连接
+        if (connection.connectionState == BluetoothConstants.STATE_CONNECTING) {
+            Log.w(TAG, deviceType + " 正在连接中,请勿重复调用");
+            return;
+        }
+
+        // 更新状态
+        connection.deviceAddress = deviceAddress;
+        updateConnectionState(deviceType, BluetoothConstants.STATE_CONNECTING);
+
+        // 启动连接线程
+        new ConnectThread(deviceType, deviceAddress).start();
+    }
+
+    /**
+     * 断开指定类型设备的连接
+     * @param deviceType 设备类型
+     */
+    public void disconnect(String deviceType) {
+        DeviceConnection connection = getDeviceConnection(deviceType);
+        if (connection == null || connection.connectionState == BluetoothConstants.STATE_DISCONNECTED) {
+            return;
+        }
+
+        try {
+            // 停止读取线程
+            if (connection.readThread != null) {
+                connection.readThread.interrupt();
+                connection.readThread = null;
+            }
+            // 关闭socket
+            if (connection.socket != null) {
+                connection.socket.close();
+                connection.socket = null;
+            }
+            // 清空流
+            connection.inputStream = null;
+            connection.outputStream = null;
+            // 更新状态
+            updateConnectionState(deviceType, BluetoothConstants.STATE_DISCONNECTED);
+            Log.d(TAG, deviceType + " 蓝牙连接已断开");
+        } catch (IOException e) {
+            Log.e(TAG, deviceType + " 断开连接失败", e);
+            notifyError(deviceType, BluetoothConstants.ERROR_DISCONNECT_FAILED, "断开连接失败: " + e.getMessage());
+        }
+    }
+
+    /**
+     * 发送数据到指定设备
+     * @param deviceType 设备类型
+     * @param data 字节数据
+     * @return 是否发送成功
+     */
+    public boolean sendData(String deviceType, byte[] data) {
+        DeviceConnection connection = getDeviceConnection(deviceType);
+        if (connection == null || connection.connectionState != BluetoothConstants.STATE_CONNECTED || connection.outputStream == null) {
+            notifyError(deviceType, BluetoothConstants.ERROR_SEND_DATA_FAILED, "设备未连接,发送失败");
+            return false;
+        }
+
+        try {
+            connection.outputStream.write(data);
+            connection.outputStream.flush();
+            Log.d(TAG, deviceType + " 发送数据长度: " + data.length);
+            return true;
+        } catch (IOException e) {
+            Log.e(TAG, deviceType + " 发送数据失败", e);
+            notifyError(deviceType, BluetoothConstants.ERROR_SEND_DATA_FAILED, "发送数据失败: " + e.getMessage());
+            return false;
+        }
+    }
+
+    /**
+     * 获取指定设备的连接状态
+     * @param deviceType 设备类型
+     * @return 连接状态
+     */
+    public int getConnectionState(String deviceType) {
+        DeviceConnection connection = getDeviceConnection(deviceType);
+        return connection != null ? connection.connectionState : BluetoothConstants.STATE_DISCONNECTED;
+    }
+
+    /**
+     * 检查指定设备是否已连接
+     * @param deviceType 设备类型
+     * @return 是否连接
+     */
+    public boolean isConnected(String deviceType) {
+        return getConnectionState(deviceType) == BluetoothConstants.STATE_CONNECTED;
+    }
+
+    /**
+     * 释放指定设备的连接资源
+     * @param deviceType 设备类型
+     */
+    public void releaseDeviceConnection(String deviceType) {
+        disconnect(deviceType);
+        deviceConnectionMap.remove(deviceType);
+        Log.d(TAG, "释放设备连接: " + deviceType);
+    }
+
+    /**
+     * 释放所有设备连接资源
+     */
+    public void releaseAllConnections() {
+        for (String deviceType : deviceConnectionMap.keySet()) {
+            disconnect(deviceType);
+        }
+        deviceConnectionMap.clear();
+    }
+
+    // --------------------- 私有工具方法 ---------------------
+    /**
+     * 获取设备连接信息
+     */
+    private DeviceConnection getDeviceConnection(String deviceType) {
+        return deviceConnectionMap.get(deviceType);
+    }
+
+    /**
+     * 更新连接状态并回调
+     */
+    private void updateConnectionState(String deviceType, int state) {
+        DeviceConnection connection = getDeviceConnection(deviceType);
+        if (connection != null) {
+            connection.connectionState = state;
+            mainHandler.post(() -> {
+                if (connection.callback != null) {
+                    connection.callback.onConnectionStateChanged(deviceType, state);
+                }
+            });
+        }
+    }
+
+    /**
+     * 通知错误信息
+     */
+    private void notifyError(String deviceType, String errorCode, String errorMsg) {
+        DeviceConnection connection = getDeviceConnection(deviceType);
+        if (connection != null && connection.callback != null) {
+            mainHandler.post(() -> connection.callback.onError(deviceType, errorCode, errorMsg));
+        }
+    }
+
+    // --------------------- 内部线程类 ---------------------
+    /**
+     * 连接线程
+     */
+    private class ConnectThread extends Thread {
+        private final String deviceType;
+        private final String deviceAddress;
+
+        public ConnectThread(String deviceType, String deviceAddress) {
+            this.deviceType = deviceType;
+            this.deviceAddress = deviceAddress;
+        }
+
+        @Override
+        public void run() {
+            BluetoothDevice bluetoothDevice = bluetoothAdapter.getRemoteDevice(deviceAddress);
+            if (bluetoothDevice == null) {
+                mainHandler.post(() -> {
+                    notifyError(deviceType, BluetoothConstants.ERROR_DEVICE_NOT_FOUND, "未找到蓝牙设备: " + deviceAddress);
+                    updateConnectionState(deviceType, BluetoothConstants.STATE_DISCONNECTED);
+                });
+                return;
+            }
+
+            try {
+                // 创建串口Socket
+                UUID uuid = UUID.fromString(BluetoothConstants.UUID_SERIAL_PORT);
+                BluetoothSocket socket = bluetoothDevice.createRfcommSocketToServiceRecord(uuid);
+
+                // 关闭蓝牙发现(提升连接速度)
+                if (bluetoothAdapter.isDiscovering()) {
+                    bluetoothAdapter.cancelDiscovery();
+                }
+
+                // 连接设备
+                socket.connect();
+
+                // 更新连接信息
+                DeviceConnection connection = getDeviceConnection(deviceType);
+                if (connection != null) {
+                    connection.socket = socket;
+                    connection.inputStream = socket.getInputStream();
+                    connection.outputStream = socket.getOutputStream();
+
+                    // 启动读取线程
+                    connection.readThread = new ReadThread(deviceType);
+                    connection.readThread.start();
+
+                    // 更新连接状态
+                    updateConnectionState(deviceType, BluetoothConstants.STATE_CONNECTED);
+                    Log.d(TAG, deviceType + " 连接成功: " + deviceAddress);
+                }
+            } catch (IOException e) {
+                Log.e(TAG, deviceType + " 连接失败", e);
+                mainHandler.post(() -> {
+                    notifyError(deviceType, BluetoothConstants.ERROR_CONNECTION_FAILED, "连接失败: " + e.getMessage());
+                    updateConnectionState(deviceType, BluetoothConstants.STATE_DISCONNECTED);
+                });
+                // 关闭失败的socket
+                try {
+                    DeviceConnection connection = getDeviceConnection(deviceType);
+                    if (connection != null && connection.socket != null) {
+                        connection.socket.close();
+                    }
+                } catch (IOException closeException) {
+                    Log.e(TAG, deviceType + " 关闭Socket失败", closeException);
+                }
+            }
+        }
+    }
+
+    /**
+     * 数据读取线程
+     */
+    private class ReadThread extends Thread {
+        private final String deviceType;
+        private final byte[] buffer = new byte[1024];
+
+        public ReadThread(String deviceType) {
+            this.deviceType = deviceType;
+        }
+
+        @Override
+        public void run() {
+            DeviceConnection connection = getDeviceConnection(deviceType);
+            if (connection == null) return;
+
+            while (!isInterrupted()) {
+                try {
+                    if (connection.inputStream == null) break;
+
+                    int bytes = connection.inputStream.read(buffer);
+                    if (bytes > 0) {
+                        byte[] data = new byte[bytes];
+                        System.arraycopy(buffer, 0, data, 0, bytes);
+
+                        // 1. 通知原始数据
+                        if (connection.callback != null) {
+                            mainHandler.post(() -> connection.callback.onRawDataReceived(deviceType, data));
+                        }
+                    }
+                } catch (IOException e) {
+                    Log.e(TAG, deviceType + " 读取数据失败", e);
+                    mainHandler.post(() -> {
+                        notifyError(deviceType, BluetoothConstants.ERROR_READ_DATA_FAILED, "读取数据失败: " + e.getMessage());
+                        disconnect(deviceType);
+                    });
+                    break;
+                }
+            }
+        }
+    }
+
+    @Override
+    public void onDestroy() {
+        stopScan(); // 销毁时停止扫描
+        releaseAllConnections();
+        Log.d(TAG, "通用蓝牙串口服务销毁");
+        super.onDestroy();
+    }
+}

+ 160 - 0
UI/CF.APP/chicken_farm/android/app/src/main/java/com/vber/chicken_farm/bluetooth/scale/BluetoothScale.java

@@ -0,0 +1,160 @@
+package com.vber.chicken_farm.bluetooth.scale;
+
+import android.util.Log;
+
+import com.vber.chicken_farm.bluetooth.core.BluetoothConstants;
+import com.vber.chicken_farm.bluetooth.core.BluetoothDevice;
+import com.vber.chicken_farm.bluetooth.core.BluetoothDeviceCallback;
+import com.vber.chicken_farm.bluetooth.core.BluetoothSerialService;
+
+import org.json.JSONObject;
+
+/**
+ * 蓝牙秤业务实现类
+ * 仅处理蓝牙秤的业务逻辑(数据解析、指令封装等)
+ */
+public class BluetoothScale implements BluetoothDevice {
+    private static final String TAG = "BluetoothScale";
+    private final BluetoothSerialService serialService;
+    private BluetoothDeviceCallback callback;
+
+    public BluetoothScale(BluetoothSerialService serialService) {
+        this.serialService = serialService;
+        // 初始化设备连接
+        this.serialService.initDeviceConnection(getDeviceType(), new InternalCallback());
+    }
+
+    @Override
+    public String getDeviceType() {
+        return BluetoothConstants.DEVICE_TYPE_SCALE;
+    }
+
+    @Override
+    public void connect(String deviceAddress) {
+        serialService.connect(getDeviceType(), deviceAddress);
+    }
+
+    @Override
+    public void disconnect() {
+        serialService.disconnect(getDeviceType());
+    }
+
+    @Override
+    public boolean sendData(byte[] data) {
+        return serialService.sendData(getDeviceType(), data);
+    }
+
+    @Override
+    public int getConnectionState() {
+        return serialService.getConnectionState(getDeviceType());
+    }
+
+    @Override
+    public boolean isConnected() {
+        return serialService.isConnected(getDeviceType());
+    }
+
+    @Override
+    public void setCallback(BluetoothDeviceCallback callback) {
+        this.callback = callback;
+    }
+
+    @Override
+    public String parseRawDataToBusinessData(byte[] rawData) {
+        try {
+            // 蓝牙秤数据解析逻辑(根据实际协议调整)
+            String rawStr = new String(rawData).trim();
+            Log.d(TAG, "蓝牙秤原始数据: " + rawStr);
+
+            // 示例协议:"W123.45kg" → 重量123.45kg
+            if (rawStr.startsWith("W") && rawStr.length() > 1) {
+                StringBuilder weightStr = new StringBuilder();
+                StringBuilder unitStr = new StringBuilder();
+
+                for (char c : rawStr.substring(1).toCharArray()) {
+                    if (Character.isDigit(c) || c == '.') {
+                        weightStr.append(c);
+                    } else {
+                        unitStr.append(c);
+                    }
+                }
+
+                float weight = Float.parseFloat(weightStr.toString());
+                String unit = unitStr.toString();
+
+                // 封装为JSON业务数据
+                JSONObject businessData = new JSONObject();
+                businessData.put("weight", weight);
+                businessData.put("unit", unit);
+                return businessData.toString();
+            } else {
+                Log.w(TAG, "无效的蓝牙秤数据格式: " + rawStr);
+                return null;
+            }
+        } catch (Exception e) {
+            Log.e(TAG, "解析蓝牙秤数据失败", e);
+            return null;
+        }
+    }
+
+    /**
+     * 内部回调转发(处理通用服务的原始数据,解析后转发给外部回调)
+     */
+    private class InternalCallback implements BluetoothDeviceCallback {
+        @Override
+        public void onConnectionStateChanged(String deviceType, int state) {
+            if (callback != null) {
+                callback.onConnectionStateChanged(deviceType, state);
+            }
+        }
+
+        @Override
+        public void onRawDataReceived(String deviceType, byte[] data) {
+            // 解析原始数据为业务数据
+            String businessData = parseRawDataToBusinessData(data);
+            if (businessData != null && callback != null) {
+                callback.onBusinessDataReceived(deviceType, businessData);
+            }
+            // 转发原始数据(可选)
+            if (callback != null) {
+                callback.onRawDataReceived(deviceType, data);
+            }
+        }
+
+        @Override
+        public void onBusinessDataReceived(String deviceType, String data) {
+            // 通用服务不处理业务数据,由本类解析后触发
+        }
+
+        @Override
+        public void onError(String deviceType, String errorCode, String errorMsg) {
+            if (callback != null) {
+                callback.onError(deviceType, errorCode, errorMsg);
+            }
+        }
+
+        @Override
+        public void onScanStateChanged(int state) {
+            // 扫描状态由全局回调处理
+        }
+
+        @Override
+        public void onDeviceDiscovered(BluetoothDeviceInfo device) {
+            // 设备发现由全局回调处理
+        }
+
+        @Override
+        public void onScanCompleted(List<BluetoothDeviceInfo> devices) {
+            // 扫描完成由全局回调处理
+        }
+    }
+
+    // --------------------- 蓝牙秤特有方法 ---------------------
+    /**
+     * 发送获取重量指令(蓝牙秤特有)
+     */
+    public boolean sendGetWeightCommand() {
+        // 根据实际蓝牙秤指令调整
+        return sendStringData("GET_WEIGHT");
+    }
+}

+ 100 - 0
UI/CF.APP/chicken_farm/lib/core/services/pda/bluetooth_channel.dart

@@ -0,0 +1,100 @@
+import 'package:flutter/services.dart';
+
+/// 蓝牙 Channel 通信封装
+/// 仅处理与原生的 MethodChannel 交互,不包含业务逻辑
+class BluetoothChannel {
+  // 通用蓝牙通道名称
+  static const String _channelName = 'com.vber.chicken_farm/bluetooth_common';
+
+  // MethodChannel 实例
+  final MethodChannel _channel = const MethodChannel(_channelName);
+
+  /// 注册原生回调处理器
+  void setMethodCallHandler(Future<void> Function(MethodCall call) handler) {
+    _channel.setMethodCallHandler(handler);
+  }
+
+  /// 移除回调处理器
+  void clearMethodCallHandler() {
+    _channel.setMethodCallHandler(null);
+  }
+
+  // --------------------- 扫描相关方法 ---------------------
+  /// 开始扫描蓝牙设备
+  /// [duration] 扫描时长(毫秒),默认10秒
+  Future<bool> startScan({int duration = 10000}) async {
+    try {
+      return await _channel.invokeMethod('scan.start', {'duration': duration});
+    } on PlatformException catch (_) {
+      return false;
+    }
+  }
+
+  /// 停止扫描蓝牙设备
+  Future<bool> stopScan() async {
+    try {
+      return await _channel.invokeMethod('scan.stop');
+    } on PlatformException catch (_) {
+      return false;
+    }
+  }
+
+  // --------------------- 蓝牙秤相关方法 ---------------------
+  /// 连接蓝牙秤
+  /// [address] 设备MAC地址
+  Future<bool> connectScale(String address) async {
+    try {
+      return await _channel.invokeMethod('scale.connect', {'address': address});
+    } on PlatformException catch (_) {
+      return false;
+    }
+  }
+
+  /// 断开蓝牙秤连接
+  Future<bool> disconnectScale() async {
+    try {
+      return await _channel.invokeMethod('scale.disconnect');
+    } on PlatformException catch (_) {
+      return false;
+    }
+  }
+
+  /// 发送获取重量指令
+  Future<bool> sendGetWeightCommand() async {
+    try {
+      return await _channel.invokeMethod('scale.sendGetWeightCommand');
+    } on PlatformException catch (_) {
+      return false;
+    }
+  }
+
+  /// 发送自定义指令
+  /// [command] 指令字符串
+  Future<bool> sendScaleCommand(String command) async {
+    try {
+      return await _channel.invokeMethod('scale.sendCommand', {
+        'command': command,
+      });
+    } on PlatformException catch (_) {
+      return false;
+    }
+  }
+
+  /// 获取蓝牙秤连接状态
+  Future<int> getScaleConnectionState() async {
+    try {
+      return await _channel.invokeMethod('scale.getConnectionState');
+    } on PlatformException catch (_) {
+      return 0; // 返回断开状态
+    }
+  }
+
+  /// 检查蓝牙秤是否已连接
+  Future<bool> isScaleConnected() async {
+    try {
+      return await _channel.invokeMethod('scale.isConnected');
+    } on PlatformException catch (_) {
+      return false;
+    }
+  }
+}

+ 247 - 0
UI/CF.APP/chicken_farm/lib/core/services/pda/bluetooth_manager.dart

@@ -0,0 +1,247 @@
+import 'dart:convert';
+import 'package:chicken_farm/core/services/pda/bluetooth_channel.dart';
+import 'package:flutter/services.dart';
+
+/// 蓝牙设备管理器
+/// 处理业务逻辑、状态管理、数据解析,依赖 BluetoothChannel 进行通信
+class BluetoothManager {
+  // 通信层实例
+  final BluetoothChannel _bluetoothChannel = BluetoothChannel();
+
+  // 状态管理
+  int _scanState = 0; // 0:未扫描 1:扫描中 2:已停止
+  List<Map<String, dynamic>> _discoveredDevices = [];
+
+  BluetoothManager() {
+    // 初始化回调监听
+    _initMethodCallHandler();
+  }
+
+  // --------------------- 初始化与销毁 ---------------------
+  /// 初始化原生回调处理器
+  void _initMethodCallHandler() {
+    _bluetoothChannel.setMethodCallHandler(_handleMethodCall);
+  }
+
+  /// 释放资源
+  void dispose() {
+    _bluetoothChannel.clearMethodCallHandler();
+    _discoveredDevices.clear();
+    _scanState = 0;
+  }
+
+  // --------------------- 回调处理 ---------------------
+  /// 处理原生回调
+  Future<void> _handleMethodCall(MethodCall call) async {
+    switch (call.method) {
+      // 扫描状态变化
+      case 'scan.onScanStateChanged':
+        _scanState = call.arguments;
+        _onScanStateChanged?.call(_scanState);
+        break;
+
+      // 发现新设备
+      case 'scan.onDeviceDiscovered':
+        final device = _parseDeviceJson(call.arguments);
+        if (device != null && !_isDeviceExist(device)) {
+          _discoveredDevices.add(device);
+          _onDeviceDiscovered?.call(device);
+        }
+        break;
+
+      // 扫描完成
+      case 'scan.onScanCompleted':
+        _discoveredDevices = _parseDeviceListJson(call.arguments);
+        _onScanCompleted?.call(_discoveredDevices);
+        break;
+
+      // 蓝牙秤连接状态变化
+      case 'scale.onConnectionStateChanged':
+        final state = call.arguments;
+        _onScaleConnectionStateChanged?.call(state);
+        break;
+
+      // 蓝牙秤业务数据(重量)
+      case 'scale.onBusinessDataReceived':
+        final weightData = _parseWeightData(call.arguments);
+        _onScaleWeightReceived?.call(weightData);
+        break;
+
+      // 错误回调
+      case 'scale.onError':
+      case 'scan.onError':
+        final error = call.arguments as List;
+        _onError?.call(error[0], error[1]);
+        break;
+    }
+  }
+
+  // --------------------- 数据解析 ---------------------
+  /// 解析单个设备JSON字符串
+  Map<String, dynamic>? _parseDeviceJson(String jsonStr) {
+    try {
+      return jsonDecode(jsonStr);
+    } catch (_) {
+      return null;
+    }
+  }
+
+  /// 解析设备列表JSON字符串
+  List<Map<String, dynamic>> _parseDeviceListJson(String jsonStr) {
+    try {
+      final list = jsonDecode(jsonStr) as List;
+      return list.cast<Map<String, dynamic>>();
+    } catch (_) {
+      return [];
+    }
+  }
+
+  /// 解析重量数据
+  Map<String, dynamic> _parseWeightData(String jsonStr) {
+    try {
+      return jsonDecode(jsonStr);
+    } catch (_) {
+      return {'weight': 0.0, 'unit': 'kg'};
+    }
+  }
+
+  /// 检查设备是否已存在(按MAC地址去重)
+  bool _isDeviceExist(Map<String, dynamic> device) {
+    return _discoveredDevices.any((d) => d['address'] == device['address']);
+  }
+
+  // --------------------- 业务方法 ---------------------
+  /// 开始扫描蓝牙设备
+  /// [duration] 扫描时长(毫秒)
+  Future<void> startScan({int duration = 10000}) async {
+    _discoveredDevices.clear();
+    final success = await _bluetoothChannel.startScan(duration: duration);
+    if (!success) {
+      _onError?.call('SCAN_FAILED', '扫描启动失败');
+    }
+  }
+
+  /// 停止扫描蓝牙设备
+  Future<void> stopScan() async {
+    final success = await _bluetoothChannel.stopScan();
+    if (!success) {
+      _onError?.call('SCAN_FAILED', '扫描停止失败');
+    }
+  }
+
+  /// 连接蓝牙秤
+  /// [address] 设备MAC地址
+  Future<void> connectScale(String address) async {
+    final success = await _bluetoothChannel.connectScale(address);
+    if (!success) {
+      _onError?.call('CONNECT_FAILED', '蓝牙秤连接失败');
+    }
+  }
+
+  /// 断开蓝牙秤连接
+  Future<void> disconnectScale() async {
+    final success = await _bluetoothChannel.disconnectScale();
+    if (!success) {
+      _onError?.call('DISCONNECT_FAILED', '蓝牙秤断开失败');
+    }
+  }
+
+  /// 发送获取重量指令
+  Future<void> sendGetWeightCommand() async {
+    final success = await _bluetoothChannel.sendGetWeightCommand();
+    if (!success) {
+      _onError?.call('SEND_COMMAND_FAILED', '获取重量指令发送失败');
+    }
+  }
+
+  /// 发送自定义指令到蓝牙秤
+  Future<void> sendScaleCommand(String command) async {
+    final success = await _bluetoothChannel.sendScaleCommand(command);
+    if (!success) {
+      _onError?.call('SEND_COMMAND_FAILED', '自定义指令发送失败');
+    }
+  }
+
+  /// 获取蓝牙秤连接状态
+  Future<int> getScaleConnectionState() async {
+    return await _bluetoothChannel.getScaleConnectionState();
+  }
+
+  /// 检查蓝牙秤是否已连接
+  Future<bool> isScaleConnected() async {
+    return await _bluetoothChannel.isScaleConnected();
+  }
+
+  // --------------------- 状态获取 ---------------------
+  /// 获取当前扫描状态
+  int get scanState => _scanState;
+
+  /// 获取已发现设备列表
+  List<Map<String, dynamic>> get discoveredDevices =>
+      List.unmodifiable(_discoveredDevices);
+
+  /// 获取扫描状态文本描述
+  String get scanStateText => _getScanStateText(_scanState);
+
+  /// 获取连接状态文本描述
+  String getScaleConnectionStateText(int state) => _getConnStateText(state);
+
+  // --------------------- 工具方法 ---------------------
+  /// 转换扫描状态为文本
+  String _getScanStateText(int state) {
+    switch (state) {
+      case 0:
+        return '未扫描';
+      case 1:
+        return '扫描中';
+      case 2:
+        return '已停止';
+      default:
+        return '未知状态';
+    }
+  }
+
+  /// 转换连接状态为文本
+  String _getConnStateText(int state) {
+    switch (state) {
+      case 0:
+        return '已断开';
+      case 1:
+        return '连接中';
+      case 2:
+        return '已连接';
+      default:
+        return '未知状态';
+    }
+  }
+
+  // --------------------- 事件回调 ---------------------
+  /// 扫描状态变化回调
+  Function(int)? _onScanStateChanged;
+  set onScanStateChanged(Function(int)? callback) =>
+      _onScanStateChanged = callback;
+
+  /// 发现新设备回调
+  Function(Map<String, dynamic>)? _onDeviceDiscovered;
+  set onDeviceDiscovered(Function(Map<String, dynamic>)? callback) =>
+      _onDeviceDiscovered = callback;
+
+  /// 扫描完成回调
+  Function(List<Map<String, dynamic>>)? _onScanCompleted;
+  set onScanCompleted(Function(List<Map<String, dynamic>>)? callback) =>
+      _onScanCompleted = callback;
+
+  /// 蓝牙秤连接状态变化回调
+  Function(int)? _onScaleConnectionStateChanged;
+  set onScaleConnectionStateChanged(Function(int)? callback) =>
+      _onScaleConnectionStateChanged = callback;
+
+  /// 蓝牙秤重量数据回调
+  Function(Map<String, dynamic>)? _onScaleWeightReceived;
+  set onScaleWeightReceived(Function(Map<String, dynamic>)? callback) =>
+      _onScaleWeightReceived = callback;
+
+  /// 错误回调
+  Function(String, String)? _onError;
+  set onError(Function(String, String)? callback) => _onError = callback;
+}