为方便客户对安装包制作过程中的配置进行更好地理解与应用,我们对nsNiuniuSkin的配置进行如下整理,从手工配置,到全自动集成,做全覆盖的说明与解释!
我们以leeqia_mountain模板为例,介绍一下如何配置与打包:
在正式开始配置之前,有几个点需要先给大家说明一下:
. 7z压缩工具以及python、bat打包脚本
├── FilesToInstall 待打包文件列表放置的目录
├── Helper 打包辅助工具
├── NiuNiuCaptureElectronDemo Electron项目示例(用于演示如何打包Electron程序)
├── NSIS NSIS打包工具相关文件
├── Output 打包完成的文件存放目录
├── SetupScripts 打包核心nsis脚本
│ └── leeqia_mountain nsi文件以及安装卸载图标存放位置
│ ├── LanguageFiles 语言翻译文件
│ └── skin 安装界面配置文件
│ └── images 安装界面需要的图片
└── Sign 签名脚本
不管采用哪种方式打包,必要的UI修改都是要做的,比如图标以及个别界面上的提示信息;我们的UI模板已经尽可能做到简洁与美观,相信您只需要替换部分图标后,完全可以直接作为您产品的安装包界面。
如果对duilib的界面配置不熟悉的话,我们不建议您修改界面的布局,尽量只是按照原尺寸的图片进行替换即可;在SetupScripts\leeqia_mountain\skin目录下,用于存储UI相关的文件:
文件名 | 说明 |
---|---|
install.xml | 这是一个总领脚本,包含标题栏,阴影以及语言选择框 |
configpage.xml | 配置打开安装包后显示的第一个界面,也是用于选择安装路径等的界面 |
licensepage.xml | 配置许可协议显示界面 |
installingpage.xml | 安装过程中的界面 |
finishpage.xml | 安装完成的界面 |
uninstallpage.xml | 卸载入口界面 |
uninstallingpage.xml | 安装过程中的界面 |
uninstallfinishpage.xml | 卸载完成的界面 |
msgBox.xml | 二级弹窗 |
以上xml在文本工具中即可编辑,属性的修改参考duilib_ultimate的属性列表;同时我们提供一个在线预览与调试工具,可以在不重新打包的情况下,预览所有界面效果,将会使您的界面修改效率提升数倍,见如下链接:
http://leeqia.com/articles/nsniuniuskin_designer.html
注:
手工配置打包比较适合于那些产品信息及版本信息不怎么变动的项目打包,比如您有一个产品,安装包上的信息(主要指版本信息)平时并不变更,那么用这种方式配置与打包,是最省时间的。
在soft_setup.nsi文件中,根据您的项目修改如下宏定义:
# ====================== 自定义宏 产品信息==============================
!define /ifndef PRODUCT_NAME "利洽科技截图控件" #产品名称
!define /ifndef PRODUCT_NAME_EN "Leeqia ScreenCapture" #英文产品名称
!define /ifndef PRODUCT_PATHNAME "Leeqia_Capture" #安装与卸载项用到的KEY,与Electron中的guid相同
!define /ifndef INSTALL_APPEND_PATH "Leeqia_Capture" #安装路径追加的名称
!define /ifndef INSTALL_DEFALT_SETUPPATH "$PROGRAMFILES32\${INSTALL_APPEND_PATH}" #默认生成的安装路径
!define /ifndef EXE_NAME "牛牛截图.exe" #主程序EXE文件名
!define /ifndef PRODUCT_VERSION "2.5.0.0" #版本号
!define /ifndef PRODUCT_PUBLISHER "Leeqia" #发布者
!define /ifndef PRODUCT_LEGAL "Leeqia Copyright(c)2020" #版权信息
!define /ifndef INSTALL_MODE_ALL_USERS "all" # all current,是否安装到所有用户,默认为是,会影响注册表、快捷方式、开始菜单等
!define /ifndef INSTALL_EXECUTION_LEVEL "admin" # 如果INSTALL_MODE_ALL_USERS使用current,则此处请同步改成user (RequestExecutionLevel none|user|highest|admin)
!define /ifndef INSTALL_OUTPUT_NAME "Test_PC_Setup_v2.5.0.exe" #默认的安装包名称,在bat中控制传入
!define /ifndef INSTALL_LOCATION_KEY "InstPath" #默认的注册表中安装位置的key值
# ====================== 以下宏用于控制特定的行为 ==============================
!define /ifndef INSTALL_DEFAULT_AUTORUN 0 #默认是否自动开机启动
!define /ifndef INSTALL_DEFAULT_SHOTCUT 0 #默认是否添加快捷方式
!define /ifndef TEST_SLEEP 1 #测试安装过程中的延时开关,方便查看进度变化和轮播图,实际使用,请改成0
!define /ifndef INSTALL_DOWNLOAD_BASEURL "http://www.ggniu.cn/test_online_install/"
# ====================== 上述具体的宏定义均可以在pre_define.nsh文件中预先定义,可任意指定为其他的值 ==============================
在leeqia_mountain目录下,有根据语言ID命令的rtf文档,您相应的修改其内容即可,如果有新的语言的许可协议文件,也请进行新增。
将要安装的文件复制到FilsToInstall目录下;打包脚本将会对这个目录下(包含多级子目录)进行压缩打包。 这个步骤一般是在测试阶段使用,实际打包过程中一般是通过脚本自动化复制。
双击指定的bat,即可完成打包:
文件名 | 说明 |
---|---|
build-leeqia_mountain.bat | 会先将文件压缩成7z.app,再进行打包 |
build-leeqia_mountain-nozip.bat | 直接打包文件 |
build-leeqia_mountain-online.bat | 打包在线安装包,同时生成在线数据包文件和配置 |
看了上述的过程,有没有觉得打包真的很简单呢,仅仅需要五步,就能实现一个属于您的安装啦!
为了能够更加方便地集成进既有的打包流程中,我们专门用python开发了一套命令行的接口,您不再需要去修改soft_setup.nsi文件中的宏定义,而只需要通过我们package.py的命令行参数来进行控制即可。
之所以能够如此设置,在于NSIS的宏定义支持 /ifndef属性,表示如果在此之前未定义才定义,而我们在soft_setup.nsi文件的顶部,优先引入一个叫pre_define.nsh文件,如果在pre_define.nsh中已经定义的宏,那么他将优先使用。
事实上NSIS自身也支持命令行来传入宏定义,在这个情况下,一个宏有效的优先级为:
NSIS命令行 > pre_define.nsh > soft_setup.nsi
有了这个前提,我们在package.py中,将接受到的命令行参数,转换成NSIS的宏定义,写入到pre_define.nsh文件中,以此方式来实现打包时配置信息的参数化。
package.py具体参数较多,如下:
optional arguments:
-h, --help show this help message and exit
--log_dir LOG_DIR if None, log will be written to console
--project_name PROJECT_NAME the project name, eg: leeqia_moutain
--package_mode PACKAGE_MODE the package mode, 0:7z, 1:nozip, 2: online
--need_sign NEED_SIGN check if sign uninstall and setup file
--build_for_electron BUILD_FOR_ELECTRON check if build for electron, if True, we will call npm build in scripts
--electron_build_path ELECTRON_BUILD_PATH electron build path, the dir path of package.json
--generate_latest_file GENERATE_LATEST_FILE check if generate latest.yml for electron-updater
--files_toinstall_name FILES_TOINSTALL_NAME local directory name for nsNiuniuSkin, FilesToInstall default
--auto_write_uninst AUTO_WRITE_UNINST check if generate uninstall automatically, default False
--uninst_file_name UNINST_FILE_NAME the uninstall file name
--src_files_dir SRC_FILES_DIR the unpacked file path, if specified, we will copy the files to [files_toinstall_name] and package them
--PRODUCT_NAME PRODUCT_NAME setup file name, if None, we will use the definition in soft_setup.nsi
--PRODUCT_NAME_EN PRODUCT_NAME_EN setup file name, if None, we will use the definition in soft_setup.nsi
--INSTALL_OUTPUT_NAME INSTALL_OUTPUT_NAME setup file name, if None, we will use the definition in soft_setup.nsi
--PRODUCT_VERSION PRODUCT_VERSION the package version, if None, we will use the definition in soft_setup.nsi
--EXE_NAME EXE_NAME the main exe name, if None, we will use the definition in soft_setup.nsi
--INSTALL_LOCATION_KEY INSTALL_LOCATION_KEY the install localtion key, if None, we will use the definition in soft_setup.nsi
--INSTALL_APPEND_PATH INSTALL_APPEND_PATH the append path when install, if None, we will use the definition in soft_setup.nsi
--PRODUCT_PATHNAME PRODUCT_PATHNAME the identity in reg, if None, we will use the definition in soft_setup.nsi
--INSTALL_DEFALT_SETUPPATH INSTALL_DEFALT_SETUPPATH the default setup path, if None, we will use the definition in soft_setup.nsi
--TEST_SLEEP TEST_SLEEP if True, it will sleep when extract the files, if None, we will use the definition in soft_setup.nsi
--INSTALL_DEFAULT_SHOTCUT INSTALL_DEFAULT_SHOTCUT check if add shortcut for default, if None, we will use the definition in soft_setup.nsi
--INSTALL_DEFAULT_AUTORUN INSTALL_DEFAULT_AUTORUN check if add auto run for default, if None, we will use the definition in soft_setup.nsi
--INSTALL_EXECUTION_LEVEL INSTALL_EXECUTION_LEVEL execution level(admin/user), if None, we will use the definition in soft_setup.nsi
--INSTALL_MODE_ALL_USERS INSTALL_MODE_ALL_USERS install mode(all/current), if None, we will use the definition in soft_setup.nsi
--INSTALL_DOWNLOAD_BASEURL INSTALL_DOWNLOAD_BASEURL download base url for online install, if None, we will use the definition in soft_setup.nsi
--PRODUCT_LEGAL PRODUCT_LEGAL product legal, if None, we will use the definition in soft_setup.nsi
--PRODUCT_PUBLISHER PRODUCT_PUBLISHER publisher info, if None, we will use the definition in soft_setup.nsi
具体每个参数解释如下:
参数名称 | 参数类型 | 参数用途 | 备注 |
---|---|---|---|
--log_dir | str | 指定日志写入路径 | 如果不指定,则打印到控制台 |
--project_name | str | 打包的项目名称 |
对应于您使用的模板名称,比如高山版本为:leeqia_moutian * 必填项 |
--package_mode | int | 打包模式 |
用于指定使用哪种方式打包:1: 采用7z解压模式2: 采用非7z模式3: 打在线安装包 * 必填项 |
--need_sign | bool | 是否要对卸载程序和安装程序进行签名 | 默认为False,如果指定为True,还需要配置代码签名 |
--build_for_electron | bool | 是否是打包electron程序 | 默认为False |
--electron_build_path | str | electron程序打包的目录 | 如果build_for_electron为True,则此值必需指定 |
--generate_latest_file | bool | 是否生成匹配给electron-updater使用的latest.yml | 默认为False |
--files_toinstall_name | str | nsNiuniuSkin本地打包目录名称 | 默认为FilesToInstall,可不指定 |
--auto_write_uninst | bool | 是否在安装时自动生成卸载程序 | 默认为False,这种方式生成的卸载程序无法签名,建议不指定 |
--uninst_file_name | str | 卸载程序的文件名 | 默认为uninst.exe |
--src_files_dir | str | 要打包的源目录 |
如果指定,则在打包时我们会将此目录下的文件复制到我们的本地打包目录下, 再进行打包uild_for_electron为True时,此值无效 |
--PRODUCT_NAME | str | 打包的产品名称 | 中文模式下的快捷方式,开始菜单,安装界面呈现等均使用此值 |
--PRODUCT_NAME_EN | str | 打包的英文产品名称 |
英文模式下的快捷方式,开始菜单,安装界面呈现等均使用此值注意, 如果新增加语言,需要自行扩展package.py的参数,或者在soft_setup.nsi中设置好 |
--INSTALL_OUTPUT_NAME | str | 打出来的安装包名称 | 当build_fore_electron为False时,此参数必需指定,签名时也会用到 |
--PRODUCT_VERSION | str | 产品版本号 | 版本号 |
--EXE_NAME | str | 待安装的主程序名称 | 快捷方式,开始菜单等地方用到 |
--INSTALL_LOCATION_KEY | str | 安装路径的注册表保存key | 用于找到软件之前的安装目录,默认为InstPath,Electron程序请指定为InstallLocation |
--PRODUCT_PATHNAME | str | 软件安装标识在注册表中的保存key | 用于软件与卸载信息的保存 |
--INSTALL_APPEND_PATH | str | 安装时追加的目录名 | |
--INSTALL_DEFALT_SETUPPATH | str | 软件默认安装路径 | |
--TEST_SLEEP | int | 是否在解压过程中增加延迟 | 默认为0,表示不增加延迟,1表示增加 |
--INSTALL_DEFAULT_SHOTCUT | int | 默认是否开启添加快捷方式 | 默认为0,表示不开启 |
--INSTALL_DEFAULT_AUTORUN | int | 默认是否启用开机启动 | 默认为0,表示不开启 |
--INSTALL_EXECUTION_LEVEL | str | 安装包权限 | none/user/highest/admin 默认为admin |
--INSTALL_MODE_ALL_USERS | str | 安装包所有用户还是当前用 | all/current,此参数与上一个参数应用有关联性,请关注 |
--INSTALL_DOWNLOAD_BASEURL | str | 在线安装包的数据包下载基地址 | 如果打在线安装包,此值必需指定 |
--PRODUCT_LEGAL | str | 版本信息 | 例如:Leeqia Copyright(c)2020 |
--PRODUCT_PUBLISHER | str | 发布者信息 | 例如:公司名 |
比如,想打包一个程序,想指定的信息如下:
那么打包的命令行参数为:
python package.py --package_mode=1 --project_name=leeqia_mountain --PRODUCT_NAME=测试软件 --PRODUCT_VERSION=0.5.0 --EXE_NAME=Test.exe --INSTALL_OUTPUT_NAME=Test_Setup.exe --src_files_dir=C:\unpacked_files
如果还有更多的参数要指定,则追加即可。
看完这一节,相信您也一定发现了,第一节中的手工配置的soft_setup.nsi文件的步骤完全可以舍弃,可以直接采用这种命令行的方式来打包。 哪怕信息是相对固定的,也可以将这个命令行参数用bat文件保存起来。
注:
利用python.py的命令行脚本,需要在打包的环境中安装了python3
对于Electron程序的打包,我们支持打包的同时生成与electron-updater兼容的latest.yml,以支持Electron程序的自动升级。
在对Electron程序打包前,我们需要考虑如下几个问题,并根据结论形成正确的配置:
当前程序是首次发布还是延续之前electron-builder打出来的程序继续发布
打包入口问题
a) 如果是electron-builder作为打包入口,那么您只需要通过命令行,传递准确的信息,同时指定build_for_electron为False即可,因为这种模式对于我们nsNiuniuSkin来讲,和打包其他方式一样(这是我们建议的方式)
b) 如果您希望打包的入口在我们的 package.py,那么需要传递build_for_electron为True,同时把项目路径传递过来,我们将会尝试读取项目路径下package.json中的版本号,软件名称,guid等信息,然后在项目路径下执行npm build run指令,最终打包成完整的安装包(如果您的打包的配置或方式与我们默认集成的有所不同,那么需要您修改package_util.py中的build_for_electron函数的实现)。
还需要考虑要如何配置如下参数:
功能项 | 配置参数名 | 建议(尽可能与原安装包配置一致) |
---|---|---|
是否安装到所有用户 | --INSTALL_MODE_ALL_USERS | 建议安装到所有用户,传all,同时也要考虑旧的electron程序的权限 |
是否以管理员权限启动 | --INSTALL_EXECUTION_LEVEL | 建议以管理员权限启动,传admin,同时也要考虑旧的electron程序的权限 |
软件安装标识 | --PRODUCT_PATHNAME | 根据electron-builder中配置的guid来传 |
安装路径在注册表中的key | --INSTALL_LOCATION_KEY | 传InstallLocaltion |
是否生成latest.yml | --generate_latest_file | 传True |
根据以往客户用于打包Electron程序时遇到过的问题,容易出错的地方如下,希望对您有帮助:
问题 | 原因 | 解决办法 |
---|---|---|
在package.json中没有guid,导致读取不到 |
这个guid是安装包在注册表中的软件标识,每一个安装包都需要有一个独特的值 ,在有些项目中,打包的配置并不是全写在package.json中的,甚至有些就是没有设置这个guid属性, 这导致转成nsNiuniuSkin打包时,读取不到它,就无法正确的写入注册表。 |
在这种情况下,一般按如下方式解决: a) 如果有设置,只是没在package.json中设置,那么直接从命令行参数中传递给我们即可 b) 如果electron-builder中没指定,并不知道原来的key是什么 这时候就需要使用7zip,解压electron-builder生成的安装包,在其nsi脚本中找到这个值,并且通过命令行传递给我们 当然,这种一般是指在使用nsNiuniuSkin打包前已经发布了安装包的,需要让新的安装包的各种配置与旧的一致时才使用,否则直接传递一个您认为唯一且正确的值即可。 |
打包出来的安装包比electron-builder打出来的安装包要大 | 这种一般是指定的package_mode未正确指定的问题 | 将package_mode指定为1即可 |
打出来的安装包不能识别electron-builder打出来安装包安装过的路径 |
a) 当前用户与所有用户的配置不一致 在electron-builder的配置中,一般会有是否是安装到perMachine的配置,这个配置表示安装到所有用户下; 而nsNiuniuSkin中的默认配置是在所有用户下,如果这两个配置不匹配,那么将读取不到。 b) 注册表中安装位置的key值不一致 nsNiuniuSkin在注册表中默认的安装位置的key是InstPath,而electron-builder打包出来的程序,使用的是InstallLocation c) 注册表中软件标识不一致 nsNiuniuSkin安装包的注册表key与electron-builder打出来的不一致 |
配置正确的值即可 |
打包完成后,发现生成的latest.yml中的大小与sha512值与实际的安装文件不匹配 | 在打包流程生成latest.yml后,安装包文件又被变更了 |
在我们的打包流程中,我们的最后一步是生成latest.yml,意味着在这之后对安装包的所有变更(比如代码签名),都将导致latest.yml中的信息变的不再正确。 建议您将证书配置到我们的打包流程中,这样将能有效的解决这个问题,同时还能对卸载程序进行签名,有效的防止误报; 或者您额外对安装包进行签名后,需要重新根据签名后的文件再生成一次latest.yml。 |
我们已经将完整的安装功能均写到了setup_control.nsh脚本中,正常来讲,您不需要修改这里的脚本,setup_control.nsh文件中的一些关键函数如下:
函数名 | 主要功能说明 |
---|---|
DUIPage | 安装入口脚本,用于初始化一些信息 |
un.DUIPage | 卸载入口脚本 |
BindUIControls | 绑定按钮及其他响应事件 |
ShowMsgBox | 显示二级子窗口 |
OnBtnInstall | 安装主流程控制 |
CustomizeInstall | 更多的自定义安装行为 |
如果是在安装过程中有一些额外的功能要加,可以在setup_control.nsh中的CustomizeInstall函数下进行扩展,比如安装.netframework等;这个函数将会运行在BGWorker下,您不用担心会导致安装界面卡住。
代码签名对于软件的分发以及防误报来说有重要作用,我们在Sign目录下,已经放了签名的基础脚本等信息,您只需要替换signfile.bat中的几个关键信息,同时将证书和证书密码等信息,然后在打包时指定need_sign为True即可。
注:
1)如果您的签名证书默认不是按我们这种方式签名的,那么您需要自行修改Sign.bat,保证不破坏他的参数接收的情况下,能够最终完成签名即可。
希望这篇配置说明能够帮助您快速的配置好属于您项目专属的打包脚本,核心在于对package.py的命令行参数和NSIS对宏定义的设置顺序的理解。
在安装包安装过程中,精美的UI往往能让客户对所安装产品的印象更加深刻,更能体现出软件服务商在用户体验上的专注与用心! 希望我们的努力,能够让安装包制作再容易一点,再快乐一点!
愿天下没有难做的安装包!