Files
desktop-plugin/lib/ui/app_tray.dart
T
dzc 527baf7ec5 fix(windows): 托盘图标不显示——tray_manager 原生 LoadImage 只认 .ico
用户 Windows 实测:日志"托盘已就绪"无报错、不在折叠区,但任务栏无图标。
源码级定位:tray_manager 0.5.3 Windows 原生端用
LoadImage(IMAGE_ICON, LR_LOADFROMFILE) 加载图标文件——该 Win32 API 只认
.ico,传入 png 返回 NULL → Shell_NotifyIcon 添加成功但图标为空 → 任务栏
不显示且全程无任何报错(mac 走 base64+NSImage 另一条路径所以正常)。

修复:Windows 托盘改用 assets/tray_icon_win.ico(16/24/32 三尺寸 PNG-in-ICO,
gen_app_icons.dart 生成,python struct 校验目录项 offset 严格对齐;ico 随
flutter_assets 打包,Debug/Release/Inno 全形态生效);删除无效的
tray_icon_win.png;AppTray 按平台选路径。
2026-09-21 16:27:03 +08:00

84 lines
2.3 KiB
Dart

import 'dart:io';
import 'package:tray_manager/tray_manager.dart';
import 'package:window_manager/window_manager.dart';
import '../agent.dart';
/// 后台托盘:点窗口关闭按钮 = 隐藏窗口进后台(服务继续运行),
/// 托盘常驻(mac 菜单栏 template 图标 / Windows 系统托盘彩色图标),
/// 单击/双击托盘恢复窗口,右键弹菜单,退出入口只放在托盘菜单里。
class AppTray with TrayListener, WindowListener {
AppTray({required this.agent});
final Agent agent;
static const _menuShow = 'menu_show';
static const _menuExit = 'menu_exit';
bool _started = false;
Future<void> start() async {
if (_started) return;
_started = true;
windowManager.addListener(this);
await windowManager.setPreventClose(true);
await trayManager.setIcon(
Platform.isMacOS ? 'assets/tray_icon_mac.png' : 'assets/tray_icon_win.ico',
);
await trayManager.setToolTip('资安信插件助手 · 饭卡打印(后台运行中)');
await trayManager.setContextMenu(_menu);
trayManager.addListener(this);
agent.log.write('托盘已就绪:关闭窗口将最小化到托盘,服务持续运行');
}
// ---------------- 窗口事件 ----------------
@override
void onWindowClose() async {
// 关窗不退出:隐藏窗口,服务与托盘保持运行
await windowManager.hide();
}
// ---------------- 托盘事件 ----------------
@override
void onTrayIconMouseDown() => _showWindow();
@override
void onTrayIconRightMouseDown() {
trayManager.popUpContextMenu();
}
@override
void onTrayMenuItemClick(MenuItem menuItem) async {
switch (menuItem.key) {
case _menuShow:
await _showWindow();
case _menuExit:
await _exitApp();
}
}
Menu get _menu => Menu(
items: [
MenuItem(key: _menuShow, label: '显示主界面'),
MenuItem.separator(),
MenuItem(key: _menuExit, label: '退出'),
],
);
Future<void> _showWindow() async {
await windowManager.show();
await windowManager.focus();
}
Future<void> _exitApp() async {
agent.log.write('用户从托盘退出,停止服务');
await agent.stop();
await trayManager.destroy();
await windowManager.destroy();
}
}