From dd434bc1464e0932a1a5b6b76ffe6dc33e203cc5 Mon Sep 17 00:00:00 2001 From: fdp <1286779656@qq.com> Date: Mon, 12 May 2025 00:51:45 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E4=B8=8D=E6=9B=B4=E6=96=B0?= =?UTF-8?q?=E7=94=B5=E9=87=8F=E8=AE=BE=E5=A4=87=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/data/services/ble_manager.dart | 142 ++++++++++--- .../home/controllers/home_controller.dart | 156 ++++++++------ lib/modules/home/views/home_view.dart | 182 ++++++++-------- .../controllers/ota_upgrade_controller.dart | 170 +++++++++++---- .../ota_upgrade_model.dart} | 0 .../ota_upgrade/views/ota_upgrade_view.dart | 200 ++++++++++-------- .../yunqiinnovation/ble_service/BleService.kt | 60 +++--- .../ble_service/ios/Classes/BleService.swift | 10 + .../ios/Classes/SwiftBleServicePlugin.swift | 8 +- .../ble_service/lib/ble_service.dart | 11 + 10 files changed, 602 insertions(+), 337 deletions(-) rename lib/modules/ota_upgrade/{ota.dart => model/ota_upgrade_model.dart} (100%) diff --git a/lib/data/services/ble_manager.dart b/lib/data/services/ble_manager.dart index cc72b46c6..0f826a7c4 100644 --- a/lib/data/services/ble_manager.dart +++ b/lib/data/services/ble_manager.dart @@ -9,13 +9,15 @@ import 'package:deep_voice/data/models/appconfig_model.dart'; import 'dart:convert'; import 'package:flutter/services.dart' show rootBundle; import 'package:agent_service/agent_service.dart'; +import 'package:classic_bluetooth/classic_bluetooth.dart'; /// 命令类型常量(与原生层保持一致) class BleCommands { static const int GET_VERSION = 0x01; - static const int GET_BATTERY_INFO = 0x02; - static const int CONTROL_CODEC = 0x03; - static const int PLAY_A2DP = 0x04; + static const int GET_PRODUCT_ID = 0x02; + static const int GET_PRODUCT_COLOR = 0x03; + static const int GET_BATTERY_INFO = 0x04; + static const int CONTROL_CODEC = 0x05; } /// 蓝牙设备信息缓存模型 @@ -37,6 +39,8 @@ class DeviceInfo { final bool caseCharging; final String firmwareVersion; + final String firmwareProductId; + final String firmwareProductColor; final DateTime lastUpdated; DeviceInfo({ @@ -50,6 +54,8 @@ class DeviceInfo { this.rightEarCharging = false, this.caseCharging = false, this.firmwareVersion = '', + this.firmwareProductId = '', + this.firmwareProductColor = '', DateTime? lastUpdated, }) : lastUpdated = lastUpdated ?? DateTime.now(); @@ -65,6 +71,8 @@ class DeviceInfo { bool? rightEarCharging, bool? caseCharging, String? firmwareVersion, + String? firmwareProductId, + String? firmwareProductColor, }) { return DeviceInfo( address: address ?? this.address, @@ -77,6 +85,8 @@ class DeviceInfo { rightEarCharging: rightEarCharging ?? this.rightEarCharging, caseCharging: caseCharging ?? this.caseCharging, firmwareVersion: firmwareVersion ?? this.firmwareVersion, + firmwareProductId: firmwareProductId ?? this.firmwareProductId, + firmwareProductColor: firmwareProductColor ?? this.firmwareProductColor, lastUpdated: DateTime.now(), ); } @@ -96,6 +106,7 @@ class BleManager extends GetxService { // BLE服务实例 final BleService _bleService = BleService(); +// 经典蓝牙实例 // BLE连接状态 final _connectionState = BleConnectionState.disconnected.obs; @@ -106,8 +117,7 @@ class BleManager extends GetxService { bool get isConnected => _isConnected.value; // 设备信息缓存 - final Rx _deviceInfo = Rx(null); - DeviceInfo? get deviceInfo => _deviceInfo.value; + final deviceInfo = Rx(null); // 使用 Rx 包装 // 订阅 StreamSubscription? _statusSubscription; @@ -145,8 +155,8 @@ class BleManager extends GetxService { if (event is Map) { // 处理连接状态更新 - if (event.containsKey('connectionState')) { - final state = event['connectionState'] as int; + if (event['type'] == 'connectionStateChanged') { + final state = event['state'] as int; _connectionState.value = state; // 连接状态转换 @@ -154,8 +164,13 @@ class BleManager extends GetxService { Logger.info('BLE设备已连接'); _isConnected.value = true; - // 在连接成功后获取设备信息 - _fetchDeviceInfo(); + // 在连接成功后延迟 300 毫秒获取设备信息(可根据需要调整时间) + Future.delayed(const Duration(milliseconds: 300), () { + // 可选:检查是否仍处于连接状态 + if (_isConnected.value) { + fetchDeviceInfo(); + } + }); } else if (state == BleConnectionState.disconnected || state == BleConnectionState.error) { Logger.info('BLE设备已断开或发生错误'); @@ -218,12 +233,18 @@ class BleManager extends GetxService { void _processDeviceInfoByCommandId( int commandId, Map data) { switch (commandId) { - case BleCommands.GET_BATTERY_INFO: - _updateBatteryInfoFromData(data); - break; case BleCommands.GET_VERSION: _updateVersionInfoFromData(data); break; + case BleCommands.GET_PRODUCT_ID: + _updateProductIdFromData(data); + break; + case BleCommands.GET_PRODUCT_COLOR: + break; + case BleCommands.GET_BATTERY_INFO: + _updateBatteryInfoFromData(data); + break; + default: Logger.info('未处理的命令ID: $commandId'); } @@ -239,6 +260,11 @@ class BleManager extends GetxService { case 'versionInfo': _updateVersionInfoFromData(data); break; + case 'productId': + _updateProductIdFromData(data); + break; + case 'productColor': + break; default: Logger.info('未处理的命令名称: $commandName'); } @@ -307,6 +333,29 @@ class BleManager extends GetxService { } } + /// 更新设备id + void _updateProductIdFromData(Map data) { + try { + // 确保数据中包含版本信息 + if (!data.containsKey('productId')) { + Logger.warning('版本信息数据不完整'); + return; + } + + // 提取版本信息 + final String productId = data['productId'] as String? ?? ''; + + // 更新设备信息 + _updateDeviceInfoIfNeeded( + firmwareProductId: productId, + ); + + Logger.info('设备设备id已更新: 设备id=$productId'); + } catch (e) { + Logger.error('更新设备id失败: $e'); + } + } + /// 更新设备信息(如果已存在设备) void _updateDeviceInfoIfNeeded({ int? batteryLevel, @@ -317,31 +366,53 @@ class BleManager extends GetxService { bool? rightEarCharging, bool? caseCharging, String? firmwareVersion, + String? firmwareProductId, + String? firmwareProductColor, }) { // 如果设备信息已存在,则更新 - if (_deviceInfo.value != null) { - _deviceInfo.value = _deviceInfo.value!.copyWith( - batteryLevel: batteryLevel, - leftEarBattery: leftEarBattery, - rightEarBattery: rightEarBattery, - caseBattery: caseBattery, - leftEarCharging: leftEarCharging, - rightEarCharging: rightEarCharging, - caseCharging: caseCharging, - firmwareVersion: firmwareVersion, + if (deviceInfo.value != null) { + deviceInfo.value = deviceInfo.value!.copyWith( + batteryLevel: batteryLevel ?? deviceInfo.value?.batteryLevel, + leftEarBattery: leftEarBattery ?? deviceInfo.value?.leftEarBattery, + rightEarBattery: rightEarBattery ?? deviceInfo.value?.rightEarBattery, + caseBattery: caseBattery ?? deviceInfo.value?.caseBattery, + leftEarCharging: leftEarCharging ?? deviceInfo.value!.leftEarCharging, + rightEarCharging: + rightEarCharging ?? deviceInfo.value!.rightEarCharging, + caseCharging: caseCharging ?? deviceInfo.value!.caseCharging, + firmwareVersion: firmwareVersion ?? deviceInfo.value!.firmwareVersion, + firmwareProductId: + firmwareProductId ?? deviceInfo.value!.firmwareProductId, + firmwareProductColor: + firmwareProductColor ?? deviceInfo.value!.firmwareProductColor, ); } + // 创建设备信息 // 如果设备信息不存在,但有地址和名称,则创建新的设备信息 - else if (_deviceInfo.value == null && + else if (deviceInfo.value == null && _isConnected.value && (firmwareVersion != null || batteryLevel != null)) { // 提示尝试创建设备信息但缺少必要信息 Logger.warning('尝试更新设备信息,但设备基本信息不存在'); + deviceInfo.value = DeviceInfo( + address: "", // 应确保从连接信息中获取真实值 + name: "", + batteryLevel: batteryLevel ?? 0, + leftEarBattery: leftEarBattery ?? 0, + rightEarBattery: rightEarBattery ?? 0, + caseBattery: caseBattery ?? 0, + leftEarCharging: leftEarCharging ?? false, + rightEarCharging: rightEarCharging ?? false, + caseCharging: caseCharging ?? false, + firmwareVersion: firmwareVersion ?? '', + firmwareProductId: firmwareProductId ?? '', + firmwareProductColor: firmwareProductColor ?? '', + ); } } /// 连接成功后获取设备信息 - Future _fetchDeviceInfo() async { + Future fetchDeviceInfo() async { Logger.info('开始获取BLE设备详细信息'); try { @@ -360,6 +431,14 @@ class BleManager extends GetxService { } else { Logger.warning('版本信息获取指令发送失败'); } + + // 获取产品id + final productIdResult = await _bleService.getProductId(); + if (productIdResult) { + Logger.info('产品id获取指令已发送'); + } else { + Logger.warning('产品id获取指令发送失败'); + } } catch (e) { Logger.error('获取BLE设备信息失败: $e'); } @@ -450,9 +529,9 @@ class BleManager extends GetxService { _connectionState.value = BleConnectionState.connected; // 如果设备信息存在,则获取详细信息 - if (_deviceInfo.value != null) { + if (deviceInfo.value != null) { // 获取详细设备信息 - _fetchDeviceInfo(); + fetchDeviceInfo(); } } } else { @@ -486,7 +565,6 @@ class BleManager extends GetxService { } } - /// 获取电池电量 Future getBatteryLevel() async { try { @@ -507,6 +585,16 @@ class BleManager extends GetxService { } } + /// 主动产品id + Future getProductId() async { + try { + return await _bleService.getProductId(); + } catch (e) { + Logger.error('获取设备版本失败: $e'); + return false; + } + } + /// 主动获取设备版本信息 Future fetchDeviceVersion() async { try { diff --git a/lib/modules/home/controllers/home_controller.dart b/lib/modules/home/controllers/home_controller.dart index f1a5955e4..f389cc7d5 100644 --- a/lib/modules/home/controllers/home_controller.dart +++ b/lib/modules/home/controllers/home_controller.dart @@ -19,7 +19,7 @@ enum ConnectionStatus { /// 主页控制器,管理设备连接状态和信息展示 class HomeController extends GetxController { static HomeController get to => Get.find(); - + // 依赖的控制器 final ExploreController exploreController = Get.find(); @@ -27,31 +27,47 @@ class HomeController extends GetxController { final _connectionStatus = ConnectionStatus.disconnected.obs; final _connectionErrorMsg = ''.obs; final _bluetoothState = 'unknown'.obs; - + // Getter方法 ConnectionStatus get connectionStatus => _connectionStatus.value; String get connectionErrorMsg => _connectionErrorMsg.value; String get bluetoothState => _bluetoothState.value; BluetoothDevice? get currentDevice => _bluetoothManager.currentDevice; - DeviceInfo? get deviceInfo => _bleManager.deviceInfo; + Rx get deviceInfo => _bleManager.deviceInfo; bool get isConnected => currentDevice != null; - + // 设备详细信息的getter,从deviceInfo获取数据 - int get leftEarBattery => deviceInfo?.leftEarBattery ?? 0; - int get rightEarBattery => deviceInfo?.rightEarBattery ?? 0; - int get caseBattery => deviceInfo?.caseBattery ?? 0; - bool get leftEarCharging => deviceInfo?.leftEarCharging ?? false; - bool get rightEarCharging => deviceInfo?.rightEarCharging ?? false; - bool get caseCharging => deviceInfo?.caseCharging ?? false; - String get firmwareVersion => deviceInfo?.firmwareVersion ?? ''; + final leftEarBattery = 0.obs; + final rightEarBattery = 0.obs; + final caseBattery = 0.obs; + final leftEarCharging = false.obs; + final rightEarCharging = false.obs; + final caseCharging = false.obs; + final firmwareVersion = ''.obs; + // int get leftEarBattery => deviceInfo?.leftEarBattery ?? 0; + // int get rightEarBattery => deviceInfo?.rightEarBattery ?? 0; + // int get caseBattery => deviceInfo?.caseBattery ?? 0; + // bool get leftEarCharging => deviceInfo?.leftEarCharging ?? false; + // bool get rightEarCharging => deviceInfo?.rightEarCharging ?? false; + // bool get caseCharging => deviceInfo?.caseCharging ?? false; + // String get firmwareVersion => deviceInfo?.firmwareVersion ?? ''; + /// 当有新的deviceInfo时更新所有Observable变量 + void updateDeviceInfo(DeviceInfo? newDeviceInfo) { + leftEarBattery.value = newDeviceInfo?.leftEarBattery ?? 0; + rightEarBattery.value = newDeviceInfo?.rightEarBattery ?? 0; + caseBattery.value = newDeviceInfo?.caseBattery ?? 0; + leftEarCharging.value = newDeviceInfo?.leftEarCharging ?? false; + rightEarCharging.value = newDeviceInfo?.rightEarCharging ?? false; + caseCharging.value = newDeviceInfo?.caseCharging ?? false; + firmwareVersion.value = newDeviceInfo?.firmwareVersion ?? ''; + } - // 监听和订阅 Worker? _deviceInfoWorker; Worker? _bluetoothStateWorker; Worker? _deviceWorker; - + // 蓝牙服务 final _bluetoothManager = Get.find(); final _bleManager = Get.find(); @@ -60,7 +76,7 @@ class HomeController extends GetxController { super.onInit(); _initWithCachedInfo(); } - + @override void onClose() { _deviceInfoWorker?.dispose(); @@ -73,11 +89,12 @@ class HomeController extends GetxController { void _initWithCachedInfo() { // 使用蓝牙服务中的当前状态 _bluetoothState.value = _bluetoothManager.bluetoothState; - + // 根据当前设备状态设置连接状态 if (currentDevice != null) { _connectionStatus.value = ConnectionStatus.connected; _connectionErrorMsg.value = ''; + updateDeviceInfo(_bleManager.deviceInfo.value); Logger.info('主页加载缓存设备信息: ${currentDevice!.name}'); } else { _connectionStatus.value = ConnectionStatus.disconnected; @@ -87,67 +104,73 @@ class HomeController extends GetxController { _connectionErrorMsg.value = '未连接到设备'; } } - + // 设置监听器监听蓝牙服务状态变化 _setupStateListeners(); } - + /// 设置状态监听器 void _setupStateListeners() { // 设备信息监听 - 设备信息更新时自动触发UI更新 - _deviceInfoWorker = ever(_bleManager.deviceInfo.obs, (DeviceInfo? info) { + _deviceInfoWorker = ever(_bleManager.deviceInfo, (DeviceInfo? info) { + Logger.info('设备信息监听'); if (info != null) { Logger.info('主页更新设备信息: ${info.toString()}'); + updateDeviceInfo(info); } else { Logger.info('主页清空设备信息'); } + update(); }); - + // 蓝牙状态监听 - _bluetoothStateWorker = ever(_bluetoothManager.bluetoothState.obs, (String state) { + _bluetoothStateWorker = + ever(_bluetoothManager.bluetoothState.obs, (String state) { _bluetoothState.value = state; - + // 如果蓝牙关闭,更新错误信息 if (state == 'off') { _connectionErrorMsg.value = '蓝牙未开启'; _connectionStatus.value = ConnectionStatus.disconnected; } - + update(); }); - + // 设备连接状态监听 - 直接监听设备变化 - _deviceWorker = ever(_bluetoothManager.currentDeviceRx, (BluetoothDevice? device) { + _deviceWorker = + ever(_bluetoothManager.currentDeviceRx, (BluetoothDevice? device) { if (device != null) { // 设备已连接 if (_connectionStatus.value != ConnectionStatus.connected) { _connectionStatus.value = ConnectionStatus.connected; _connectionErrorMsg.value = ''; - Logger.info('主页检测到设备已连接: ${device.name}'); } } else if (_connectionStatus.value == ConnectionStatus.connected) { // 设备已断开 _connectionStatus.value = ConnectionStatus.disconnected; _connectionErrorMsg.value = '设备已断开连接'; - + Logger.info('主页检测到设备已断开连接'); } - + update(); }); } - + /// 刷新设备连接状态 /// 注意:此方法不会主动刷新设备,只更新UI状态 Future refreshDeviceConnection() async { // 更新当前状态以反映UI变化 bool hasDevice = currentDevice != null; - + if (hasDevice) { _connectionStatus.value = ConnectionStatus.connected; _connectionErrorMsg.value = ''; + await _bleManager.fetchDeviceInfo(); + Logger.info('使用缓存设备信息: ${currentDevice!.name}'); } else { if (_bluetoothState.value == 'off') { @@ -157,13 +180,13 @@ class HomeController extends GetxController { } _connectionStatus.value = ConnectionStatus.disconnected; } - + // 刷新UI update(); } // 导航和功能方法 - + /// 重新扫描设备 void rescanDevices() { Get.toNamed(Routes.pairing); @@ -185,7 +208,7 @@ class HomeController extends GetxController { } // UI辅助方法 - + /// 获取连接状态对应的颜色 Color getConnectionStatusColor() { switch (_connectionStatus.value) { @@ -244,62 +267,71 @@ class HomeController extends GetxController { /// 获取设备ID String getDeviceId() { - return deviceInfo?.address ?? currentDevice?.address ?? 'unknown'.tr; + return deviceInfo.value?.address ?? currentDevice?.address ?? 'unknown'.tr; } - + /// 获取设备电量文本 String getBatteryText() { - return deviceInfo?.batteryLevel != null && deviceInfo!.batteryLevel > 0 - ? '${deviceInfo!.batteryLevel}%' - : 'unknown'.tr; + return deviceInfo.value?.batteryLevel != null && + deviceInfo.value!.batteryLevel > 0 + ? '${deviceInfo.value?.batteryLevel}%' + : 'unknown'.tr; } - + /// 获取耳机左右电量文本 String getEarbudsText() { - if (deviceInfo == null || (deviceInfo!.leftEarBattery <= 0 && deviceInfo!.rightEarBattery <= 0)) { + if (deviceInfo == null || + (deviceInfo.value!.leftEarBattery <= 0 && + deviceInfo.value!.rightEarBattery <= 0)) { return 'unknown'.tr; } - - String leftStatus = deviceInfo!.leftEarBattery > 0 ? '${deviceInfo!.leftEarBattery}%' : 'N/A'; - String rightStatus = deviceInfo!.rightEarBattery > 0 ? '${deviceInfo!.rightEarBattery}%' : 'N/A'; - - leftStatus = deviceInfo!.leftEarCharging ? '$leftStatus ⚡' : leftStatus; - rightStatus = deviceInfo!.rightEarCharging ? '$rightStatus ⚡' : rightStatus; - + + String leftStatus = deviceInfo.value!.leftEarBattery > 0 + ? '${deviceInfo.value!.leftEarBattery}%' + : 'N/A'; + String rightStatus = deviceInfo.value!.rightEarBattery > 0 + ? '${deviceInfo.value!.rightEarBattery}%' + : 'N/A'; + + leftStatus = + deviceInfo.value!.leftEarCharging ? '$leftStatus ⚡' : leftStatus; + rightStatus = + deviceInfo.value!.rightEarCharging ? '$rightStatus ⚡' : rightStatus; + return '左耳: $leftStatus / 右耳: $rightStatus'; } - + /// 获取充电仓电量文本 String getCaseText() { - if (deviceInfo == null || deviceInfo!.caseBattery <= 0) { + if (deviceInfo.value == null || deviceInfo.value!.caseBattery <= 0) { return 'unknown'.tr; } - - String caseStatus = '${deviceInfo!.caseBattery}%'; - if (deviceInfo!.caseCharging) { + + String caseStatus = '${deviceInfo.value!.caseBattery}%'; + if (deviceInfo.value!.caseCharging) { caseStatus = '$caseStatus ⚡'; } - + return '充电仓: $caseStatus'; } - + /// 获取充电状态文本 String getChargingText() { if (deviceInfo == null) { return 'unknown'.tr; } - - bool isCharging = deviceInfo!.leftEarCharging || - deviceInfo!.rightEarCharging || - deviceInfo!.caseCharging; - + + bool isCharging = deviceInfo.value!.leftEarCharging || + deviceInfo.value!.rightEarCharging || + deviceInfo.value!.caseCharging; + return isCharging ? 'charging'.tr : 'notCharging'.tr; } - + /// 获取设备版本文本 String getVersionText() { - return deviceInfo?.firmwareVersion.isNotEmpty == true ? - deviceInfo!.firmwareVersion : 'unknown'.tr; + return deviceInfo.value?.firmwareVersion.isNotEmpty == true + ? deviceInfo.value!.firmwareVersion + : 'unknown'.tr; } - } diff --git a/lib/modules/home/views/home_view.dart b/lib/modules/home/views/home_view.dart index abdb2f920..dae65616a 100644 --- a/lib/modules/home/views/home_view.dart +++ b/lib/modules/home/views/home_view.dart @@ -160,43 +160,43 @@ class HomeView extends GetView { child: ClipRRect( // 添加 ClipRRect 来实现圆角 borderRadius: BorderRadius.circular(16.r), // 使用与其他部件一致的圆角大小 - child: SizedBox( - width: double.infinity, - height: 200.h, - child: Image.asset( - isDarkMode - ? 'assets/images/robot_light.png' - : 'assets/images/robot_light.png', - fit: BoxFit.fitWidth, + child: SizedBox( + width: double.infinity, + height: 200.h, + child: Image.asset( + isDarkMode + ? 'assets/images/robot_light.png' + : 'assets/images/robot_light.png', + fit: BoxFit.fitWidth, + ), ), ), ), - ), Center( child: ClipRRect( // 添加 ClipRRect borderRadius: BorderRadius.circular(16.r), - child: Image.asset( - isDarkMode - ? 'assets/images/headphone_dark.png' - : 'assets/images/headphone_light.png', - height: 180.h, - fit: BoxFit.contain, + child: Image.asset( + isDarkMode + ? 'assets/images/headphone_dark.png' + : 'assets/images/headphone_light.png', + height: 180.h, + fit: BoxFit.contain, + ), ), ), - ), Center( child: ClipRRect( // 添加 ClipRRect borderRadius: BorderRadius.circular(16.r), - child: SizedBox( - width: double.infinity, - height: 200.h, - child: Image.asset( - isDarkMode - ? 'assets/images/glasses_light.png' - : 'assets/images/glasses_light.png', - fit: BoxFit.fitWidth, + child: SizedBox( + width: double.infinity, + height: 200.h, + child: Image.asset( + isDarkMode + ? 'assets/images/glasses_light.png' + : 'assets/images/glasses_light.png', + fit: BoxFit.fitWidth, ), ), ), @@ -283,50 +283,52 @@ class HomeView extends GetView { ], ), Obx(() => Row( - children: [ - Container( - width: 8.w, - height: 8.w, - decoration: BoxDecoration( - color: controller.getConnectionStatusColor(), - shape: BoxShape.circle, - boxShadow: [ - BoxShadow( - color: controller.getConnectionStatusColor().withOpacity(0.3), - blurRadius: 4, - spreadRadius: 1, + children: [ + Container( + width: 8.w, + height: 8.w, + decoration: BoxDecoration( + color: controller.getConnectionStatusColor(), + shape: BoxShape.circle, + boxShadow: [ + BoxShadow( + color: controller + .getConnectionStatusColor() + .withOpacity(0.3), + blurRadius: 4, + spreadRadius: 1, + ), + ], ), - ], - ), - ), - SizedBox(width: 4.w), - Text( - controller.getConnectionStatusText(), - style: TextStyle( - fontSize: 12.sp, - color: controller.getConnectionStatusColor(), - ), - ), - // 添加刷新按钮 - SizedBox(width: 8.w), - InkWell( - onTap: () => controller.refreshDeviceConnection(), - borderRadius: BorderRadius.circular(12.r), - child: Container( - padding: EdgeInsets.all(4.w), - decoration: BoxDecoration( - color: isDarkMode ? Colors.grey[800] : Colors.grey[200], - shape: BoxShape.circle, ), - child: Icon( - Icons.refresh, - size: 14.sp, - color: isDarkMode ? Colors.grey[400] : Colors.grey[600], + SizedBox(width: 4.w), + Text( + controller.getConnectionStatusText(), + style: TextStyle( + fontSize: 12.sp, + color: controller.getConnectionStatusColor(), + ), ), - ), - ), - ], - )), + // 添加刷新按钮 + SizedBox(width: 8.w), + InkWell( + onTap: () => controller.refreshDeviceConnection(), + borderRadius: BorderRadius.circular(12.r), + child: Container( + padding: EdgeInsets.all(4.w), + decoration: BoxDecoration( + color: isDarkMode ? Colors.grey[800] : Colors.grey[200], + shape: BoxShape.circle, + ), + child: Icon( + Icons.refresh, + size: 14.sp, + color: isDarkMode ? Colors.grey[400] : Colors.grey[600], + ), + ), + ), + ], + )), ], ); } @@ -338,9 +340,8 @@ class HomeView extends GetView { Container( padding: EdgeInsets.all(12.w), decoration: BoxDecoration( - color: isDarkMode - ? Colors.red[900]!.withOpacity(0.2) - : Colors.red[50], + color: + isDarkMode ? Colors.red[900]!.withOpacity(0.2) : Colors.red[50], borderRadius: BorderRadius.circular(12.r), border: Border.all( color: isDarkMode ? Colors.red[800]! : Colors.red[200]!), @@ -440,12 +441,12 @@ class HomeView extends GetView { final leftBattery = controller.leftEarBattery; final rightBattery = controller.rightEarBattery; final caseBattery = controller.caseBattery; - + // 获取充电状态 final leftEarCharging = controller.leftEarCharging; final rightEarCharging = controller.rightEarCharging; final caseCharging = controller.caseCharging; - + return GridView.count( crossAxisCount: 3, shrinkWrap: true, @@ -457,33 +458,33 @@ class HomeView extends GetView { _buildBatteryGridItem( icon: Icons.headphones, label: '左耳机', - batteryLevel: leftBattery, - isCharging: leftEarCharging, + batteryLevel: leftBattery.value, + isCharging: leftEarCharging.value, isDarkMode: isDarkMode, ), - + // 右耳机 _buildBatteryGridItem( icon: Icons.headphones, label: '右耳机', - batteryLevel: rightBattery, - isCharging: rightEarCharging, + batteryLevel: rightBattery.value, + isCharging: rightEarCharging.value, isDarkMode: isDarkMode, ), - + // 充电盒 _buildBatteryGridItem( icon: Icons.charging_station, label: '充电盒', - batteryLevel: caseBattery, - isCharging: caseCharging, + batteryLevel: caseBattery.value, + isCharging: caseCharging.value, isDarkMode: isDarkMode, ), ], ); }); } - + // 单个电池网格项 Widget _buildBatteryGridItem({ required IconData icon, @@ -495,7 +496,7 @@ class HomeView extends GetView { // 获取电池图标和颜色 IconData batteryIcon; Color batteryColor; - + if (batteryLevel > 75) { batteryIcon = Icons.battery_full; batteryColor = Colors.green[600]!; @@ -512,16 +513,16 @@ class HomeView extends GetView { batteryIcon = Icons.battery_alert; batteryColor = Colors.red[600]!; } - + return Container( decoration: BoxDecoration( color: isDarkMode ? Colors.grey[900] : Colors.grey[100], borderRadius: BorderRadius.circular(12.r), boxShadow: [ BoxShadow( - color: isDarkMode ? - Colors.black.withOpacity(0.1) : - Colors.grey.withOpacity(0.1), + color: isDarkMode + ? Colors.black.withOpacity(0.1) + : Colors.grey.withOpacity(0.1), blurRadius: 4, spreadRadius: 0, offset: Offset(0, 2), @@ -545,7 +546,7 @@ class HomeView extends GetView { ), ), SizedBox(height: 6.h), - + // 标签 Text( label, @@ -557,7 +558,7 @@ class HomeView extends GetView { textAlign: TextAlign.center, ), SizedBox(height: 6.h), - + // 电池指示器 Row( mainAxisAlignment: MainAxisAlignment.center, @@ -614,16 +615,15 @@ class HomeView extends GetView { isDarkMode: isDarkMode, ), SizedBox(height: 8.h), - + // 固件版本 _buildInfoRow( icon: Icons.info_outline, label: 'firmwareVersion'.tr, - value: controller.firmwareVersion, + value: controller.firmwareVersion.value, isDarkMode: isDarkMode, ), - - + // 连接状态标签 SizedBox(height: 10.h), Container( @@ -763,7 +763,7 @@ class HomeView extends GetView { ), ); } - + // 热门AI体验标题 Widget _buildSectionTitle(bool isDarkMode) { return Row( diff --git a/lib/modules/ota_upgrade/controllers/ota_upgrade_controller.dart b/lib/modules/ota_upgrade/controllers/ota_upgrade_controller.dart index 878a97be6..a59a16289 100644 --- a/lib/modules/ota_upgrade/controllers/ota_upgrade_controller.dart +++ b/lib/modules/ota_upgrade/controllers/ota_upgrade_controller.dart @@ -1,19 +1,17 @@ import 'package:flutter/material.dart'; import 'package:get/get.dart'; +import 'package:path/path.dart'; import 'dart:async'; -import 'dart:convert'; -import 'package:get_storage/get_storage.dart'; import '../../../data/services/network/api.dart'; -import '../ota.dart'; +import '../model/ota_upgrade_model.dart'; import 'dart:io'; import 'package:dio/dio.dart'; -import 'package:flutter/material.dart'; -import 'package:get/get.dart'; -import 'package:package_info_plus/package_info_plus.dart'; import 'package:path_provider/path_provider.dart'; -import 'package:json_annotation/json_annotation.dart'; +import '../../../data/services/ble_manager.dart'; class OtaUpgradeController extends GetxController { + final RxString errorMessage = ''.obs; + final RxBool isFetchingDeviceInfo = false.obs; final Dio _dio = Dio(); final RxString latestVersion = ''.obs; final RxString currentVersion = ''.obs; @@ -24,41 +22,93 @@ class OtaUpgradeController extends GetxController { final RxDouble progress = 0.0.obs; + // 蓝牙服务 + final _bleManager = Get.find(); @override void onInit() { super.onInit(); _getCurrentVersion(); } - // 获取当前版本信息 + // 添加重试方法 + void retryConnection() { + errorMessage.value = ''; + _getCurrentVersion(); + } + + // 添加更新方法 + Future startUpdate() async { + try { + isUpdating.value = true; + // 实现更新逻辑... + } catch (e) { + errorMessage.value = e.toString(); + Get.snackbar('更新失败', e.toString()); + } finally { + isUpdating.value = false; + } + } + Future _getCurrentVersion() async { - //发送ble获取固件版本 - var firmwareVersion = "1.1.0"; - currentVersion.value = firmwareVersion; - //发送ble获取产品id - var id = "a2"; - //发送api请求 - final response = await Api.getequipmentinfo({ - "id": id, - }); - if (response['info'] != '') { - print('getLoginToken:进来了'); - // 根据API设计调整 - final resp = OtaConfigResp.fromJson(response); + try { + // 添加获取设备信息的重试机制 + DeviceInfo? deviceInfo = _bleManager.deviceInfo.value; + + // 第一次检查设备信息 + if (deviceInfo == null) { + // 显示加载提示 + isFetchingDeviceInfo.value = true; + + // 尝试重新获取设备信息 + await _bleManager.fetchDeviceInfo(); + + // 等待后再次获取设备信息 + deviceInfo = _bleManager.deviceInfo.value; + isFetchingDeviceInfo.value = false; + + // 仍然为空则抛出异常 + if (deviceInfo == null) { + throw const FormatException('无法获取设备信息,请检查设备连接'); + } + } + + // 检查固件信息有效性 + if (deviceInfo.firmwareVersion.isEmpty + //|| + // deviceInfo.firmwareProductId.isEmpty + ) { + throw const FormatException('设备固件信息不完整'); + } + + // 正常流程 + currentVersion.value = deviceInfo.firmwareVersion; - print('成功解析: ${resp.id}, ${resp.factory}'); + // API请求 + final response = await Api.getequipmentinfo({ + "id": "a2", + }); + + // 处理API响应 + if (response['info'] == null) { + throw const FormatException('API 响应格式错误'); + } + + final resp = OtaConfigResp.fromJson(response); latestVersion.value = resp.systemversion!; updatepackageaddress = resp.updatepackageaddress!; - if (_isNewVersionAvailable(resp.systemversion!)) { - //需要升级 - print('需要更新'); - isUpdateAvailable.value = false; - } else { - isUpdateAvailable.value = true; - //已经是最新版本更新ui,按钮隐藏 - } - } else { - throw const FormatException('API 响应缺少 "info" 字段'); + + // 版本检查 + isUpdateAvailable.value = _isNewVersionAvailable(resp.systemversion!); + } catch (e) { + // 统一错误处理 + errorMessage.value = e.toString(); + Get.snackbar('错误', e.toString(), + snackPosition: SnackPosition.BOTTOM, + backgroundColor: Colors.red, + colorText: Colors.white); + // 重要:重新抛出异常以便上层处理(可选) + } finally { + isFetchingDeviceInfo.value = false; } } @@ -120,13 +170,10 @@ class OtaUpgradeController extends GetxController { ); } - // 开始下载 +// 修改后的startDownload方法 Future startDownload() async { isUpdating.value = true; - // 查找最后一个 '/' 的位置 int lastIndex = updatepackageaddress.lastIndexOf('/'); - - // 截取最后一个 '/' 后面的字符串 String fileName = updatepackageaddress.substring(lastIndex + 1); String directoryName = "ota_upgrades"; @@ -145,14 +192,54 @@ class OtaUpgradeController extends GetxController { throw FileSystemException('无法访问下载目录'); } - // 创建子目录:Download/APP final targetDir = Directory('${downloadsDir.path}/$directoryName'); if (!await targetDir.exists()) { await targetDir.create(recursive: true); } final savePath = '${targetDir.path}/$fileName'; - print('文件保存路径: $savePath'); // 关键日志 + + // 新增:检查同名文件逻辑 + bool existingSameFile = false; + try { + var files = await targetDir.list().toList(); + for (var entity in files) { + if (await FileSystemEntity.isFile(entity.path)) { + String name = basename(entity.path); // 使用path包中的basename + if (name == fileName) { + existingSameFile = true; + break; + } + } + } + } catch (e) { + Get.snackbar('错误', '检查本地文件失败: $e'); + isUpdating.value = false; + return; + } + + if (existingSameFile) { + Get.snackbar('文件已存在', '跳过下载,直接更新'); + isUpdating.value = false; + _installApp(savePath); + return; + } + + // 新增:删除其他文件逻辑 + try { + var files = await targetDir.list().toList(); + for (var entity in files) { + if (await FileSystemEntity.isFile(entity.path)) { + await entity.delete(); + } + } + } catch (e) { + Get.snackbar('错误', '删除旧文件失败: $e'); + isUpdating.value = false; + return; + } + + print('文件保存路径: $savePath'); final options = Options( receiveTimeout: Duration.zero, @@ -181,22 +268,23 @@ class OtaUpgradeController extends GetxController { }, ); - // 下载完成后验证文件存在性 File file = File(savePath); if (await file.exists()) { - Get.snackbar('下载完成', '文件已保存至: $savePath'); // 明确提示路径 + Get.snackbar('下载完成', '文件已保存至: $savePath'); } else { Get.snackbar('错误', '文件未找到,请检查写入权限'); } isUpdating.value = false; - //下载完成,开始升级 _installApp(savePath); } on DioException catch (e) { Get.snackbar('下载失败', '错误: ${e.message}'); + isUpdating.value = false; } on FileSystemException catch (e) { Get.snackbar('存储失败', '无法写入文件: ${e.message}'); + isUpdating.value = false; } catch (e) { Get.snackbar('未知错误', e.toString()); + isUpdating.value = false; } } diff --git a/lib/modules/ota_upgrade/ota.dart b/lib/modules/ota_upgrade/model/ota_upgrade_model.dart similarity index 100% rename from lib/modules/ota_upgrade/ota.dart rename to lib/modules/ota_upgrade/model/ota_upgrade_model.dart diff --git a/lib/modules/ota_upgrade/views/ota_upgrade_view.dart b/lib/modules/ota_upgrade/views/ota_upgrade_view.dart index bc507d1e9..a33120845 100644 --- a/lib/modules/ota_upgrade/views/ota_upgrade_view.dart +++ b/lib/modules/ota_upgrade/views/ota_upgrade_view.dart @@ -4,106 +4,126 @@ import '../controllers/ota_upgrade_controller.dart'; class OtaUpgradeView extends GetView { const OtaUpgradeView({Key? key}) : super(key: key); + @override Widget build(BuildContext context) { return Scaffold( body: Center( - // 添加外层Center - child: SingleChildScrollView( - // 添加滚动防止小屏溢出 - child: Padding( - padding: EdgeInsets.all(20), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, // 水平居中 - mainAxisSize: MainAxisSize.min, // 紧凑布局 - children: [ - // 设备图标 - CircleAvatar( - radius: 60, - backgroundColor: Colors.blue[100], - child: Icon( - Icons.phone_iphone, - size: 60, - color: Colors.blue, - ), - ), - SizedBox(height: 30), + child: ConstrainedBox( + constraints: BoxConstraints(maxWidth: 600), // 限制最大宽度 + child: SingleChildScrollView( + child: Padding( + padding: EdgeInsets.all(20), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + // 设备图标 + _buildDeviceIcon(), + SizedBox(height: 30), - // 版本信息 - Column( - children: [ - Text( - '当前版本', - style: TextStyle( - fontSize: 18, - color: Colors.grey, - ), - ), - SizedBox(height: 8), - Text( - 'v${controller.currentVersion}', - style: TextStyle( - fontSize: 24, - fontWeight: FontWeight.bold, - color: Colors.blue, - ), - ), - ], - ), - SizedBox(height: 40), + // 版本信息 + _buildVersionInfo(), + SizedBox(height: 40), - // 更新按钮/进度条 - Obx(() { - if (controller.isUpdating.value) { - return Column( - children: [ - SizedBox( - width: 200, // 限制进度条宽度 - child: LinearProgressIndicator( - value: controller.downloadProgress.value, - backgroundColor: Colors.grey[200], - valueColor: - AlwaysStoppedAnimation(Colors.blue), - minHeight: 12, - borderRadius: BorderRadius.circular(10), - ), - ), - SizedBox(height: 20), - Text( - '${(controller.downloadProgress.value * 100).toStringAsFixed(1)}%', - style: TextStyle(color: Colors.grey), - ) - ], - ); - } else { - return ElevatedButton( - onPressed: controller.isUpdateAvailable.value - ? null - : controller.checkUpdate, - style: ElevatedButton.styleFrom( - backgroundColor: controller.isUpdateAvailable.value - ? Colors.grey - : Colors.blue, - foregroundColor: Colors.white, - padding: - EdgeInsets.symmetric(horizontal: 40, vertical: 15), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(30), - ), - ), - child: Text( - controller.isUpdateAvailable.value ? '已是最新版本' : '立即更新', - style: TextStyle(fontSize: 16), - ), - ); - } - }), - ], + // 状态显示区域 + Obx(() { + if (controller.isFetchingDeviceInfo.value) { + return _buildLoadingIndicator(); + } + if (controller.errorMessage.value.isNotEmpty) { + return _buildErrorInfo(); + } + return _buildUpdateButton(); + }), + ], + ), ), ), ), ), ); } + + // 组件化构建方法 + Widget _buildDeviceIcon() => CircleAvatar( + radius: 60, + backgroundColor: Colors.blue[100], + child: Icon(Icons.phone_iphone, size: 60, color: Colors.blue), + ); + + Widget _buildVersionInfo() => Column( + children: [ + Text('当前版本', style: TextStyle(fontSize: 18, color: Colors.grey)), + SizedBox(height: 8), + Text('v${controller.currentVersion}', + style: TextStyle( + fontSize: 24, + fontWeight: FontWeight.bold, + color: Colors.blue)), + ], + ); + + Widget _buildLoadingIndicator() => Column( + children: [ + CircularProgressIndicator(), + SizedBox(height: 20), + Text('正在连接设备...', style: TextStyle(color: Colors.grey)) + ], + ); + + Widget _buildErrorInfo() => Column( + children: [ + Icon(Icons.error_outline, color: Colors.red, size: 40), + SizedBox(height: 10), + Text(controller.errorMessage.value, + style: TextStyle(color: Colors.red)), + SizedBox(height: 20), + ElevatedButton( + onPressed: controller.retryConnection, + child: Text('重试连接'), + ) + ], + ); + + Widget _buildUpdateButton() { + return controller.isUpdating.value + ? _buildProgressIndicator() + : ElevatedButton( + style: ElevatedButton.styleFrom( + backgroundColor: controller.isUpdateAvailable.value + ? Colors.blue + : Colors.grey, + padding: EdgeInsets.symmetric(horizontal: 40, vertical: 15), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(30), + ), + ), + onPressed: controller.isUpdateAvailable.value + ? controller.startUpdate + : null, + child: Text( + controller.isUpdateAvailable.value ? '立即更新' : '已是最新版本', + style: TextStyle(fontSize: 16, color: Colors.white), + ), + ); + } + + Widget _buildProgressIndicator() => Column( + children: [ + SizedBox( + width: 200, + child: LinearProgressIndicator( + value: controller.downloadProgress.value, + backgroundColor: Colors.grey[200], + valueColor: AlwaysStoppedAnimation(Colors.blue), + minHeight: 12, + borderRadius: BorderRadius.circular(10), + ), + ), + SizedBox(height: 20), + Text( + '${(controller.downloadProgress.value * 100).toStringAsFixed(1)}%', + style: TextStyle(color: Colors.grey)) + ], + ); } diff --git a/local_plugins/ble_service/android/src/main/kotlin/com/yunqiinnovation/ble_service/BleService.kt b/local_plugins/ble_service/android/src/main/kotlin/com/yunqiinnovation/ble_service/BleService.kt index ef5a6553d..dd6d24917 100644 --- a/local_plugins/ble_service/android/src/main/kotlin/com/yunqiinnovation/ble_service/BleService.kt +++ b/local_plugins/ble_service/android/src/main/kotlin/com/yunqiinnovation/ble_service/BleService.kt @@ -473,7 +473,7 @@ object BleService { } override fun onCharacteristicChanged(g: BluetoothGatt, c: BluetoothGattCharacteristic) { - + val data = c.value ?: return // 根据特征UUID区分处理 @@ -1017,9 +1017,11 @@ object BleService { stopOpusStreamDecoding() // 停止Opus解码流 return sendCommand( BleConst.CMD_CONTROL_CODEC.toByte(), - byteArrayOf(BleConst.CODEC_CONTROL_CLOSE.toByte(), - - BleConst.AUDIO_CHANNEL_RIGHT.toByte()) // 或其他默认声道 + byteArrayOf( + BleConst.CODEC_CONTROL_CLOSE.toByte(), + + BleConst.AUDIO_CHANNEL_RIGHT.toByte() + ) // 或其他默认声道 ) } @@ -1027,45 +1029,54 @@ object BleService { * 控制编解码 - 打开解码 */ fun openDecoder(): Boolean { - FileLogger.i(TAG, "打开编码 (设备侧)...") + FileLogger.i(TAG, "打开编码 (设备侧)...") val opusStarted = startOpusStreamDecoding( hasHeader = false, // BLE传输的Opus数据通常无文件头 channel = 1, // 单声道 sampleRate = 16000,// Opus推荐16kHz或更高 packetSize = 40 // Opus常用帧长,如20ms, 40ms, 60ms。 (16000Hz * 1channel * 2bytes/sample * 0.04s = 1280 bytes/frame if PCM) - // packetSize for Opus is typically in ms, e.g. 20, 40, 60. - // The library might expect this in a different unit or derive it. - // Given JlOpusPlugin.kt, packetSize refers to Opus encoded frame duration in ms. + // packetSize for Opus is typically in ms, e.g. 20, 40, 60. + // The library might expect this in a different unit or derive it. + // Given JlOpusPlugin.kt, packetSize refers to Opus encoded frame duration in ms. ) - + FileLogger.i(TAG, "打开解码...") - return sendCommand(BleConst.CMD_CONTROL_CODEC.toByte(), byteArrayOf(BleConst.CODEC_CONTROL_DECODE_ON.toByte(), - - BleConst.AUDIO_CHANNEL_RIGHT.toByte())) + return sendCommand( + BleConst.CMD_CONTROL_CODEC.toByte(), byteArrayOf( + BleConst.CODEC_CONTROL_DECODE_ON.toByte(), + + BleConst.AUDIO_CHANNEL_RIGHT.toByte() + ) + ) } + /** * 控制编解码 - 打开解码 */ fun openA2DPDecoder(): Boolean { - FileLogger.i(TAG, "打开编码 (设备侧)...") + FileLogger.i(TAG, "打开编码 (设备侧)...") val opusStarted = startOpusStreamDecoding( hasHeader = false, // BLE传输的Opus数据通常无文件头 channel = 1, // 单声道 sampleRate = 16000,// Opus推荐16kHz或更高 packetSize = 40 // Opus常用帧长,如20ms, 40ms, 60ms。 (16000Hz * 1channel * 2bytes/sample * 0.04s = 1280 bytes/frame if PCM) - // packetSize for Opus is typically in ms, e.g. 20, 40, 60. - // The library might expect this in a different unit or derive it. - // Given JlOpusPlugin.kt, packetSize refers to Opus encoded frame duration in ms. + // packetSize for Opus is typically in ms, e.g. 20, 40, 60. + // The library might expect this in a different unit or derive it. + // Given JlOpusPlugin.kt, packetSize refers to Opus encoded frame duration in ms. ) - + FileLogger.i(TAG, "打开解码...") - return sendCommand(BleConst.CMD_CONTROL_CODEC.toByte(), byteArrayOf(BleConst.CODEC_CONTROL_A2DP_PLAY.toByte(), - - BleConst.AUDIO_CHANNEL_RIGHT.toByte())) + return sendCommand( + BleConst.CMD_CONTROL_CODEC.toByte(), byteArrayOf( + BleConst.CODEC_CONTROL_A2DP_PLAY.toByte(), + + BleConst.AUDIO_CHANNEL_RIGHT.toByte() + ) + ) } /** @@ -1087,11 +1098,11 @@ object BleService { channel = 1, // 单声道 sampleRate = 16000,// Opus推荐16kHz或更高 packetSize = 40 // Opus常用帧长,如20ms, 40ms, 60ms。 (16000Hz * 1channel * 2bytes/sample * 0.04s = 1280 bytes/frame if PCM) - // packetSize for Opus is typically in ms, e.g. 20, 40, 60. - // The library might expect this in a different unit or derive it. - // Given JlOpusPlugin.kt, packetSize refers to Opus encoded frame duration in ms. + // packetSize for Opus is typically in ms, e.g. 20, 40, 60. + // The library might expect this in a different unit or derive it. + // Given JlOpusPlugin.kt, packetSize refers to Opus encoded frame duration in ms. ) - + // 注意:此方法通常是控制设备端开始编码并发送数据。 // App侧通常是打开解码器(openDecoder)来接收和处理这些数据。 @@ -1178,7 +1189,6 @@ object BleService { return bluetoothAdapter } - // ====================================================================================================== // 资源清理 diff --git a/local_plugins/ble_service/ios/Classes/BleService.swift b/local_plugins/ble_service/ios/Classes/BleService.swift index b4c2ae456..92f129d9a 100644 --- a/local_plugins/ble_service/ios/Classes/BleService.swift +++ b/local_plugins/ble_service/ios/Classes/BleService.swift @@ -353,6 +353,11 @@ actor BleService { func getDeviceVersion() -> Bool { return sendCommand(BleConst.CMD_GET_VERSION) } + ///获取产品ID + /// - Returns: 是否成功发送请求 + func getProductId() -> Bool { + return sendCommand(BleConst.CMD_GET_PRODUCT_ID) + } /// 获取电池信息 /// - Returns: 是否成功发送请求 @@ -371,6 +376,11 @@ actor BleService { func openDecoder() -> Bool { return sendCodecControl(BleConst.CODEC_CONTROL_DECODE_ON) } + /// 打开解码器 + /// - Returns: 是否成功发送请求 + func openA2DPDecoder() -> Bool { + return sendCodecControl(BleConst.CODEC_CONTROL_A2DP_PLAY) + } /// 关闭编解码器 /// - Returns: 是否成功发送请求 diff --git a/local_plugins/ble_service/ios/Classes/SwiftBleServicePlugin.swift b/local_plugins/ble_service/ios/Classes/SwiftBleServicePlugin.swift index 140c0ca7a..e3004c43c 100644 --- a/local_plugins/ble_service/ios/Classes/SwiftBleServicePlugin.swift +++ b/local_plugins/ble_service/ios/Classes/SwiftBleServicePlugin.swift @@ -73,12 +73,18 @@ public class SwiftBleServicePlugin: NSObject, FlutterPlugin, BleDelegate { case "getDeviceVersion": result(bleService.getDeviceVersion()) + case "getProductId": + result(bleService.getProductId()) + case "openEncoder": result(bleService.openEncoder()) case "openDecoder": result(bleService.openDecoder()) - + + case "openA2DPDecoder": + result(bleService.openA2DPDecoder()) + case "closeCodec": result(bleService.closeCodec()) diff --git a/local_plugins/ble_service/lib/ble_service.dart b/local_plugins/ble_service/lib/ble_service.dart index 3b791b437..9b28d7cfc 100644 --- a/local_plugins/ble_service/lib/ble_service.dart +++ b/local_plugins/ble_service/lib/ble_service.dart @@ -83,6 +83,17 @@ class BleService { } } + /// 获取产品ID + Future getProductId() async { + try { + final result = await _methodChannel.invokeMethod('getProductId'); + return result ?? false; + } catch (e) { + print('获取设备版本失败: $e'); + return false; + } + } + /// 获取电池信息 Future getBatteryInfo() async { try {