安装包UI美化之路-通过nsNiuniuSkin来做Electron程序的打包、发布与升级
nsNiuniuSkin从发布之初,因其简单、简洁、高效,受到了非常多公司的青睐,现在已经越来越多的公司采用我们的这套解决方案来制作安装包了!
从一个安装包UI插件,逐步演化成一套集美观、安全、简洁、自动化为一体的完整的解决方案,实属不易,感谢所有朋友的信任!
前言
网上有不少关于Electron安装包美化的文章,有使用sciter的,有使用QT的,也有基于我们早期版本进行深度或简单集成的;整体看下来,这些方案多少会有一点问题:
- 使用sciter和QT,增加了不少体积
- 没有完整的与Electron打包升级完整整合
而现在Electron应用非常广泛,Electron应用程序的安装包制作,当然少不了我们;在翻看了electron-builder和electron-updater源码后,再结合反解Electron应用程序的安装包脚本,我们了解了其运作的机制,实现了一套与Electron打包无缝对接的方案,完全支持自动化,兼容electron程序的升级。
之前有了解到有一个朋友做Electron安装包的美化,前后花费了一个月时间的,真的让人痛心!希望有了我们的方案,大家能够在一天内完成安装包的制作以及升级功能的对接。
原理
在实际介绍nsNiuniuSkin的Electron安装包制作方案之前,我们需要讲清楚几个原理:
electron-builder在Windows上默认使用NSIS进行打包
electron-builder内置了很多模板化的nsis脚本,在package.json中的关于nsis的设置,将会通过参数的形式,结合模板,最终形成完整的打包脚本,进而生成安装包。 如果你有想不明白的打包与升级的问题,基本都可以在electron-builder的源码中找到相关的答案或者资料。
electron-updater的升级思路
此处我们只讲全量更新,electron-updater升级流程如下:
- 在electron-builder打包时,通过配置,会在resources目录下生成一个app-update.yml配置文件,其中包含了当前的版本号,以及升级检测的服务端地址;同时会生成一个elevate.exe的程序(用于在升级包需要管理员权限运行时进行提权)
- electron-builder打包完成后,会同步生成一个叫latest.yml文件,其中写了最新的版本号、大小、文件的SHA512哈希值等信息;这些信息将作为客户端升级校验的基础(打包后需要将latest.yml以及安装包放到指定的服务器上)
- 客户端运行时,electron-updater下载服务器的latest.yml,与本地的进行对比,判断是否有新版本
- 下载latest.yml中安装包文件名对应的文件,并校验其SHA512与大小是否与配置文件中一致
- 退出当前主进程,调用新的安装包,并传递--updated --force-run /S等参数(--force-run /S根据updater配置逐项增加)
我们的实现方案
知道了Electron打包与升级的逻辑,我们的Electron打包方案就变的容易了,处理细节较多,这里我们主要介绍几个技术要点:
- 自动读取Electron目录下的package.json中的版本号以及guid,这两个信息对于安装包非常重要
- 支持从外部指定安装包名、安装权限、安装到当前用户还是所有用户等
- 调用Electron打包命令,生成unpacked files,并复制到我们的打包目录下
- 安装包打包完成后,自动签名,同时生成latest.yml配置文件,达到完全兼容electron-updater升级的效果
- 自动处理electron-updater传递过来的命令行参数,将升级行为处理成与原生的electron打包的安装包一致
我们的优势
有人会说Electron自己的打包就是这样,你做的这些有什么意义呢?
意义非常大,且听我道来:
- 我们的安装包UI高度美观,且可以随意扩展
- 我们的安装包自带防解包功能,安全性上比Electron自己打出来的更高
- 我们的安装包方案中,自带一键生成在线安装包,网站上可以只发布非常小的一个预安装程序即可
- 我们除了生成与electron-updater完全匹配的升级包以外,同时支持更灵活的升级方案
- 一键式打包,同步生成卸载程序及其签名,防误报
打包示例与效果展示
说了这么多,都是理论性的东西,直接看脚本和效果吧,不需要复杂的配置,直接执行打包脚本即可。
package.json脚本
在打包脚本目录下,我们提供了一份名叫NiuNiuCaptureElectronDemo的electron源码,其中已经包含了基本的打包脚本package.json的配置,以及基本的升级相关的代码。
package.json的部分配置如下:
{"name": "TestCapture","version": "1.0.0","main": "main.js","description": "","author": "support@leeqia.com","build": {"appId": "appid","nsis": {"guid": "Test_Capture"  },"extraFiles": ["capture"],"win": {"target": "dir","icon": "app.ico"},"publish": [{"provider": "generic","url": "http://127.0.0.1:8080/upload/"}]}
}
上述打包脚本配置,表示我们的一些核心配置如下:
- 版本号为1.0.0
- 安装包在注册表中的标识key为Test_Capture
- 指定升级包下载路径等
- 我们依赖的electron和electron-builder的版本如上,如果你机器上的版本不一样,请相应调整
build-for-electron.bat脚本
同时我们提供了一份build-for-electron.bat的脚本,默认已经配置成正常打包NiuNiuCaptureElectronDemo下的应用程序;脚本部分代码如下(实际应用中只需要修改大概4-5个字段,output_setup_prefix、electron_build_path、shell_all_user_mode、install_execution_level):
@rem 打包脚本项目名称
@set project_name=leeqia_general
@rem 安装包名前缀 
@set output_setup_prefix=LeeqiaCapture_PC_Setup_@rem 主程序名称 (可根据你的项目自行调整)
@set main_exe_name=TestCapture.exe@rem electron程序中打包的guid,用于安装在注册表中的key(卸载与软件信息)
@set electron_guid=
@rem 软件版本号
@set electron_app_version=
@rem 是安装到所有用户下,还是安装到当前用户下,all/current
@set shell_all_user_mode=all
@rem 安装包的启动权限,user/admin
@set install_execution_level=admin
@rem electron项目所在目录
@set electron_build_path=.\NiuNiuCaptureElectronDemo
@set electron_unpacked_dir=%electron_build_path%\dist\win-unpacked
@rem 读取yml文件,提取版本号和guid信息
.\Helper\NSISHelper.exe --mode="get_electron_app_info" --src="%electron_build_path%\package.json" --dst=".\get_electron_app_version.bat"
Call get_electron_app_version.bat
@echo %electron_app_version%
@echo %electron_guid%
@rem 完整的安装包名称
@set output_setup_file_name=%output_setup_prefix%%electron_app_version%.exe
@rem 打包,生成unpacked files (如果你的打包脚本是其他的,则修改此处,在具体环境中打包可能报错,需要调整package.json中的electron和electron-builder的版本号)
cd %electron_build_path%
call npm run build
执行build-for-electron.bat,就可以开始打包了,他将会做几件事:
- 提取package.json中的guid和version字段,传递给后续的打包流程
- 进入electron应用程序所在目录下,执行打包脚本npm run build
- 复制dis\win-unpacked下的文件
- 执行安装包打包(包含卸载程序、安装程序的打包与签名)
- 生成最终安装包的latest.yml
以下是我们的打包脚本执行过程:

