diff --git a/airhub_app/ios/Podfile.lock b/airhub_app/ios/Podfile.lock index d68fb16..c650a4f 100644 --- a/airhub_app/ios/Podfile.lock +++ b/airhub_app/ios/Podfile.lock @@ -1,8 +1,4 @@ PODS: - - ali_auth (1.3.7): - - Flutter - - MJExtension - - SDWebImage - audio_session (0.0.1): - Flutter - Flutter (1.0.0) @@ -14,12 +10,8 @@ PODS: - just_audio (0.0.1): - Flutter - FlutterMacOS - - MJExtension (3.4.2) - permission_handler_apple (9.3.0): - Flutter - - SDWebImage (5.21.6): - - SDWebImage/Core (= 5.21.6) - - SDWebImage/Core (5.21.6) - shared_preferences_foundation (0.0.1): - Flutter - FlutterMacOS @@ -28,7 +20,6 @@ PODS: - FlutterMacOS DEPENDENCIES: - - ali_auth (from `.symlinks/plugins/ali_auth/ios`) - audio_session (from `.symlinks/plugins/audio_session/ios`) - Flutter (from `Flutter`) - flutter_blue_plus_darwin (from `.symlinks/plugins/flutter_blue_plus_darwin/darwin`) @@ -38,14 +29,7 @@ DEPENDENCIES: - shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`) - webview_flutter_wkwebview (from `.symlinks/plugins/webview_flutter_wkwebview/darwin`) -SPEC REPOS: - trunk: - - MJExtension - - SDWebImage - EXTERNAL SOURCES: - ali_auth: - :path: ".symlinks/plugins/ali_auth/ios" audio_session: :path: ".symlinks/plugins/audio_session/ios" Flutter: @@ -64,15 +48,12 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/webview_flutter_wkwebview/darwin" SPEC CHECKSUMS: - ali_auth: fe9a6188a90eb39227f3674c05a71383ac4ec6a2 audio_session: 9bb7f6c970f21241b19f5a3658097ae459681ba0 Flutter: cabc95a1d2626b1b06e7179b784ebcf0c0cde467 flutter_blue_plus_darwin: 20a08bfeaa0f7804d524858d3d8744bcc1b6dbc3 image_picker_ios: e0ece4aa2a75771a7de3fa735d26d90817041326 just_audio: 4e391f57b79cad2b0674030a00453ca5ce817eed - MJExtension: e97d164cb411aa9795cf576093a1fa208b4a8dd8 permission_handler_apple: 4ed2196e43d0651e8ff7ca3483a069d469701f2d - SDWebImage: 1bb6a1b84b6fe87b972a102bdc77dd589df33477 shared_preferences_foundation: 7036424c3d8ec98dfe75ff1667cb0cd531ec82bb webview_flutter_wkwebview: 8ebf4fded22593026f7dbff1fbff31ea98573c8d diff --git a/airhub_app/lib/core/network/api_config.dart b/airhub_app/lib/core/network/api_config.dart index 89b6863..cc20d06 100644 --- a/airhub_app/lib/core/network/api_config.dart +++ b/airhub_app/lib/core/network/api_config.dart @@ -1,6 +1,6 @@ class ApiConfig { /// 后端服务器地址(开发环境请替换为实际 IP) - static const String baseUrl = 'http://192.168.124.24:8000'; + static const String baseUrl = 'http://192.168.124.8:8000'; /// App 端 API 前缀 static const String apiPrefix = '/api/v1'; diff --git a/airhub_app/lib/core/services/log_center_service.dart b/airhub_app/lib/core/services/log_center_service.dart index d22cc2b..948577c 100644 --- a/airhub_app/lib/core/services/log_center_service.dart +++ b/airhub_app/lib/core/services/log_center_service.dart @@ -16,6 +16,7 @@ class LogCenterService { defaultValue: 'https://qiyuan-log-center-api.airlabs.art', ); static const String _url = '$_baseUrl/api/v1/logs/report'; + static const String _registerUrl = '$_baseUrl/api/v1/projects/register'; static const String _projectId = 'airhub_app'; static const String _repoUrl = 'https://gitea.airlabs.art/zyc/rtc_prd.git'; @@ -29,6 +30,24 @@ class LogCenterService { )); } + /// 初始化:向 Log Center 注册项目 + Future initialize() async { + try { + await _dio.post(_registerUrl, data: { + 'project_id': _projectId, + 'repo_url': _repoUrl, + 'description': 'Flutter mobile app (subdirectory of rtc_prd repo)', + 'platform': defaultTargetPlatform.name, + 'environment': const String.fromEnvironment( + 'ENVIRONMENT', + defaultValue: kDebugMode ? 'development' : 'production', + ), + }); + } catch (_) { + // 静默失败,不影响 App 启动 + } + } + /// 上报 Flutter 框架错误(FlutterError) void reportFlutterError(FlutterErrorDetails details) { _report( diff --git a/airhub_app/lib/features/device/domain/entities/device.g.dart b/airhub_app/lib/features/device/domain/entities/device.g.dart index efe2721..04c0e22 100644 --- a/airhub_app/lib/features/device/domain/entities/device.g.dart +++ b/airhub_app/lib/features/device/domain/entities/device.g.dart @@ -33,9 +33,9 @@ _DeviceInfo _$DeviceInfoFromJson(Map json) => _DeviceInfo( deviceType: (json['device_type'] is Map) ? DeviceType.fromJson(json['device_type'] as Map) : null, - deviceTypeInfo: json['device_type_info'] == null - ? null - : DeviceType.fromJson(json['device_type_info'] as Map), + deviceTypeInfo: (json['device_type_info'] is Map) + ? DeviceType.fromJson(json['device_type_info'] as Map) + : null, macAddress: json['mac_address'] as String?, name: json['name'] as String? ?? '', status: json['status'] as String? ?? 'in_stock', diff --git a/airhub_app/lib/main.dart b/airhub_app/lib/main.dart index 21a7dc8..ef9f08b 100644 --- a/airhub_app/lib/main.dart +++ b/airhub_app/lib/main.dart @@ -14,6 +14,7 @@ void main() { final container = ProviderContainer(); final logCenter = container.read(logCenterServiceProvider); + logCenter.initialize(); // 捕获 Flutter 框架错误(Widget build 异常等) FlutterError.onError = (details) { diff --git a/airhub_app/lib/pages/bluetooth_page.dart b/airhub_app/lib/pages/bluetooth_page.dart index cde01a0..a1a989f 100644 --- a/airhub_app/lib/pages/bluetooth_page.dart +++ b/airhub_app/lib/pages/bluetooth_page.dart @@ -75,7 +75,7 @@ class _BluetoothPageState extends ConsumerState static const _airhubPrefix = 'Airhub_'; // 状态 - bool _isSearching = true; + bool _isSearching = !kIsWeb; // Web 平台不自动搜索,需用户手势触发 bool _isBluetoothOn = false; List _devices = []; int _currentIndex = 0; @@ -132,7 +132,8 @@ class _BluetoothPageState extends ConsumerState setState(() => _isBluetoothOn = isOn); if (isOn) { - _startSearch(); + // Web 平台: BLE scan 必须由用户手势触发,不自动扫描 + if (!kIsWeb) _startSearch(); } else if (state == BluetoothAdapterState.off) { FlutterBluePlus.stopScan(); setState(() { @@ -307,6 +308,7 @@ class _BluetoothPageState extends ConsumerState /// 请求蓝牙权限 Future _requestPermissions() async { + if (kIsWeb) return; // Web 平台无需请求原生权限 try { if (Platform.isAndroid) { // Android 需要位置权限才能扫描 BLE @@ -324,7 +326,7 @@ class _BluetoothPageState extends ConsumerState /// 蓝牙未开启弹窗 void _showBluetoothOffDialog() { - if (!mounted) return; + if (!mounted || kIsWeb) return; // Web 平台不弹原生蓝牙设置弹窗 showGlassDialog( context: context, title: '蓝牙未开启', @@ -781,9 +783,9 @@ class _BluetoothPageState extends ConsumerState return Container( padding: EdgeInsets.fromLTRB( 20, // HTML: 20px sides - 20, // HTML: 20px top + 16, // HTML: 20px top (reduced to prevent overflow) 20, - MediaQuery.of(context).padding.bottom + 60, // HTML: safe-area + 60px + MediaQuery.of(context).padding.bottom + 40, // HTML: safe-area + bottom padding ), child: Row( mainAxisAlignment: MainAxisAlignment.center, @@ -812,6 +814,16 @@ class _BluetoothPageState extends ConsumerState ), ), ), + // 搜索按钮 (Web 平台初始状态或无设备时显示) + if (!_isSearching && _devices.isEmpty) ...[ + const SizedBox(width: 16), + GradientButton( + text: '搜索设备', + width: 180, + height: 52, + onPressed: _startSearch, + ), + ], // 连接按钮 (搜索完成后显示) if (!_isSearching && _devices.isNotEmpty) ...[ const SizedBox(width: 16), // HTML: gap 16px