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 按平台选路径。
This commit is contained in:
dzc committed 2026-09-21 16:27:03 +08:00
1 parent 1deb3125be
commit 527baf7ec5
5 files changed
+37 -4

No files matched your search

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 719 B

+1 -1
View File
@@ -25,7 +25,7 @@ class AppTray with TrayListener, WindowListener {
await windowManager.setPreventClose(true);
await trayManager.setIcon(
Platform.isMacOS ? 'assets/tray_icon_mac.png' : 'assets/tray_icon_win.png',
Platform.isMacOS ? 'assets/tray_icon_mac.png' : 'assets/tray_icon_win.ico',
);
await trayManager.setToolTip('资安信插件助手 · 饭卡打印(后台运行中)');
await trayManager.setContextMenu(_menu);
+2 -1
View File
@@ -71,9 +71,10 @@ flutter:
uses-material-design: true
# 托盘图标(白底圆盘+logo,深浅菜单栏/任务栏均可见)与侧栏 logo
# Windows 托盘必须用 .ico(tray_manager 原生 LoadImage 只认 ico,png 静默失败)
assets:
- assets/tray_icon_mac.png
- assets/tray_icon_win.png
- assets/tray_icon_win.ico
- assets/logo.png
# HiTi Mac 驱动安装包(不进 git:放 assets/drivers/*.dmg 后重新打包;缺失时向导降级为官网链接)
- assets/drivers/
+34 -2
View File
@@ -134,8 +134,40 @@ void main(List<String> args) {
Directory('assets').createSync(recursive: true);
File('assets/tray_icon_mac.png').writeAsBytesSync(encodePng(trayIcon(64)));
File('assets/tray_icon_win.png').writeAsBytesSync(encodePng(trayIcon(32)));
print('written assets/tray_icon_mac.png / tray_icon_win.png');
print('written assets/tray_icon_mac.png');
// Windows 托盘必须用 .ico:tray_manager 的原生端 LoadImage(IMAGE_ICON) 只认
// ico 文件(传 png 返回 NULL → 图标空占位、任务栏不显示且无任何报错)
Uint8List buildIcoFrom(Image Function(int) generator, List<int> sizes) {
final pngs = <int, Uint8List>{
for (final s in sizes) s: Uint8List.fromList(encodePng(generator(s))),
};
final b = BytesBuilder();
// ICONDIR:reserved=0, type=icon, count
b.addByte(0); b.addByte(0); b.addByte(1); b.addByte(0);
b.addByte(sizes.length); b.addByte(0);
var offset = 6 + 16 * sizes.length;
// 目录项全部在前
for (final s in sizes) {
final png = pngs[s]!;
b.addByte(s); b.addByte(s); b.addByte(0); b.addByte(0);
b.addByte(1); b.addByte(0); b.addByte(32); b.addByte(0);
for (var i = 0; i < 4; i++) {
b.addByte((png.length >> (8 * i)) & 0xff);
}
for (var i = 0; i < 4; i++) {
b.addByte((offset >> (8 * i)) & 0xff);
}
offset += png.length;
}
// PNG 数据全部在后
for (final s in sizes) {
b.add(pngs[s]!);
}
return b.toBytes();
}
final trayIco = buildIcoFrom(trayIcon, [16, 24, 32]);
File('assets/tray_icon_win.ico').writeAsBytesSync(trayIco);
print('written assets/tray_icon_win.ico (${trayIco.length} bytes)');
// ---------- 原样 logo ----------
File('assets/logo.png').writeAsBytesSync(encodePng(logo));