打包完成后,最终打包出来的安装包程序:

安装效果如下:
开始安装:

安装中:

升级效果展示
在上一节中,我们已经打出来了1.0.0版本的安装包LeeqiaCapture_PC_Setup_1.0.0.exe,并且已经安装到电脑上进行使用;接下来我们演示一下打出新的版本,放到升级目录下,触发旧版本的升级。
我们先需要搭建一个简单的静态http服务器,安装http-server模块即可。
安装后,我们新建立目录e:\testweb\update,然后在e:\testweb目录下下执行: http-server 此时升级服务器就算是准备好了。
我们将package.json中的version字段改为1.0.1,并再次执行build-for-electron.bat进行打包,此时我们会得到两个文件:
- LeeqiaCapture_PC_Setup_1.0.1.exe
- latest.yml
我们将打好的安装包和升级文件复制到e:\testweb\update目录下,然后运行之前安装好的1.0.0版本的测试程序:

此时将会弹出检测到新版本的安装包,是否进行升级的提示,点击确认,升级就开始了,升级完成后,会自动再次拉起主程序来。

与旧的Electron应用程序的兼容
如果之前已经通过electron打包发布了的程序,替换成由nsNiuniuSkin打的安装包,要如何与旧的版本完全兼容呢?
这是非常重要的一点,也是众多Electron开发者在切换安装包打包工具时的困惑所在。
我们之所以要读取package.json中的guid,就是想要实现与旧版本兼容。只要知道了它,我们就能够在脚本中定位原来旧的Electron安装包的安装位置,可以进一步进行覆盖安装。
当然要处理的细节还是比较多的,比如:
- 安装路径的读取与写入 安装位置,我们使用的key值是InstPath,而Electron使用的key值是InstallLocation;我们在接下来会介绍的build-by-external.bat(build-for-electron.bat也是调用这个脚本)中,预留了可以设置此值的参数,并且指定为InstallLocation,所以Electron程序打包默认都会指定这个值,也就与旧版本匹配了。
- 快捷方式的替换 快捷方式比较简单,只要前后的快捷方式名称一致,且与旧版本安装包的安装配置(是安装到所有用户还是当前用户)一致即可
- 开始菜单的处理 与快捷方式同理
不光如此,类似的其他方案制作的安装包,要无缝的切换成我们的安装包方案,也是很简单的:
我们在脚本中内置了注册表key的默认值,只需要将其修改成您旧的程序写的key即可确保读写用的是同一个键值。
灵活的集成方案,兼顾不同的打包方式与场景
在我们的打包方案中,我们提供了两种形式的打包脚本,同时兼顾不同场景的打包需求:
主动打包
之所以称之为主动打包,是因为打包的触发入口是在我们的打包入口脚本中,我们提供了一个叫build-for-electron.bat脚本,在其中只要配置好以下几点,就可以开始打包了(上面的示例已经介绍):
- electron应用程序所在的目录
- electron应用程序主程序的文件名
- electron应用程序的安装包名前缀等
被动打包
被动打包的意思是说打包的触发点不在我们这边,而是有其他流程已经打出来了unpacked files,并且已经复制到了我们要打包的目录下,需要调用我们的脚本打包成最终的安装包,同时生成latest.yml文件。 如果当前已经有了较为完整的打包自动化流程,只是想切换到nsNiuniuSkin的打包方案中,可以试着在你们的流程中调用build-by-external.bat脚本,并传递指定的参数即可,脚本参数较多,如下:
Call build-by-external.bat project_name electron_guid electron_app_version output_setup_file_name shell_all_user_mode install_execution_level file_pack_path main_exe_name gen_latest
脚本部分代码如下(命令行参数每个参数的解释都在脚本代码中了):
@rem 此脚本表示外部已经打好electron的unpacked files,并且已经复制到我们的FilesToInstall下,我们只需要相应的打包成最终的安装包即可 
@rem 打包脚本名称,如leeqia_simple,对于于SetupScripts目录下的具体文件夹名称
@set project_name=%1
@rem electron中配置的guid,用于指定注册表中的key
@set electron_guid=%2
@rem 软件版本号
@set electron_app_version=%3
@rem 完整的安装包名
@set output_setup_file_name=%4
@rem 是安装到所有用户下,还是安装到当前用户下,all/current
@set shell_all_user_mode=%5
@rem 安装包的启动权限,user/admin
@set install_execution_level=%6
@rem 等待打包文件所在目录名,默认为FilesToInstall
@set file_pack_path=%7
@rem 主程序EXE名称
@set main_exe_name=%8
@rem 是否生成latest.yml,用于electron相关程序的打包 
@set gen_latest=%9
@rem 注册表中安装包位置存储的key值
@set install_location_key=InstallLocation
总结
看完上述的介绍与演示,是不是觉得非常简单呢? 所有复杂的逻辑以及需要与electron-updater交互的地方,都由我们安装包制作方案自动完成,提供出统一的接口。
整个过程非常简单,配置build-for-electron.bat中的各个参数(如果你的electron-builder的配置文件还没配置好,也需要配置下),然后执行此脚本,安装包就打包好了。
你对Electron应用的安装包美化和升级还有什么疑惑么?有机会一起探讨一下吧。
结语
在安装包安装过程中,精美的UI往往能让客户对所安装产品的印象更加深刻,更能体现出软件服务商在用户体验上的专注与用心! 希望我们的努力,能够让安装包制作再容易一点,再快乐一点!今后Electron程序的打包,就交给我们吧!^_^
愿天下没有难做的安装包!
相关文章:
 
