import 'dart:io'; import 'package:flutter/material.dart'; import 'package:window_manager/window_manager.dart'; import 'agent.dart'; import 'setup/single_instance.dart'; import 'setup/url_scheme.dart'; import 'ui/app_shell.dart'; import 'ui/app_tray.dart'; import 'utils/file_log.dart'; /// 资安信插件助手(desktop-plugin):桌面插件集成软件。 /// 当前内置插件:饭卡打印机(card-printer);左侧菜单与插件页均由 lib/ui/routes.dart 驱动。 /// 关闭窗口 = 最小化到后台托盘,服务持续运行;退出入口在托盘菜单。 /// /// 健壮性铁律:runApp 之前的任何非关键步骤(托盘/scheme 注册/单实例)一律 /// try-catch 吞错并记日志——否则在目标机环境差异下抛异常会让界面永远起不来 /// (窗口由原生创建、Dart 未 runApp = 白屏窗口),开发机上无法复现。 Future main(List args) async { WidgetsFlutterBinding.ensureInitialized(); // 文件日志最先初始化(此后的每一步现场都可追溯;目录不可用时自动禁用) FileLog.init(); FileLog.write('==== 启动 ===='); FileLog.write( '环境: ${Platform.operatingSystem} ${Platform.operatingSystemVersion} / exe: ${Platform.resolvedExecutable} / args: $args'); String? bootWarning; try { await windowManager.ensureInitialized(); } catch (e) { bootWarning = '窗口管理初始化失败:$e'; FileLog.write(bootWarning); } // 单实例:zaxprint:// 唤起或重复双击会启动第二进程——通知常驻实例弹窗后自己退出 bool isPrimary = true; try { isPrimary = await SingleInstance.acquire( onWake: () async { FileLog.write('收到唤醒(zaxprint:// 或重复双击):显示主窗口'); await windowManager.show(); await windowManager.focus(); }, ); } catch (e) { bootWarning = '${bootWarning == null ? "" : "$bootWarning\n"}单实例检测失败:$e'; FileLog.write(bootWarning); } if (!isPrimary) { FileLog.write('已有常驻实例(唤醒通知已发),本进程退出'); exit(0); } final agent = Agent(AgentOptions.parse(args)); String? startError; try { await agent.start(); } catch (e) { startError = '$e'; agent.log.write('服务启动失败:$startError'); } try { await UrlScheme.ensureRegistered(); // Windows 运行时注册 zaxprint://;mac 由 Info.plist 声明 } catch (e) { agent.log.write('网页唤起协议注册失败(不影响其他功能):$e'); } final appTray = AppTray(agent: agent); try { await appTray.start(); } catch (e) { agent.log.write('托盘初始化失败(不影响其他功能):$e'); } agent.log.write('界面启动(日志目录:${FileLog.dir ?? "不可用"})'); runApp(DesktopPluginApp(agent: agent, startError: startError ?? bootWarning)); } class DesktopPluginApp extends StatelessWidget { const DesktopPluginApp({super.key, required this.agent, this.startError}); final Agent agent; final String? startError; @override Widget build(BuildContext context) { return MaterialApp( title: '资安信插件助手', debugShowCheckedModeBanner: false, theme: _darkTheme(), home: AppShell(agent: agent, startError: startError), ); } /// 深色运维风格(ui-ux-pro-max 设计系统:OLED 深底 + 运维三色语义)。 ThemeData _darkTheme() { final base = ThemeData(brightness: Brightness.dark, useMaterial3: true); final scheme = base.colorScheme.copyWith( // 正常/主操作:operational green primary: const Color(0xFF4ADE80), onPrimary: const Color(0xFF052E16), primaryContainer: const Color(0xFF14532D), onPrimaryContainer: const Color(0xFFDCFCE7), // 故障红 error: const Color(0xFFF87171), errorContainer: const Color(0xFF7F1D1D), onErrorContainer: const Color(0xFFFEE2E2), // 表面层级:#0F172A 底 / #111827 卡 / #1E293B 强调 surface: const Color(0xFF0F172A), onSurface: const Color(0xFFF8FAFC), onSurfaceVariant: const Color(0xFFCBD5E1), surfaceContainerLow: const Color(0xFF111827), surfaceContainerHighest: const Color(0xFF1E293B), outlineVariant: const Color(0xFF334155), ); return base.copyWith( colorScheme: scheme, scaffoldBackgroundColor: const Color(0xFF0F172A), cardTheme: const CardTheme(color: Color(0xFF111827)), snackBarTheme: const SnackBarThemeData(behavior: SnackBarBehavior.floating), dividerTheme: const DividerThemeData(color: Color(0xFF334155), thickness: 1), ); } }