wjc
2026-03-24 c4ae4589c6c001329ebb731589b209e8ddcbf7ca
app/src/main/java/com/hdl/photovoltaic/utils/BleWifiConfiguratorUtils.java
@@ -46,28 +46,21 @@
public class BleWifiConfiguratorUtils {
    private static final String TAG = "BleWifiConfigurator";
    // 默认的 UUID(设备端需要定义以下服务和特征)
    //这是主服务,包含所有配网相关的特征。
    public static final UUID DEFAULT_SERVICE_UUID = UUID.fromString("0000fff0-0000-1000-8000-00805f9b34fb");
    public static final UUID DEFAULT_SERVICE_UUID = UUID.fromString("000000ff-0000-1000-8000-00805f9b34fb");
    //特征值 1: 0000fff1-0000-1000-8000-00805f9b34fb (SSID)
    //用途:写入 Wi-Fi 的 SSID 名称
    //属性:Write (可写)
    //数据类型:UTF-8 字符串
    //示例:"MyWiFi_5G"
    public static final UUID DEFAULT_SSID_CHAR_UUID = UUID.fromString("0000fff1-0000-1000-8000-00805f9b34fb");
    //特征值 2: 0000fff2-0000-1000-8000-00805f9b34fb (密码)
    // 用途:写入 Wi-Fi 密码
    //属性:Write (可写)
    //数据类型:UTF-8 字符串
    //示例:"password123"
    public static final UUID DEFAULT_PWD_CHAR_UUID = UUID.fromString("0000fff2-0000-1000-8000-00805f9b34fb");
    public static final UUID DEFAULT_CHAR_UUID = UUID.fromString("0000ff01-0000-1000-8000-00805f9b34fb");
    //特征值 3: 0000fff3-0000-1000-8000-00805f9b34fb (通知,可选)
    //用途:接收设备端的响应消息
    //属性:Notify (通知)
    //数据类型:UTF-8 字符串
    //示例响应:"SUCCESS", "FAIL: Invalid SSID"
    public static final UUID DEFAULT_NOTIFY_CHAR_UUID = UUID.fromString("0000fff3-0000-1000-8000-00805f9b34fb"); // 可选,用于接收设备响应
    public static final UUID DEFAULT_NOTIFY_CHAR_UUID = UUID.fromString("0000ff01-0000-1000-8000-00805f9b34fb"); // 可选,用于接收设备响应
    // 上下文
    private Context context;
@@ -79,14 +72,12 @@
    // GATT 相关
    private BluetoothGatt bluetoothGatt;
    private BluetoothGattService targetService;
    private BluetoothGattCharacteristic ssidCharacteristic;
    private BluetoothGattCharacteristic pwdCharacteristic;
    private BluetoothGattCharacteristic characteristic;
    private BluetoothGattCharacteristic notifyCharacteristic; // 可选
    // 自定义 UUID(允许调用者修改)
    private UUID serviceUuid = DEFAULT_SERVICE_UUID;
    private UUID ssidCharUuid = DEFAULT_SSID_CHAR_UUID;
    private UUID pwdCharUuid = DEFAULT_PWD_CHAR_UUID;
    private UUID charUuid = DEFAULT_CHAR_UUID;
    private UUID notifyCharUuid = DEFAULT_NOTIFY_CHAR_UUID;
    // 回调接口
@@ -97,9 +88,7 @@
    // 内部状态
    private boolean isScanning = false;
    private boolean isConnected = false;
    private int writeState = 0; // 0: idle, 1: writing ssid, 2: writing pwd
    private String ssidToWrite;
    private String pwdToWrite;
    private String dataToWrite; // 待写入的数据
    // 用于将 BLE 回调抛到主线程
    private final Handler callbackHandler = new Handler(Looper.getMainLooper());
@@ -126,17 +115,10 @@
    }
    /**
     * 设置自定义 SSID 特征 UUID(可选)
     * 设置自定义特征 UUID(可选)
     */
    public void setSsidCharUuid(UUID ssidCharUuid) {
        this.ssidCharUuid = ssidCharUuid;
    }
    /**
     * 设置自定义密码特征 UUID(可选)
     */
    public void setPwdCharUuid(UUID pwdCharUuid) {
        this.pwdCharUuid = pwdCharUuid;
    public void setCharUuid(UUID charUuid) {
        this.charUuid = charUuid;
    }
    /**
@@ -144,6 +126,13 @@
     */
    public void setNotifyCharUuid(UUID notifyCharUuid) {
        this.notifyCharUuid = notifyCharUuid;
    }
    /**
     * 检查蓝牙连接状态
     */
    public boolean getBluetoothStatus() {
        return this.isConnected;
    }
    // ==================== 权限检查 ====================
@@ -156,6 +145,7 @@
    public List<String> getMissingPermissions() {
        List<String> missing = new ArrayList<>();
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
            //在应用里--权限名称--附近的设备
            if (context.checkSelfPermission(android.Manifest.permission.BLUETOOTH_SCAN) != android.content.pm.PackageManager.PERMISSION_GRANTED) {
                missing.add(android.Manifest.permission.BLUETOOTH_SCAN);
                Log.d(TAG, "No Permissions: android.Manifest.permission.BLUETOOTH_SCAN");
@@ -225,7 +215,7 @@
            isScanning = true;
            Log.d(TAG, "BLE scan started");
        } catch (Exception e) {
            Log.d(TAG, "BLE scan fail");
        }
    }
@@ -249,6 +239,29 @@
        @Override
        public void onScanResult(int callbackType, ScanResult result) {
            BluetoothDevice device = result.getDevice();
//            //  关键:获取设备的蓝牙类型
//            int bluetoothType = device.getType();
//            switch (bluetoothType) {
//                case BluetoothDevice.DEVICE_TYPE_CLASSIC:
//                    Log.d(TAG, "📞 经典蓝牙设备:" + device.getName());
//                    // 例如:蓝牙耳机、车载音响
//                    break;
//
//                case BluetoothDevice.DEVICE_TYPE_LE:
//                    Log.d(TAG, "💡 低功耗蓝牙设备:" + device.getName());
//                    // 例如:手环、智能灯、你的 HDL 设备
//                    break;
//
//                case BluetoothDevice.DEVICE_TYPE_DUAL:
//                    Log.d(TAG, "🔄 双模设备(支持两种):" + device.getName());
//                    // 例如:高端蓝牙耳机
//                    break;
//
//                case BluetoothDevice.DEVICE_TYPE_UNKNOWN:
//                    Log.d(TAG, "❓ 未知类型");
//                    break;
//            }
            Log.d("===", "onDeviceFound: " + Objects.requireNonNull(result.getScanRecord()).getDeviceName());
//            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
//                if (ActivityCompat.checkSelfPermission(context, Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) {
@@ -266,7 +279,7 @@
            int rssi = result.getRssi();
            byte[] scanRecord = result.getScanRecord() != null ? result.getScanRecord().getBytes() : null;
            if (scanListener != null) {
                callbackHandler.post(() -> scanListener.onDeviceFound(device, rssi, scanRecord));
                callbackHandler.post(() -> scanListener.onDeviceFound(device, rssi, scanRecord, result));
            }
        }
@@ -293,7 +306,7 @@
    // ==================== 连接相关 ====================
    /**
     * 连接指定的 BLE 设备(系统默认连接超时30秒        )
     * 连接指定的 BLE 设备(系统默认连接超时30秒)
     *
     * @param deviceAddress 目标设备BluetoothDevice
     * @param listener      连接状态回调
@@ -309,9 +322,12 @@
            callbackHandler.post(() -> this.connectListener.onConnectionFailed("No permissions")); // 没有权限
            return;
        }
        if (bluetoothGatt != null) {
            bluetoothGatt.disconnect();  // 先断开连接
            bluetoothGatt.close();
            bluetoothGatt = null;
            Log.d(TAG, "Connecting to 先断开旧蓝牙连接");
        }
        BluetoothDevice device = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(deviceAddress);
        // 自动连接 = false,避免系统缓存连接
@@ -340,8 +356,7 @@
        }
        isConnected = false;
        targetService = null;
        ssidCharacteristic = null;
        pwdCharacteristic = null;
        characteristic = null;
        notifyCharacteristic = null;
    }
@@ -355,9 +370,15 @@
                gatt.discoverServices();
            } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
                isConnected = false;
//                if (bluetoothGatt != null) {
//                    bluetoothGatt.close();
//                    bluetoothGatt = null;
//                }
                if (connectListener != null) {
                    callbackHandler.post(() -> connectListener.onDisconnected());
                }
                Log.d(TAG, "Connected to GATT server, onDisconnected");
            }//
        }
@@ -371,15 +392,17 @@
                    notifyConnectionFailed("Service not found");
                    return;
                }
                ssidCharacteristic = targetService.getCharacteristic(ssidCharUuid);
                pwdCharacteristic = targetService.getCharacteristic(pwdCharUuid);
                characteristic = targetService.getCharacteristic(charUuid);
                notifyCharacteristic = targetService.getCharacteristic(notifyCharUuid);
                if (ssidCharacteristic == null || pwdCharacteristic == null) {
                boolean mtuRequestResult = gatt.requestMtu(512); // 默认设置请求最大 MTU,有设备可能不支持
                Log.d(TAG, "requestMtu(512) 结果:" + mtuRequestResult);
                if (characteristic == null) {
                    Log.e(TAG, "Required characteristics not found");
                    notifyConnectionFailed("Characteristics not found");
                    return;
                }
                Log.e(TAG, "Required characteristics find");
                // 如果支持通知,可以开启通知(可选)
                if (notifyCharacteristic != null) {
                    enableNotification(notifyCharacteristic);
@@ -401,25 +424,16 @@
            boolean success = status == BluetoothGatt.GATT_SUCCESS;
            if (!success) {
                Log.e(TAG, "Write failed, status: " + status);
                writeState = 0;
                if (writeListener != null) {
                    callbackHandler.post(() -> writeListener.onWriteFailed(status));
                }
                return;
            }
            if (writeState == 1 && characteristic.getUuid().equals(ssidCharUuid)) {
                // SSID 写入成功,开始写密码
                writeState = 2;
            Log.d(TAG, "onCharacteristicWrite: 写入成功回复");
            if (characteristic.getUuid().equals(charUuid)) {
                //写入成功
                if (writeListener != null) {
                    callbackHandler.post(() -> writeListener.onSsidWriteSuccess());
                }
                writeCharacteristic(pwdCharacteristic, pwdToWrite);
            } else if (writeState == 2 && characteristic.getUuid().equals(pwdCharUuid)) {
                // 密码写入成功
                writeState = 0;
                if (writeListener != null) {
                    callbackHandler.post(() -> writeListener.onPasswordWriteSuccess());
                    callbackHandler.post(() -> writeListener.onWriteSuccess());
                    callbackHandler.post(() -> writeListener.onWriteComplete(true));
                }
            }
@@ -427,6 +441,8 @@
        @Override
        public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
            Log.d(TAG, "onCharacteristicChanged: " + characteristic.getUuid());
            //收到蓝牙回复的数
            if (characteristic.getUuid().equals(notifyCharUuid) && writeListener != null) {
                byte[] value = characteristic.getValue();
                String response = new String(value, StandardCharsets.UTF_8);
@@ -436,16 +452,47 @@
        @Override
        public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
            Log.d(TAG, "onDescriptorWrite: status=" + status +
                    ", descriptor=" + descriptor.getUuid());
            // 通知描述符写入完成,可以忽略
//            if (status == BluetoothGatt.GATT_SUCCESS) {
//                Log.d(TAG, "通知开启成功,可以接收设备响应了");
//            } else {
//                Log.e(TAG, "通知开启失败:" + status);
//                if (writeListener != null) {
//                    callbackHandler.post(() -> writeListener.onWriteFailed(status));
//                }
//            }
            if (status == BluetoothGatt.GATT_SUCCESS) {
                Log.d(TAG, "通知开启成功,可以接收设备响应了");
            } else {
                Log.e(TAG, "通知开启失败:" + status);
                if (writeListener != null) {
                    callbackHandler.post(() -> writeListener.onWriteFailed(status));
                }
            }
        }
        @Override
        public void onMtuChanged(BluetoothGatt gatt, int mtu, int status) {
            //todo 后面兼用mtc分包的,目前默认设置512字节
            if (status == BluetoothGatt.GATT_SUCCESS) {
//                currentMtu = mtu;
                Log.d(TAG, "✅ MTU 协商成功:当前 MTU = " + mtu + " 字节");
                Log.d(TAG, "   有效数据长度 = " + (mtu - 5) + " 字节");
//                // MTU 设置成功后,标记连接成功
//                isConnected = true;
//                if (connectListener != null) {
//                    callbackHandler.post(() -> {
//                        Log.d(TAG, "通知连接成功回调");
//                        connectListener.onConnected();
//                    });
//                }
            } else {
//                Log.w(TAG, "⚠️ MTU 协商失败,status: " + status + ",使用默认 MTU=23");
////                currentMtu = 23;
//                // 即使 MTU 失败,也认为连接成功(使用默认 MTU)
//                isConnected = true;
//                if (connectListener != null) {
//                    callbackHandler.post(() -> connectListener.onConnected());
//                }
            }
        }
    };
    @RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT)
@@ -462,12 +509,26 @@
            BluetoothGattDescriptor descriptor = characteristic.getDescriptor(
                    UUID.fromString("00002902-0000-1000-8000-00805f9b34fb"));
            if (descriptor != null) {
//                // 第 3 步:设置描述符的值
//                // 先检查特征属性,决定使用 NOTIFY 还是 INDICATE
//                int charProp = characteristic.getProperties();
//                if ((charProp & BluetoothGattCharacteristic.PROPERTY_NOTIFY) > 0) {
//                    descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
//                    Log.d(TAG, "使用 NOTIFICATION 模式");
//                } else if ((charProp & BluetoothGattCharacteristic.PROPERTY_INDICATE) > 0) {
//                    descriptor.setValue(BluetoothGattDescriptor.ENABLE_INDICATION_VALUE);
//                    Log.d(TAG, "使用 INDICATION 模式");
//                } else {
//                    Log.e(TAG, "该特征不支持通知/指示");
//                    return;
//                }
                // 第 3 步:设置描述符的值为 ENABLE_NOTIFICATION_VALUE,
                // ↑ 这个值是 byte[]{0x01, 0x00},告诉设备端"我要订阅通知"
                descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
                // 第 4 步:写入描述符到设备
                //↑ 只有写入成功后,告诉设备端,设备才会开始发送通知,
                bluetoothGatt.writeDescriptor(descriptor);
                Log.d(TAG, "writeDescriptor success");
            }
        }
    }
@@ -482,31 +543,28 @@
    // ==================== 写入凭证 ====================
    /**
     * 写入 Wi-Fi SSID 和密码(必须在连接成功后调用)
     * 写入数据(必须在连接成功后调用)
     *
     * @param ssid     Wi-Fi SSID
     * @param password Wi-Fi 密码
     * @param data     数据
     * @param listener 写入结果回调
     */
    @RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT)
    public void writeCredentials(String ssid, String password, WriteListener listener) {
    public void writeCredentials(String data, WriteListener listener) {
        Log.d(TAG, "writeCredentials :准备写入");
        this.writeListener = listener;
        if (!isConnected || ssidCharacteristic == null || pwdCharacteristic == null) {
        if (!isConnected || characteristic == null) {
            if (listener != null) {
                callbackHandler.post(() -> listener.onWriteFailed(-1)); // 自定义错误码
            }
            return;
        }
        this.ssidToWrite = ssid;
        this.pwdToWrite = password;
        // 开始写 SSID
        writeState = 1;
        writeCharacteristic(ssidCharacteristic, ssid);
        // 开始写
        writeCharacteristic(characteristic, data);
    }
    @RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT)
    private void writeCharacteristic(BluetoothGattCharacteristic characteristic, String value) {
        Log.d(TAG, "writeCharacteristic :开始写入");
        if (!this.getMissingPermissions().isEmpty()) {
            callbackHandler.post(() -> this.writeListener.onWriteFailed(-2)); // 没有权限
            return;
@@ -514,6 +572,7 @@
        characteristic.setValue(value.getBytes(StandardCharsets.UTF_8));
        characteristic.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT);
        bluetoothGatt.writeCharacteristic(characteristic);
        Log.d(TAG, "writeCharacteristic :开始完成");
    }
    // ==================== 工具方法 ====================
@@ -521,7 +580,7 @@
    /**
     * 检查蓝牙是否开启
     */
    private boolean checkBluetoothEnabled() {
    public boolean checkBluetoothEnabled() {
        return bluetoothAdapter != null && bluetoothAdapter.isEnabled();
    }
@@ -547,7 +606,7 @@
        /**
         * 发现设备(可能多次回调)
         */
        void onDeviceFound(BluetoothDevice device, int rssi, byte[] scanRecord);
        void onDeviceFound(BluetoothDevice device, int rssi, byte[] scanRecord, ScanResult scanResult);
        /**
         * 扫描失败
@@ -574,14 +633,9 @@
    public interface WriteListener {
        /**
         * SSID 写入成功
         * 写入成功
         */
        void onSsidWriteSuccess();
        /**
         * 密码写入成功
         */
        void onPasswordWriteSuccess();
        void onWriteSuccess();
        /**
         * 全部写入完成(成功为 true)