安装包UI美化之路-通过nsNiuniuSkin来做Electron程序的打包、发布与升级
nsNiuniuSkin从发布之初,因其简单、简洁、高效,受到了非常多公司的青睐,现在已经越来越多的公司采用我们的这套解决方案来制作安装包了! 从一个安装包UI插件,逐步演化成一套集美观、安全、简洁、自动化为一体的完整的…...
 
飞鹅打印机怎么样?飞鹅打印机好用吗?飞鹅打印机怎么知道订单是否漏单?
外卖打印机怎么选?飞鹅打印机好用吗?飞鹅智能云打印机产品专注于云打印的解决方案和技术服务提供。2019 年飞鹅已经成为国内先进的云打印服务提供商,主要是服务美团、饿了么客户,产品主要优势:自动接单、自动打印,无需…...
 
网络协议(八):传输层-TCP(三次握手、四次挥手原理)
网络协议系列文章 网络协议(一):基本概念、计算机之间的连接方式 网络协议(二):MAC地址、IP地址、子网掩码、子网和超网 网络协议(三):路由器原理及数据包传输过程 网络协议(四):网络分类、ISP、上网方式、公网私网、NAT 网络…...
 
最新OpenMVG编译安装与逐命令运行增量式和全局式SfM教程
openmvg是一个轻便的可以逐步运行的SfM开源库,它同时实现了增量式和全局式两种算法。 说明文档地址:https://openmvg.readthedocs.io/en/latest/ github主页地址:https://github.com/openMVG/openMVG 1 编译安装 openmvg的安装比较简单&…...
 
