# Omni-Notify 开发者文档 本文档面向需要构建、修改、审查或发布 Omni-Notify 的开发者。最终用户安装和使用说明请见 [README.md](../README.md)。 ## 技术栈 - .NET 8 - WPF - Windows Forms `NotifyIcon` - Built-in `HttpListener` - JSON 本地持久化 项目不依赖第三方 NuGet 包。 ## 项目结构 | 文件 | 责任 | | --- | --- | | `App.xaml.cs` | 应用生命周期、单实例互斥、托盘入口、本地 HTTP 服务启动 | | `MainWindow.xaml` | 主控制面板 UI | | `MainWindow.xaml.cs` | 频道管理、历史筛选、全局设置保存 | | `Models.cs` | 应用状态、频道、弹窗样式、历史记录、输入消息模型 | | `Services.cs` | 状态持久化、消息路由、限流熔断、本地 HTTP 接收服务 | | `PopupCoordinator.cs` | 弹窗队列、堆叠、替换和位置计算 | | `PopupWindow.xaml` | 单个弹窗窗口 UI | | `PopupWindow.xaml.cs` | 弹窗动画、生命周期和正文溢出处理 | | `app.manifest` | Windows 应用清单,声明普通用户权限运行 | | `scripts/package-release.ps1` | 标准发布脚本 | ## 本地构建 ```powershell dotnet build .\OmniNotify.csproj -c Release ``` 目标框架: ```xml net8.0-windows ``` 应用类型为 WPF 桌面应用,输出为 `WinExe`。 ## 本地运行 ```powershell dotnet run --project .\OmniNotify.csproj ``` 默认监听: ```text http://127.0.0.1:19845/ ``` 通知接口: ```text POST http://127.0.0.1:19845/notify ``` 请求体: ```json { "channel": "default", "title": "Build finished", "body": "The nightly job completed successfully." } ``` ## 状态持久化 状态文件路径: ```text %LOCALAPPDATA%\OmniNotify\state.json ``` 保存内容包括: - 全局设置 - 频道列表和频道样式 - 历史记录 `AppStore.Save` 会在写入前清理超出保留天数和数量限制的历史记录。 ## 消息处理流程 1. `LocalHttpServer` 接收本地 HTTP 请求。 2. 请求体反序列化为 `IncomingMessage`。 3. `NotificationRouter.Receive` 进入 UI Dispatcher。 4. 检查熔断状态和每秒消息上限。 5. 按 `channel` 严格匹配频道。 6. 根据免打扰状态决定是否弹窗。 7. 写入历史记录。 8. `PopupCoordinator` 按频道样式显示弹窗。 未知频道不会弹窗,会记录为 `IllegalChannel`。 ## 发布包 生成 v0.2.0 Windows x64 发布包: ```powershell .\scripts\package-release.ps1 -Version 0.2.0 ``` 默认产物: ```text artifacts\omni-notify-v0.2.0-win-x64.zip ``` 脚本参数: | 参数 | 默认值 | 说明 | | --- | --- | --- | | `Configuration` | `Release` | 构建配置 | | `Version` | `0.2.0` | 应用版本和产物版本 | | `RuntimeIdentifier` | `win-x64` | 目标运行时标识 | ## 发布策略 当前发布策略刻意保持透明、标准和低风险: - `SelfContained=false` - `PublishSingleFile=false` - `PublishTrimmed=false` - `PublishReadyToRun=false` - `--self-contained false` - 不使用混淆器 - 不使用 UPX - 不使用自解压启动器 - 不请求管理员权限 发布脚本会检查产物目录中是否出现以下 .NET 运行时文件: - `coreclr.dll` - `clrjit.dll` - `hostfxr.dll` - `hostpolicy.dll` 如果出现这些文件,脚本会失败,避免误发布自包含运行时包。 ## 安全敏感行为约束 v0.2.0 已删除开机自启功能。代码中不应重新引入以下行为,除非经过明确产品决策: - 写入 `HKCU\Software\Microsoft\Windows\CurrentVersion\Run` - 创建计划任务实现自启动 - 后台下载或执行外部程序 - 全局键盘/鼠标钩子 - 注入、提权、隐藏进程或绕过安全产品 应用保留的本地监听服务仅绑定 `127.0.0.1`,不应改为 `0.0.0.0` 或局域网地址,除非同时补充认证和明确的安全设计。 ## 版本与 Git 发布新版本时: 1. 更新 `OmniNotify.csproj` 中的 `Version`、`FileVersion`、`AssemblyVersion`。 2. 更新 `app.manifest` 中的 `assemblyIdentity version`。 3. 更新文档中的示例版本号。 4. 运行发布脚本生成 zip。 5. 验证发布目录不包含 .NET 运行时文件。 6. 提交代码。 7. 创建 tag,例如 `v0.2.0`。 8. 推送分支和 tag。 建议 tag 命名: ```text vMAJOR.MINOR.PATCH ``` 建议发布资产命名: ```text omni-notify-vMAJOR.MINOR.PATCH-win-x64.zip ``` ## v0.2.0 发布摘要 - 删除开机自启功能及相关注册表写入逻辑。 - 新增标准应用清单,声明普通用户权限运行。 - 新增 framework-dependent 发布脚本。 - 发布包改为 `omni-notify-v0.2.0-win-x64.zip`。 - README 改为用户文档,开发信息迁入本文档。