diff --git a/assets/tray_icon_win.ico b/assets/tray_icon_win.ico new file mode 100644 index 0000000..a26d605 Binary files /dev/null and b/assets/tray_icon_win.ico differ diff --git a/assets/tray_icon_win.png b/assets/tray_icon_win.png deleted file mode 100644 index 01223ff..0000000 Binary files a/assets/tray_icon_win.png and /dev/null differ diff --git a/lib/ui/app_tray.dart b/lib/ui/app_tray.dart index 4fb90be..d2d3ff9 100644 --- a/lib/ui/app_tray.dart +++ b/lib/ui/app_tray.dart @@ -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); diff --git a/pubspec.yaml b/pubspec.yaml index c3ce963..3340931 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -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/ diff --git a/tool/gen_app_icons.dart b/tool/gen_app_icons.dart index 7e68266..6b9f60a 100644 --- a/tool/gen_app_icons.dart +++ b/tool/gen_app_icons.dart @@ -134,8 +134,40 @@ void main(List 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 sizes) { + final pngs = { + 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));