数据结构与算法系列之插入排序
💗 💗 博客:小怡同学 💗 💗 个人简介:编程小萌新 💗 💗 如果博客对大家有用的话,请点赞关注再收藏 🌞 什么是插入排序 有一个已经有序的数据序列,要求在这个已经排好的数…...
 
Text to image论文精读ALR-GAN:文本到图像合成的自适应布局优化
ALR-GAN是北京工业大学学者提出的一种自适应布局优化生成对抗网络,其可以在没有任何辅助信息的情况下自适应地优化合成图像的布局。 文章发表于2023年,IEEE Transactions on Multimedia(TMM)期刊(CCF B,JCR…...
 
windows版 redis在同一局域网下互联
项目场景: 同一局域网下各个主机互相连接同一个redis 问题描述 无法连接 原因分析: 没有放行对方的地址 解决方案: 修改配置文件 最重要的一步如下 然后把 redis.windows.conf的文件也照上面的修改一下保持一致 然后安装一下redis服务这…...
Near-Optimal Bayesian Online Assortment of Reusable Resources
摘要 受租赁服务在电子商务中的应用的激励,我们考虑为不同类型的到达消费者提供可重复使用资源的在线分类的收入最大化。我们针对贝叶斯环境中的最优在线策略设计了具有竞争力的在线算法,其中类型随时间独立于已知的异构分布绘制。在初始库存最小值cmin…...
数据库复习2
一. 简答题(共1题,100分) 1. (简答题) 存在数据库test,数据库中有如下表: 1.学生表 Student(Sno,Sname,Sage,Ssex) --Sno 学号,Sname 学生姓名,Sage 出生年月,Ssex 学生性别 主键Sno 2.教师表 Teacher(Tno,Tname) --T…...
 
公众号运营之竞品分析,教你拆解公众号
知己知彼,百战不殆,公众号运营亦是如此。 当运营者只关注自己账号的时候,很容易陷入某个误区中出不来。这个时候就要拓宽我们的视野,多去看看“外面的世界”,不要只局限于自己的一片小天地中。 看看同领域优秀公众号…...
 
python常见问题详解
Python python 没有多态,而是鸭子类型 多继承,没有接口,可通过语法糖实现接口的作用 lambda中只能有一句 "/"表示之前的参数是必须是位置参数,”**“表示是后面的必须是关键字参数 Python多进程 Python 多线程是伪多线…...
 
MyBatis-常用SQL操作
一、动态SQL 1.概述】 1.1动态SQL: 是 MyBatis 的强大特性之一,解决拼接动态SQL时候的难题,提高开发效 1.2分类: if choose(when,otherwise) trim(where,set) foreach 2.if 2.1 做 where 语句后面条件查询的,if 语句是可以…...
 
DSPE-PEG-TCO;磷脂-聚乙二醇-反式环辛烯科研用化学试剂简介
中文名称 磷脂-聚乙二醇-反式环辛烯 英文名称 DSPE-PEG-TCO 外观:粉末或半固体,取决于分子量。 溶剂:溶于大部分有机溶剂,如:DCM、DMF、DMSO、THF等等。在水中有很好的溶解性 稳定性:冷藏保存ÿ…...
华为OD机试真题Java实现【最小施肥机能效】真题+解题思路+代码(20222023)
最小施肥机能效 某农场主管理了一大片果园,fields[i]表示不同果林的面积,单位:( m 2 m^2 m2),现在要为所有的果林施肥且必须在 n 天之内完成,否则影响收成。 小布是果林的工作人员,他每次选择一片果林进行施肥,且一片果林施肥完后当天不再进行施肥作业。 假设施肥机的…...
【问题记录】【排查问题的方法总结】vue3中数据失去响应式?为什么数据变了,视图只更新了一次就不再更新了?
一、问题概述: 持续请求的数据变动之后,控制台输出绑定的响应式变量 mapObj 的确变了,但是视图上只更新了一次,后续就不再更新了。 二、排查过程: PC上用定时器setInterval模拟数据(全是小于0的数据)更新࿰…...
 
基于遗传算法的柔性生产调度研究(Matlab代码实现)
👨🎓个人主页:研学社的博客💥💥💞💞欢迎来到本博客❤️❤️💥💥🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密…...
Heroku的12条准则
I. Codebase One codebase tracked in revision control, many deploys 要有代码仓库,多版本控制,如使用git来管理代码仓库。 II. Dependencies Explicitly declare and isolate dependencies 明确声明依赖,隔离依赖。强依赖往往会导致连…...
 
Qt图片定时滚动
目录参考结构PicturePlay.promain.cpppictureplay.hpictureplay.cpppictureplay.ui效果参考 Qt图片浏览器 QT制作一个图片播放器 Qt中自适应的labelpixmap充满窗口后,无法缩小只能放大 可以显示jpg、jpeg、png、bmp。可以从电脑上拖动图到窗口并显示出来或者打开文件…...
 
深度学习引言
动手学深度学习pytorch版-笔记原文链接日常生活中的机器学习机器学习中的关键组件数据模型目标函数优化算法各种机器学习问题监督学习回归分类标记问题搜索推荐系统序列学习无监督学习与环境互动强化学习特点小结原文链接 动手学深度学习pytorch中文版 日常生活中的机器学习 …...
ESP32 WIFI使用介绍
ESP32 WIFI 概述 WIFI 库支持配置及监控 ESP32 WIFI 连网功能。支持配置 station 模式(即 STA 模式或 WIFI 客户端模式),此时 ESP32 连接到接入点(AP)。AP 模式(即 soft-AP 模式或接入点模式)&…...
 
龙虎榜——20250610
上证指数放量收阴线,个股多数下跌,盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型,指数短线有调整的需求,大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的:御银股份、雄帝科技 驱动…...
设计模式和设计原则回顾
设计模式和设计原则回顾 23种设计模式是设计原则的完美体现,设计原则设计原则是设计模式的理论基石, 设计模式 在经典的设计模式分类中(如《设计模式:可复用面向对象软件的基础》一书中),总共有23种设计模式,分为三大类: 一、创建型模式(5种) 1. 单例模式(Sing…...
ES6从入门到精通:前言
ES6简介 ES6(ECMAScript 2015)是JavaScript语言的重大更新,引入了许多新特性,包括语法糖、新数据类型、模块化支持等,显著提升了开发效率和代码可维护性。 核心知识点概览 变量声明 let 和 const 取代 var…...
 
CocosCreator 之 JavaScript/TypeScript和Java的相互交互
引擎版本: 3.8.1 语言: JavaScript/TypeScript、C、Java 环境:Window 参考:Java原生反射机制 您好,我是鹤九日! 回顾 在上篇文章中:CocosCreator Android项目接入UnityAds 广告SDK。 我们简单讲…...
Spring Boot+Neo4j知识图谱实战:3步搭建智能关系网络!
一、引言 在数据驱动的背景下,知识图谱凭借其高效的信息组织能力,正逐步成为各行业应用的关键技术。本文聚焦 Spring Boot与Neo4j图数据库的技术结合,探讨知识图谱开发的实现细节,帮助读者掌握该技术栈在实际项目中的落地方法。 …...
 
(转)什么是DockerCompose?它有什么作用?
一、什么是DockerCompose? DockerCompose可以基于Compose文件帮我们快速的部署分布式应用,而无需手动一个个创建和运行容器。 Compose文件是一个文本文件,通过指令定义集群中的每个容器如何运行。 DockerCompose就是把DockerFile转换成指令去运行。 …...
 
HubSpot推出与ChatGPT的深度集成引发兴奋与担忧
上周三,HubSpot宣布已构建与ChatGPT的深度集成,这一消息在HubSpot用户和营销技术观察者中引发了极大的兴奋,但同时也存在一些关于数据安全的担忧。 许多网络声音声称,这对SaaS应用程序和人工智能而言是一场范式转变。 但向任何技…...
离线语音识别方案分析
随着人工智能技术的不断发展,语音识别技术也得到了广泛的应用,从智能家居到车载系统,语音识别正在改变我们与设备的交互方式。尤其是离线语音识别,由于其在没有网络连接的情况下仍然能提供稳定、准确的语音处理能力,广…...
 
Java数组Arrays操作全攻略
Arrays类的概述 Java中的Arrays类位于java.util包中,提供了一系列静态方法用于操作数组(如排序、搜索、填充、比较等)。这些方法适用于基本类型数组和对象数组。 常用成员方法及代码示例 排序(sort) 对数组进行升序…...
 
Mac flutter环境搭建
一、下载flutter sdk 制作 Android 应用 | Flutter 中文文档 - Flutter 中文开发者网站 - Flutter 1、查看mac电脑处理器选择sdk 2、解压 unzip ~/Downloads/flutter_macos_arm64_3.32.2-stable.zip \ -d ~/development/ 3、添加环境变量 命令行打开配置环境变量文件 ope…...
