- 开发工具
【免费下载链接】Squirrel.Windows
An installation and update framework for Windows desktop apps
导读
Squirrel.Windows 是一套面向 Windows 桌面应用的安装与更新框架,它在生成安装程序(Setup.exe)、创建桌面/开始菜单快捷方式以及注册 Windows "程序和功能"(Programs and Features)卸载条目时,会同时从应用 EXE 的版本资源和 NuGet 包的元数据(nuspec)中提取信息。本文以官方文档 docs/using/nuget-package-metadata.md 为主体,逐字段讲解Id、Title、Version、IconUrl、Language五项元数据的作用、取值来源与注意事项,并结合仓库源码揭示这些字段在安装、卸载与打包链路中的真实调用关系,帮助你正确配置 nuspec,避免踩坑。
一、元数据从何而来:EXE 与 nuspec 的"双输入"模型
Squirrel 的安装与卸载 UI 所需信息有两个来源(见 nuget-package-metadata.md):
- 应用的 EXE 文件:主要指通过
rcedit.exe等工具写入 PE 资源的版本信息(CompanyName、FileDescription、ProductName 等)。在 src/Update/Program.cs 的setPEVersionInfoAndIcon方法中,--releasify流程会用rcedit.exe将 nuspec 中的authors、description、summary、copyright、version等数据回写到 EXE 资源中。 - NuGet 包元数据(nuspec):打包时由 nuspec 的
<metadata>节点提供,Squirrel 运行期通过 NuGet 的ZipPackage读取(参见 src/Squirrel/ReleaseEntry.cs 中GetIconUrl对zp.IconUrl的读取)。
两个输入互为补充,但 nuspec 元数据是"主干",本文重点讨论后者。
二、Id:应用标识,决定安装目录与发布包文件名
Id是应用在 Squirrel 体系中的唯一标识,直接影响两个关键产物:
- 发布包文件名:
--releasify生成的包命名为<Id>-<Version>-full.nupkg与<Id>-<Version>-delta.nupkg。该命名逻辑在 src/Squirrel/ReleasePackage.cs 中实现:return String.Format("{0}-{1}-full.nupkg", zp.Id, zp.Version);例如
Id = MyApp、Version = 1.0.0时,生成MyApp-1.0.0-full.nupkg。 - 本地安装目录:应用被安装到
%LocalAppData%\<Id>目录(如%LocalAppData%\MyApp),对应官方文档 docs/using/naming.md 中的 "Local Install location" 一节。
⚠️ 命名警告(issue #523):Id严禁包含空格和点(.)。空格与点会在包名解析(src/Squirrel/ReleaseEntry.cs 用正则^([\w-]+)-\d+\..+\.nupkg$解析PackageName)、目录创建、快捷方式命名等多个环节引发问题。另外在 src/Squirrel/UpdateManager.ApplyReleases.cs 中,Squirrel 用com.squirrel.{Id}.{exeName}生成 AppUserModelID 时会显式Replace(" ", "")去除空格,可见空格是需要规避的字符。
三、Title:Windows 卸载程序中显示的应用名
Title用于Windows 应用程序卸载程序(Programs and Features)中显示的应用名称,也就是上图中 "Name" 列的内容。源码层面的证据位于 src/Squirrel/UpdateManager.InstallHelpers.cs,写入卸载注册表的DisplayName取值为:
new { Key = "DisplayName", Value = zp.Title ?? zp.Description ?? zp.Summary },即优先使用Title,缺失时依次回退到Description、Summary。同时 src/Squirrel/UpdateManager.ApplyReleases.cs 的linkTargetForVersionInfo显示,快捷方式名称(.lnk)的命名优先级为:EXE 的ProductName→ 包Title→ EXE 的FileDescription→ EXE 文件名,Title在其中占据第二顺位(完整优先级见 docs/using/naming.md)。
四、Version:发布包版本与卸载条目版本号
Version的取值来自Properties\AssemblyInfo.cs(即程序集版本,打包时写入 nuspec 的<version>节点),其作用包括:
- 发布包文件名中的版本段:如
MyApp-1.0.0-full.nupkg中的1.0.0(与Id一节同理,见 src/Squirrel/ReleasePackage.cs)。 - Windows 卸载程序中的版本号:上图中 "Version" 列的内容。写入卸载注册表的
DisplayVersion由zp.Version.ToString()直接生成(src/Squirrel/UpdateManager.InstallHelpers.cs)。
版本号同时会被回写到 EXE 资源(--set-file-version/--set-product-version,见 src/Update/Program.cs),确保资源管理器中的"文件版本/产品版本"与卸载条目一致。
五、IconUrl:快捷方式与卸载程序图标(安装时获取!)
IconUrl是图标的 URL,用于:
- 桌面/开始菜单快捷方式图标;
- Windows 卸载程序(Programs and Features)中该应用的图标(注册表
DisplayIcon项)。
重要约束:IconUrl必须指向一个.ico(Icon)文件才能正确工作;且图标是在安装时从该 URL 获取,而非打包时(来源:issue #745)。
源码完整还原了这一流程(src/Squirrel/UpdateManager.InstallHelpers.cs):
if (zp.IconUrl != null && !File.Exists(targetIco)) { using (var wc = Utility.CreateWebClient()) { await wc.DownloadFileTaskAsync(zp.IconUrl, targetPng); using (var fs = new FileStream(targetIco, FileMode.Create)) { if (zp.IconUrl.AbsolutePath.EndsWith("ico")) { var bytes = File.ReadAllBytes(targetPng); fs.Write(bytes, 0, bytes.Length); // 直接拷贝 .ico } else { using (var bmp = (Bitmap)Image.FromFile(targetPng)) using (var ico = Icon.FromHandle(bmp.GetHicon())) { ico.Save(fs); // 其他格式临时转 .ico } } key.SetValue("DisplayIcon", targetIco, RegistryValueKind.String); } } }运行期读取 IconUrl 的入口是 src/Squirrel/ReleaseEntry.cs 的GetIconUrl,它直接从ZipPackage.IconUrl取值。需要注意:安装机在安装那一刻必须能访问该 URL;若下载失败,Squirrel 只记录一条日志("Couldn't write uninstall icon, don't care")而不会中断安装(src/Squirrel/UpdateManager.InstallHelpers.cs),因此建议将图标托管在稳定可达的地址上。
六、Language:非英文字符的代码页支持
Language字段用于修改代码页(codepage),以支持非英文字符。未设置时默认为 1252(Windows-1252,西文 Latin-1 代码页)。
其实现位于 src/Update/Program.cs 的createMsiPackage中,nuspec 的language会被解析为对应的 ANSI 代码页,并填入 WiX MSI 模板的Codepage占位符:
var culture = CultureInfo.GetCultureInfo(package.Language ?? "").TextInfo.ANSICodePage; // templateData["Codepage"] = $"{culture}";也就是说,若应用界面/安装文本包含非英文(如中文、日文、西里尔文等),应在 nuspec 中显式设置language为对应的文化名称(如zh-CN、ja-JP),否则安装程序可能按默认 1252 代码页处理导致乱码。此外在卸载注册表条目中,Squirrel 固定写入LanguageDWORD 值为0x0409(en-US 的 LCID,见 src/Squirrel/UpdateManager.InstallHelpers.cs)。
七、实战:一份完整的 nuspec 配置示例
综合以上字段,一个规范的 nuspec<metadata>节点应如下配置(参考仓库测试夹具 test/Squirrel.Tests/fixtures/Squirrel.Core.1.1.0.0.nuspec 的结构扩展):
<?xml version="1.0"?> <package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd"> <metadata> <id>MyApp</id> <!-- 无空格、无点 --> <version>1.0.0</version> <!-- 与 AssemblyInfo 版本一致 --> <title>My App</title> <!-- 卸载程序显示名 --> <authors>MyCompany</authors> <!-- 写入卸载条目 Publisher --> <owners>MyCompany</owners> <description>My desktop application.</description> <summary>Short summary for file properties.</summary> <releaseNotes>What changed in this release.</releaseNotes> <language>zh-CN</language> <!-- 非英文场景必配,默认 1252 --> <iconUrl>https://example.com/app.ico</iconUrl> <!-- 必须 .ico,安装时下载 --> <requireLicenseAcceptance>false</requireLicenseAcceptance> </metadata> <files> <file src="lib\net45\MyApp.exe" target="lib\net45\MyApp.exe" /> </files> </package>配套补充(写入卸载条目的其他字段,src/Squirrel/UpdateManager.InstallHelpers.cs):
| 注册表项 | 取值来源 |
|---|---|
DisplayName | Title??Description??Summary |
DisplayVersion | Version |
Publisher | Authors(逗号拼接) |
DisplayIcon | 安装时从IconUrl下载的app.ico |
InstallLocation | %LocalAppData%\<Id> |
URLUpdateInfo | ProjectUrl(如配置) |
Language | 固定0x0409 |
八、常见问题与最佳实践小结
- Id 千万别带空格和点:否则发布包命名、安装目录、AppUserModelID、包名解析都会出问题(issue #523)。
- Title 缺失时卸载程序会"降级"显示:按
Title → Description → Summary回退,建议至少补齐Description。 - IconUrl 必须是 .ico 且安装期可访问:Squirrel 在安装时下载图标并缓存在应用根目录
app.ico;URL 不可达不会中断安装,但卸载程序将无图标。 - 非英文应用务必配置
language:不配置时回退到 1252 代码页,可能造成安装文本乱码。 - 版本号保持 nuspec 与 AssemblyInfo 一致:二者同时影响发布包文件名、卸载条目
DisplayVersion与 EXE 资源版本。
参见
- Naming Conventions(命名约定总览):从 EXE 资源、nuspec 元数据到快捷方式/安装目录/卸载条目命名规则的完整优先级链。
- Update Manager 安装辅助实现:卸载注册表条目的完整写入逻辑。
- 打包/发布流程:
--releasify如何消费上述元数据生成 Setup.exe 与发布包。
- 开发工具
【免费下载链接】Squirrel.Windows
An installation and update framework for Windows desktop apps
相关推荐
Squirrel.Windows 打包全流程指南:构建、NuGet 打包与 Releasify 发布
Squirrel.Windows 打包全流程指南:构建、NuGet 打包与 Releasify 发布 本篇技术指南围绕 Squirrel.Windows 入门教
开发工具AzerothCore开源MMO服务器三步快速部署
AzerothCore开源MMO服务器三步快速部署 你本地已装好Docker,先花两分钟看看效果。AzerothCore开源MMO服务器是面向魔兽世界3.3.5
游戏开发后端Orleans NuGet 包全景指南:元包、Provider 与测试包的选择与使用
Orleans NuGet 包全景指南:元包、Provider 与测试包的选择与使用 本指南以 nuget packages.md https://link.g
后端微服务
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考