我说真的,这回为什么会有这个《诺艾尔会努力的_安装包_更新日志》,那完全是被逼的。上个月,我给“诺艾尔”这个小工具搞了个大版本迭代,内容是真不错,但更新方式,那叫一个惨。我以前总觉得,自己写给自己用,或者发给几个熟人测试一下,直接手动覆盖文件就行了,省事。
结果?我这边更新完了,给几个测试的朋友发过去,有一个老哥的机器就彻底崩了。他那台机器比较老旧,依赖环境复杂,文件覆盖顺序不对,直接把配置文件和注册表信息搞乱了。更要命的是,我发给他的文件里,少了一个关键的动态链接库。他一运行,直接报错,环境崩了,连带着他机器上别的软件都出了问题。
我跟他远程调试了快十个小时,一个周末直接报废了。我得一个文件一个文件帮他把旧的删掉,把注册表里错误写入的残留项清理干净,然后小心翼翼地把新文件放进去。为了这事,我差点把键盘砸了。那一瞬间我明白,光代码写得好没用,部署那一关搞不用户体验就是负分。
下定决心:告别手动覆盖,必须搞一个自动安装和更新包!
那天晚上我就想明白了,不能再东拼西凑了。之前那个示例内容里不是说了吗,东拼西凑多了就成大杂烩了。我的“诺艾尔”虽然只是个小东西,但只要部署环境多变,早晚得出事。我要像一个正经的软件那样,有一个能自动检查环境、自动更新配置、并且能优雅卸载的安装程序。
我立马就动了起来。第一件事,就是找一个靠谱的安装包制作工具。我之前用过NSIS,这回为了更精细的脚本控制,我决定尝试Inno Setup。我花了一整天的时间,把那个配置脚本的语法结构彻底捋了一遍,决定从头开始构建一个全新的安装逻辑。
我的实践过程,就是跟各种配置项搏斗的过程:
- 第一步:抓了配置文件清单。 我做的,就是把所有需要部署的文件清单拉出来,一个不漏。特别是那个动态链接库,我把它设成了“关键文件”,如果安装失败,必须明确报错。
- 第二步:琢磨路径逻辑。 然后开始写安装路径的判断逻辑。重点是判断老版本是不是存在。如果存在,不能简单覆盖,得把旧的配置文件备份出来。特别是那个用户自定义的数据库连接串,那是用户的核心数据,千万不能动,必须设为“保留文件”。
- 第三步:跟注册表搏斗。 这是最麻烦的。为了让程序启动时能自动识别一些环境参数,我必须往Windows的注册表里写点东西。我反复试了四五次,才搞明白哪个键值对是必须的,哪个是可选项。我发现如果不小心把软件的图标路径写错,卸载的时候就会残留一个空图标。我专门在脚本里加了一段清理逻辑,确保卸载得干干净净。
- 第四步:搞签名,除警告。 虽然是内部小工具,但Windows动不动就弹警告说“未知发行者”,用户看到就不敢点了。我找了个免费的自签名证书生成工具,把它嵌到安装包里。那个证书的导入导出流程,我折腾了快一天,才让Windows Defender满意,不再弹那烦人的黄色警告框。
核心实现:如何让新版本自动清理旧版本残骸
光能安装不行,得能更新。我给自己定了个规矩:新安装包必须能识别出旧版本是哪个,然后按照预设的脚本逻辑,先安静地卸载旧版本,再安装新的,中间不能让用户感觉到卡顿,也不能让他多点一个按钮。
我通过Inno Setup的自定义脚本函数,狠狠地写了一段判断逻辑。这段逻辑去读系统盘里一个隐藏的日志文件,如果读到了,说明之前安装过。它会对比当前安装包的版本号和已安装的版本号。如果新版本比旧版本高,它就不声不响地启动旧版本的卸载程序,静默执行。这个静默执行的命令参数,我来来回回试了快十个版本,要么弹窗,要么执行失败。我找到了一个非常偏门的组合参数,才让它老老实实地在后台跑起来,真正做到了“无感知更新”。
搞定之后,我把这个新的安装包发给了之前出问题的老哥。他点了一下,五秒钟,好了。什么弹窗都没有,配置也完美保留,启动路径也自动更新了。那一刻,我感觉我周末浪费的十个小时,值了。一个稳定的安装包,比一堆解释如何手动更新的文档强一百倍。
这回的更新日志,主要就是关于这个安装逻辑的优化。 今后每一次版本更新,我都会把安装包的迭代过程也记录下来,这样就算以后“诺艾尔”的代码库换了语言,部署逻辑也不会乱套。
总结一下这回的实践经验:
- 别偷懒,该花时间在部署上就要花,早晚要还。
- 处理注册表和静默安装,才是真正浪费时间的大头,但搞定它,成就感爆棚。
- 以后发布新版本,不光要测功能,还要把安装、更新和卸载的流程都当成核心功能来测!
下次再聊,希望下次“诺艾尔”能带着更多好用的功能和更稳定的安装包跟大家见面。