
1. 项目缘起为什么我们需要一个详细的NSIS打包教程如果你是一名Windows桌面应用的开发者或者负责过软件产品的发布流程那么“打包”这个词对你来说一定不陌生。打包简单来说就是把你的源代码、资源文件、依赖库等一堆零散的东西变成一个用户双击就能安装的、像模像样的安装程序。这个过程看似是开发的最后一步却往往是决定用户体验的第一道门槛。我见过太多优秀的软件因为打包环节的粗糙而“劝退”用户安装界面简陋、安装路径混乱、卸载不干净留下“注册表垃圾”、甚至因为缺少某个系统组件而直接闪退。用户不会去深究这是开发的问题还是打包的问题他们只会觉得“这个软件不好用”。所以一个专业、稳定、可控的安装包是软件产品交付给用户的“第一张名片”。在Windows平台上制作安装包的工具有很多从商业化的InstallShield、Advanced Installer到开源免费的Inno Setup、NSIS。今天我们要深入探讨的就是NSISNullsoft Scriptable Install System。它由Winamp的开发者Nullsoft创建以其轻量、高效、脚本化程度高而闻名。NSIS生成的安装程序体积可以做到非常小因为它本质上是一个自解压的脚本解释器通过脚本精确控制安装的每一个步骤。对于追求极致性能和灵活性的开发者或者需要制作复杂安装逻辑如多语言、条件安装、自定义页面的场景NSIS几乎是开源方案中的不二之选。然而NSIS的“脚本化”特性既是其强大之处也是其学习门槛所在。它不像一些带图形界面的工具那样“点点点”就能完成你需要编写一个.nsi脚本文件来定义整个安装过程。网上能找到的教程要么过于简单只教你怎么弹出个对话框要么过于晦涩直接丢给你一堆API文档。缺少一份从环境搭建、脚本编写、到调试排错、最终优化的完整“保姆级”指南。这就是我写这篇教程的初衷。我将以一个真实的、稍具复杂度的桌面应用打包需求为例手把手带你走通NSIS打包的全流程。我们不仅会写出能用的脚本更会深入每一个指令背后的逻辑分享我踩过的坑和积累的技巧目标是让你看完后能独立应对绝大多数打包需求并理解其所以然。2. 环境准备与核心工具链搭建工欲善其事必先利其器。NSIS的整个工作流围绕几个核心工具展开理解它们各自的作用是高效工作的基础。2.1 NSIS编译器的安装与选择首先你需要去NSIS的官方网站下载安装程序。这里就有第一个选择你应该下载哪个版本NSIS主要提供两个大版本稳定版Stable和开发版Development。对于生产环境我强烈建议你使用稳定版。开发版虽然包含了最新的特性和修复但可能存在未知的稳定性问题。我们的目标是做出可靠的安装包而不是追新。安装过程很简单一路“下一步”即可。安装完成后你会在开始菜单或安装目录下看到几个关键的可执行文件makensisw.exe 这是带图形界面的编译器。你可以直接拖拽.nsi脚本文件到它的窗口上或者通过它的菜单打开脚本进行编译。它的输出窗口会显示编译过程和任何错误信息非常适合初学者和调试。makensis.exe 这是命令行编译器。功能与makensisw.exe完全一致但它是为自动化构建如集成到CI/CD流水线中准备的。你可以通过命令行参数传递脚本路径和自定义定义。NSIS.exe 这是一个集成的环境包含了编译器和一个简单的脚本编辑器。对于编写复杂的脚本我更推荐使用专门的代码编辑器或IDE。2.2 脚本编辑器的选择为什么不用记事本你完全可以用记事本或任何文本编辑器来写.nsi脚本。但很快你就会发现效率低下没有语法高亮、没有代码提示、没有错误跳转。因此选择一个合适的编辑器至关重要。Visual Studio Code NSIS插件 这是目前最主流、体验最好的方案。在VSCode的扩展商店中搜索“NSIS”你会找到如NSIS IDE或NSIS等插件。安装后你会获得语法高亮 不同的指令、变量、字符串会用不同颜色区分一目了然。代码片段 输入几个字母按Tab键就能快速生成一段常用代码模板如定义一个页面。错误提示 插件能实时检查一些基本的语法错误。一键编译 配置好任务后可以按快捷键直接调用makensis.exe编译当前脚本。Notepad 语法高亮文件 如果你习惯使用Notepad可以手动导入或下载NSIS的语法高亮定义文件.xml或.udl格式。这能提供基础的色彩区分但功能上不如VSCode插件全面。专用NSIS编辑器 如HM NIS Edit这是一个历史比较悠久的NSIS集成编辑环境内置了向导、编译器集成和资源编辑器。对于习惯传统独立软件的用户来说是个不错的选择。我的选择与建议 毫不犹豫地使用VSCode NSIS插件。它不仅免费、跨平台而且其强大的扩展生态和调试能力能极大提升你编写和调试NSIS脚本的效率。后续的教程示例我也会基于这个环境来演示。2.3 理解NSIS的工作目录结构安装好NSIS后其目录下有几个重要的子文件夹了解它们有助于你后续查找文件和解决问题Include\ 存放NSIS的标准头文件.nsh。这些头文件预定义了很多有用的函数、宏和常量。例如LogicLib.nsh提供了If...Else...EndIf等逻辑判断宏FileFunc.nsh提供了文件操作的函数。在你的脚本中可以通过!include指令来引入它们。Plugins\ 存放NSIS的插件.dll文件。插件极大地扩展了NSIS的能力例如nsDialogs插件允许你创建自定义的安装界面System插件可以调用系统API。大部分常用插件已随NSIS主程序一同安装。Examples\ 官方提供的示例脚本。这是非常好的学习资料当你不知道某个功能如何实现时来这里翻看示例往往能找到灵感。Contrib\ 存放社区贡献的图形界面、图标、现代UI等资源。著名的Modern UI 2MUI2就放在这里的Modern UI\目录下。MUI2提供了一套现代化、美观的安装界面模板是大多数NSIS安装包的基础。3. 第一个NSIS脚本从“Hello World”安装包开始让我们从一个最简单的脚本开始直观感受NSIS是如何工作的。打开VSCode新建一个文件保存为HelloInstaller.nsi。; 注释以分号开头。这是一个最简单的NSIS脚本示例。 ; 1. 设置安装程序的基本属性 Outfile “HelloWorldSetup.exe” ; 最终生成的安装包名称 InstallDir $PROGRAMFILES\MyHelloApp ; 默认安装目录$PROGRAMFILES通常是C:\Program Files ; 2. 定义一个“节”Section。节是NSIS脚本执行的基本单位。 ; 这里我们定义一个名为“主程序”的节它是必须安装的所以是“必选”。 Section “主程序” SecMain ; 设置输出路径为用户选择的安装目录 SetOutPath $INSTDIR ; 将当前目录下的一个文件例如你的主程序HelloWorld.exe打包进安装程序 ; 请确保在同目录下有一个名为HelloWorld.exe的文件 File “HelloWorld.exe” ; 在开始菜单创建快捷方式 CreateDirectory “$SMPROGRAMS\MyHelloApp” ; 先在开始菜单创建程序组文件夹 CreateShortCut “$SMPROGRAMS\MyHelloApp\MyHelloApp.lnk” “$INSTDIR\HelloWorld.exe” SectionEnd ; 3. 定义一个“卸载程序”节。卸载逻辑通常单独写在一个节里。 Section “Uninstall” ; 删除安装目录及其所有文件 RMDir /r $INSTDIR ; 删除开始菜单快捷方式 Delete “$SMPROGRAMS\MyHelloApp\MyHelloApp.lnk” RMDir “$SMPROGRAMS\MyHelloApp” ; 如果文件夹空了也删除它 SectionEnd现在在同目录下放一个随便什么可执行文件重命名为HelloWorld.exe或者修改脚本中的文件名。然后在VSCode中打开终端导航到脚本所在目录执行命令makensis HelloInstaller.nsi如果一切顺利你会看到编译成功的提示并在当前目录下生成一个HelloWorldSetup.exe。运行它你会看到一个极其简陋只有进度条的安装界面完成后会在指定目录安装文件并创建开始菜单快捷方式。通过控制面板卸载它也能正确清理。这个简单示例揭示了几个核心概念OutfileInstallDir 这些是编译时指令用于定义安装程序的元信息。Section 这是功能逻辑的容器。一个安装包可以有多个节用户可以在自定义安装页面选择安装哪些节。SetOutPathFileCreateShortCut 这些是运行时指令在安装过程中执行。变量 如$INSTDIR用户选择的安装目录、$PROGRAMFILES系统程序文件目录、$SMPROGRAMS开始菜单程序目录。使用变量让脚本更灵活。注意 这个示例没有界面直接执行安装逻辑。在实际项目中我们几乎总是需要更友好的用户界面。这就需要引入NSIS最强大的特性之一页面Pages和现代用户界面Modern UI。4. 构建专业安装界面深入Modern UI (MUI2)没有人喜欢一个黑乎乎只有进度条的安装程序。NSIS通过Modern UI 2 (MUI2) 提供了一套现代化、可高度定制的安装向导界面。它是通过包含头文件和调用一系列宏来实现的。让我们改造上面的HelloInstaller.nsi加入完整的向导界面。; 引入Modern UI 2的核心头文件 !include “MUI2.nsh” ; 基本属性设置 Outfile “HelloWorldSetup_MUI.exe” InstallDir $PROGRAMFILES\MyHelloApp ; 安装目录注册表记录用于在“添加/删除程序”中正确显示安装位置并为后续安装提供默认路径 InstallDirRegKey HKLM “SOFTWARE\MyHelloApp” “Install_Dir” ; 定义压缩方式LZMA通常能提供最好的压缩比 SetCompressor /SOLID lzma ; —————— MUI2 界面配置 —————— ; 定义界面中使用的变量 !define MUI_ABORTWARNING ; 当用户点击取消时显示警告对话框 !define MUI_ICON “${NSISDIR}\Contrib\Graphics\Icons\modern-install.ico” ; 安装程序图标 !define MUI_UNICON “${NSISDIR}\Contrib\Graphics\Icons\modern-uninstall.ico” ; 卸载程序图标 !define MUI_WELCOMEFINISHPAGE_BITMAP “${NSISDIR}\Contrib\Graphics\Wizard\win.bmp” ; 欢迎/完成页面的侧边栏位图 ; 插入页面宏 ; 页面顺序决定了安装向导的流程 !insertmacro MUI_PAGE_WELCOME ; 欢迎页面 !insertmacro MUI_PAGE_LICENSE “${NSISDIR}\Docs\Modern UI\License.txt” ; 许可协议页面示例请替换为你自己的License.txt !insertmacro MUI_PAGE_DIRECTORY ; 选择安装目录页面 !insertmacro MUI_PAGE_INSTFILES ; 安装文件进度页面 !insertmacro MUI_PAGE_FINISH ; 完成页面 ; 插入卸载页面宏 !insertmacro MUI_UNPAGE_CONFIRM ; 卸载确认页面 !insertmacro MUI_UNPAGE_INSTFILES ; 卸载进度页面 ; 加载语言文件必须放在页面宏之后 !insertmacro MUI_LANGUAGE “SimpChinese” ; 使用简体中文界面 ; —————— 安装节 —————— Section “主程序” SecMain SetOutPath $INSTDIR File “HelloWorld.exe” ; 将安装路径写入注册表供卸载程序和未来升级使用 WriteRegStr HKLM “SOFTWARE\MyHelloApp” “Install_Dir” “$INSTDIR” ; 写入卸载信息到“添加/删除程序” WriteUninstaller “$INSTDIR\Uninstall.exe” WriteRegStr HKLM “SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\MyHelloApp” “DisplayName” “My Hello App” WriteRegStr HKLM “SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\MyHelloApp” “UninstallString” ‘”$INSTDIR\Uninstall.exe”‘ WriteRegStr HKLM “SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\MyHelloApp” “DisplayIcon” “$INSTDIR\HelloWorld.exe” WriteRegDWORD HKLM “SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\MyHelloApp” “NoModify” 1 ; 不允许修改 WriteRegDWORD HKLM “SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\MyHelloApp” “NoRepair” 1 ; 不允许修复 SectionEnd ; —————— 卸载节 —————— Section “Uninstall” ; 删除注册表项 DeleteRegKey HKLM “SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\MyHelloApp” DeleteRegKey HKLM “SOFTWARE\MyHelloApp” ; 删除安装目录 RMDir /r $INSTDIR ; 删除开始菜单快捷方式如果之前创建了 Delete “$SMPROGRAMS\MyHelloApp\MyHelloApp.lnk” RMDir “$SMPROGRAMS\MyHelloApp” SectionEnd关键点解析与避坑指南页面顺序!insertmacro MUI_PAGE_*的顺序就是安装时页面出现的顺序。这个顺序非常重要且符合用户习惯欢迎→许可→目录→安装→完成。语言加载时机!insertmacro MUI_LANGUAGE必须在所有页面宏定义之后、节Section定义之前调用。如果顺序错了界面可能显示为英文或直接报错。注册表操作InstallDirRegKey 在安装开始时NSIS会尝试从这个注册表键读取上次的安装路径作为默认目录显示给用户。这提供了良好的升级体验。WriteRegStr/WriteRegDWORD 在安装节中我们将安装信息写入注册表。最重要的是向Uninstall键下写入信息这样你的程序才会出现在系统的“应用和功能”或“添加/删除程序”列表中并且卸载命令指向我们生成的Uninstall.exe。DeleteRegKey 在卸载节中必须清理这些注册表项否则会留下“垃圾”。卸载程序生成WriteUninstaller指令会在$INSTDIR下生成一个名为Uninstall.exe的文件。这个文件包含了“Uninstall”节中的所有逻辑。卸载时系统就是调用这个程序。资源路径${NSISDIR}是一个内置变量指向NSIS的安装根目录。示例中使用的图标和位图都是NSIS自带的。在实际项目中你应该替换为自己的资源文件路径如”my-resources\setup-icon.ico”。实操心得 关于界面位图.bmpNSIS对位图格式有要求通常是150x57像素的24位位图。如果你使用其他尺寸或格式的图片可能会导致界面显示异常。建议使用专业的图片编辑工具如Photoshop、GIMP或在线转换工具确保图片格式完全符合要求。5. 处理复杂依赖文件、目录与运行环境一个真实的应用程序很少只有一个可执行文件。它通常包含动态链接库DLL、配置文件、资源文件如图片、音频、以及运行时环境如.NET Framework, VC Redistributable。5.1 打包多个文件与目录结构NSIS的File指令功能强大支持通配符和目录递归。Section “主程序” SetOutPath $INSTDIR File “MyApp.exe” ; 单个文件 File /r “Libs\*.dll” ; 递归打包Libs目录下的所有DLL File /r “Resources\” ; 递归打包整个Resources目录保持其内部结构 SectionEnd/r参数表示递归recursive会包含指定路径下的所有子目录和文件。使用SetOutPath可以多次切换输出目录从而构建复杂的安装后目录结构。SetOutPath $INSTDIR File “MyApp.exe” SetOutPath $INSTDIR\Config File “config.ini” SetOutPath $INSTDIR\Plugins File /r “MyPlugins\*.dll”5.2 安装系统运行库以VC Redistributable为例许多C开发的程序依赖微软的Visual C运行时库。如果用户电脑上没有程序会无法启动。NSIS可以帮你检测并安装它。方法一 打包并静默安装将对应版本的VC Redistributable安装包如vcredist_x64.exe下载到你的项目目录。在NSIS脚本中Section “运行时库” SecVCRedist ; 假设vcredist_x64.exe在编译目录的Redist文件夹下 SetOutPath $PLUGINSDIR ; $PLUGINSDIR是一个NSIS提供的临时目录安装结束后会自动清理 File “Redist\vcredist_x64.exe” ; 静默安装参数/install /quiet /norestart ExecWait ‘”$PLUGINSDIR\vcredist_x64.exe” /install /quiet /norestart’ ; ExecWait会等待安装程序结束才继续/quiet表示无界面/norestart表示不强制重启 SectionEnd你可以在“自定义安装”页面让用户选择是否安装运行时库通过节的状态SectionGetFlags来判断。方法二 使用NSIS插件检测有第三方插件如VCRedistDetect可以更精确地检测是否已安装特定版本的运行时库。这需要你先下载并安装该插件。使用插件可以避免不必要的重复安装。5.3 创建开始菜单快捷方式与桌面图标创建快捷方式不仅仅是调用CreateShortCut还要考虑用户体验和系统规范。Section “创建快捷方式” ; 创建开始菜单程序组和快捷方式 CreateDirectory “$SMPROGRAMS\MyCompany\MyApp” CreateShortCut “$SMPROGRAMS\MyCompany\MyApp\MyApp.lnk” “$INSTDIR\MyApp.exe” CreateShortCut “$SMPROGRAMS\MyCompany\MyApp\Uninstall.lnk” “$INSTDIR\Uninstall.exe” ; 创建桌面快捷方式可选通常让用户选择 ; 首先我们可以定义一个变量来让用户选择 Var /GLOBAL CreateDesktopShortcut ; 在某个自定义页面后面会讲上提供一个复选框让用户设置这个变量 ; 然后在安装节中判断 ${If} $CreateDesktopShortcut 1 CreateShortCut “$DESKTOP\MyApp.lnk” “$INSTDIR\MyApp.exe” ${EndIf} SectionEnd在卸载节中别忘了删除这些快捷方式Section “Uninstall” Delete “$DESKTOP\MyApp.lnk” Delete “$SMPROGRAMS\MyCompany\MyApp\*.lnk” RMDir “$SMPROGRAMS\MyCompany\MyApp” ; 注意RMDir只能删除空目录所以要先删除里面的文件 RMDir “$SMPROGRAMS\MyCompany” ; 如果也空了可以删除上级目录 SectionEnd踩坑记录 快捷方式的路径变量如$DESKTOP、$SMPROGRAMS指向的是当前用户的目录。如果你的安装程序是以管理员权限运行的并且希望为所有用户创建快捷方式应该使用$COMMONFILES、$COMMONPROGRAMS、$COMMONDESKTOPDIRECTORY注意变量名可能因NSIS版本略有不同请查阅文档。这是一个常见的权限与路径混淆问题。6. 高级功能与自定义页面当基础功能满足后你可能会需要更复杂的交互比如让用户选择安装组件、输入配置信息、或者显示一个自定义的配置页面。这需要用到NSIS的nsDialogs插件。6.1 自定义安装组件页面NSIS内置了组件选择页面MUI_PAGE_COMPONENTS但它的样式是固定的。如果你想有更复杂的组件逻辑如互斥选择、依赖关系可能需要结合自定义页面或脚本来实现。首先在页面序列中插入组件页!insertmacro MUI_PAGE_COMPONENTS ; 放在目录页之前比较合适 !insertmacro MUI_PAGE_DIRECTORY然后在你的节Section定义中使用SectionIn指令来控制该节出现在哪个安装类型典型、完全、自定义中并使用SectionSetText设置显示文本。 更高级的组件依赖关系可以通过SectionGetFlags、SectionSetFlags等指令在.onSelChange回调函数中编程实现。6.2 使用nsDialogs创建自定义页面假设我们需要一个页面让用户输入服务器地址。我们需要创建一个自定义页面并插入到向导序列中。; 引入必要的头文件 !include “nsDialogs.nsh” !include “LogicLib.nsh” ; 定义页面变量 Page custom nsDialogsPageCreate nsDialogsPageLeave ; 自定义页面 ; 定义控件句柄和输入值变量 Var Dialog Var ServerAddressLabel Var ServerAddressText Var ServerAddress ; 这个变量将保存用户输入的值 Function nsDialogsPageCreate ; 创建对话框 nsDialogs::Create 1018 Pop $Dialog ${If} $Dialog error Abort ${EndIf} ; 创建标签 ${NSD_CreateLabel} 0 0 100% 12u “请输入服务器地址” Pop $ServerAddressLabel ; 创建文本输入框 ${NSD_CreateText} 0 13u 100% 12u “127.0.0.1:8080” ; 默认值 Pop $ServerAddressText ; 显示对话框 nsDialogs::Show FunctionEnd Function nsDialogsPageLeave ; 页面即将离开时获取输入框的值 ${NSD_GetText} $ServerAddressText $ServerAddress ; 这里可以添加验证逻辑比如检查格式 ${If} $ServerAddress “” MessageBox MB_OK|MB_ICONEXCLAMATION “服务器地址不能为空” Abort ; 阻止页面离开 ${EndIf} ; 可以将$ServerAddress写入一个配置文件 ; FileOpen $0 “$INSTDIR\config.ini” w ; FileWrite $0 “[Server]$\r$\nAddress$ServerAddress$\r$\n” ; FileClose $0 FunctionEnd ; 在安装节中可以使用$ServerAddress变量 Section “安装主程序” ; … 其他安装逻辑 … ; 将服务器地址写入配置文件 SetOutPath $INSTDIR FileOpen $0 “$INSTDIR\config.ini” w FileWrite $0 “[Server]$\r$\n” FileWrite $0 “Address$ServerAddress$\r$\n” FileClose $0 SectionEnd关键点解析Page custom指令定义了一个自定义页面并指定了创建函数和离开验证函数。nsDialogs::Create创建对话框容器参数1018是父窗口的句柄对于页面来说通常是这个值。${NSD_Create*}是nsDialogs提供的宏用于创建各种控件Label, Text, Button, Checkbox等。参数依次是左、上、宽、高和文本。nsDialogs::Show显示这个自定义页面。在PageLeave函数中我们获取用户输入并进行验证。如果验证失败调用Abort可以阻止向导进入下一页。用户输入的值保存在变量如$ServerAddress中可以在后续的安装节中使用。经验之谈nsDialogs给了你极大的灵活性但UI美化比较有限。如果你需要非常华丽的安装界面可能需要考虑其他打包工具或者使用nsDialogs配合自绘位图来实现。对于大多数专业软件MUI2提供的标准界面加上一两个简单的自定义配置页面已经完全够用且能保持与系统风格一致。7. 脚本调试与常见问题排查即使经验丰富的开发者编写NSIS脚本也难免出错。掌握调试方法至关重要。7.1 使用MessageBox进行“打印”调试这是最原始也是最有效的方法。在脚本中插入MessageBox可以显示变量的值或确认某段代码是否被执行。Var MyVar StrCpy $MyVar “Hello Debug” MessageBox MB_OK “MyVar的值是$MyVar” ; 弹窗显示变量值 ; 在函数中调试 Function MyFunction MessageBox MB_OK “函数MyFunction被调用了” FunctionEnd7.2 查看详细的编译日志在命令行编译时使用/V4参数可以输出最详细的编译日志。makensis /V4 MyInstaller.nsi这会输出所有宏展开、变量赋值、文件处理等详细信息对于查找脚本语法错误或逻辑问题非常有帮助。7.3 利用日志文件NSIS安装程序在运行时可以生成日志文件记录所有执行的操作。这对于排查安装过程中的问题如文件复制失败、注册表写入被拒非常有用。 在安装程序命令行后加上/LOG参数MyInstallerSetup.exe /LOGinstall.log或者你可以在脚本开头强制启用日志!define MUI_FINISHPAGE_NOAUTOCLOSE ; 安装完成后不自动关闭窗口方便查看日志 LogSet on ; 开启日志7.4 常见错误与解决方案编译错误Invalid command: [某个指令]原因 通常是拼写错误或者该指令所在的头文件.nsh没有被包含。解决 检查指令拼写。如果是宏或函数如${If}确保已包含对应的头文件如!include “LogicLib.nsh”。安装时错误Error opening file for writing: [文件路径]原因 目标文件正在被其他进程占用如杀毒软件、资源管理器预览或者安装目录没有写入权限。解决关闭可能占用文件的程序。尝试以管理员身份运行安装程序。在脚本中对于可能被占用的文件如正在运行的主程序可以先尝试用ExecWait关闭它或者使用/REBOOTOK参数让NSIS在重启后替换文件。File /REBOOTOK “MyApp.exe” ; 如果文件被锁定计划在重启后替换卸载不干净原因 卸载节Section “Uninstall”中遗漏了某些文件、目录或注册表项的删除操作。解决 仔细核对安装节中所有创建了资源的地方文件、目录、快捷方式、注册表、环境变量等确保在卸载节中都有对应的清理操作。使用RMDir /r要格外小心确保路径变量$INSTDIR是正确的避免误删用户其他文件。界面乱码或中文不显示原因 NSIS脚本文件.nsi的编码问题。NSIS编译器默认可能不支持UTF-8。解决 将脚本文件保存为带BOM的UTF-8编码或ANSIGB2312编码。在VSCode中可以通过右下角的编码状态栏进行转换。同时确保在MUI_LANGUAGE中使用了正确的中文语言包如”SimpChinese”。安装包体积过大原因 打包了不必要的文件或者没有使用高效的压缩算法。解决使用SetCompressor /SOLID lzma。LZMA是NSIS支持的最高压缩比算法/SOLID参数将所有文件视为一个整体压缩能进一步提升压缩率但代价是解压稍慢。仔细检查File指令避免打包源代码、临时文件、版本控制文件夹如.git.svn等。对于大型的、已压缩的文件如.zip.7z 高清图片单独压缩的收益不大可以考虑不压缩它们以加快安装速度SetCompress off/File /NOCUSTOM。8. 从脚本到产品优化与发布 checklist当你完成核心功能的脚本编写后还需要一些“打磨”工作才能让安装包真正达到产品级质量。8.1 添加数字签名给安装程序.exe进行数字签名是专业软件发布的标配。它能向用户和操作系统证明软件的发布者身份并能避免一些杀毒软件的误报和Windows SmartScreen的警告。 你需要从可信的证书颁发机构CA购买代码签名证书。签名通常在编译完成后进行可以使用微软的signtool.exe包含在Windows SDK中signtool sign /f “MyCertificate.pfx” /p “证书密码” /t http://timestamp.digicert.com “HelloWorldSetup.exe”其中/t参数是时间戳服务确保即使证书过期签名依然有效。你可以将这条命令集成到你的构建脚本中。8.2 版本信息与属性右键点击安装程序选择“属性”-“详细信息”可以看到文件的版本、描述等信息。这些信息可以通过NSIS指令在编译时嵌入。; 在脚本开头定义版本信息 VIProductVersion “1.0.0.0” ; 格式为 major.minor.patch.build VIAddVersionKey “FileVersion” “1.0.0.0” VIAddVersionKey “ProductVersion” “1.0.0.0” VIAddVersionKey “CompanyName” “My Company” VIAddVersionKey “FileDescription” “My Awesome Application Installer” VIAddVersionKey “LegalCopyright” “© 2023 My Company. All rights reserved.” VIAddVersionKey “OriginalFilename” “MyAppSetup.exe”这些信息会让你的安装包看起来更正规。8.3 构建自动化手动编译和签名效率低下且容易出错。你应该建立一个自动化构建流程。使用批处理文件.bat 最简单的自动化方式。echo off makensis /V2 MyInstaller.nsi if errorlevel 1 ( echo 编译失败 pause exit /b 1 ) signtool sign … … 签名命令 echo 构建成功集成到CI/CD 如果你使用Jenkins, GitLab CI, GitHub Actions等可以将makensis和signtool作为构建步骤实现每次代码提交后自动生成签名的安装包。8.4 最终发布清单在将安装包交付给用户或上传到网站前请对照此清单检查[ ]功能测试 在一台干净的虚拟机或测试机上完整运行安装流程。安装路径选择是否正常所有文件是否被正确复制快捷方式是否创建在正确的位置程序能否正常启动[ ]卸载测试 运行卸载程序。是否完全清理了安装目录是否删除了所有快捷方式是否清理了注册表项检查HKCU和HKLM下相关项卸载后重新安装是否正常[ ]升级测试 如果这是新版本测试从旧版本覆盖安装。用户配置是否保留是否会出现文件冲突[ ]安全扫描 使用杀毒软件扫描安装包确保没有误报数字签名能极大减少误报。[ ]版本核对 确认安装包属性中的版本号与预期一致。[ ]文件大小 确认最终生成的安装包大小合理没有打包进无关大文件。NSIS打包是一个细节决定成败的工作。它要求开发者不仅关注代码本身还要站在最终用户的角度去思考安装、使用和卸载的每一个环节。这份教程涵盖了从入门到进阶的核心知识点但NSIS的潜力远不止于此它还有条件编译、多语言、插件扩展等更多高级特性等待你去探索。希望这份详细的指南能成为你Windows软件打包路上的得力助手帮你打造出专业、可靠的安装体验。