微信号:frontshow

介绍:关注前端发展,分享一线技术.不断学习,不断进步,登上前端之巅!

Electron开发跨平台构建流程设计

2017-12-14 23:53 赵沈晶
本文为 Electron 开发系列文章,前面的文章见:
Electron开发,如何入坑?

这是 Electron 系列文章的第二篇,本文将和大家分享我是怎么去构建自动化的 Electron 开发构建工程的,说白了,就是怎么把敲的代码变成一个用户可以下载安装的包。当然随着之后应用复杂度的提升和技术再选型,工程体系可能随时会重构或演进,但至少可以给大家一些参考,欢迎留言交流。

这是一篇很长的文章(手册),写得比较「唐僧」(知我者可以说我写得比较用心),至少会花你一天时间(没开玩笑),适用场景是「用 Electron 打造 Windows 或 Mac 应用」,是的,你没看错,同时会讲清楚兼容 Win 和 Mac 两个系统的流程。文中提及的技术方案绝对不是最佳的(我保证),因为几乎每隔几天我都会发现某个环节可以做得更好,但要明白要唱多大的戏,就先搭多大的台,够用就好,不要为了搭台耽误演出时间。

工程自动化,应该是所有开发者的一种基础追求,当你搭建建好工程体系,以后你将专注于产品功能的开发,而不会花大量不必要的时间去手动构建。作为前端,可能我们已经熟悉了 web 应用的构建和部署,但是客户端程序有其本身的特点,相比较 web 应用最大也是我认为最根本的一点区别在于「你的应用是被用户下载过去安装在用户本地再跑起来的」。

这一区别对工程的影响在于,你不可能把你的代码部署到「用户的电脑」,你需要构建安装包,你需要针对不同的用户系统构建不同的安装包,你需要让你的应用被系统认为是安全的...

本文需要做的是,把客户端的打包构建发行这一流程做到像「把大象放进冰箱」一样的简单:打开命令行,敲一个 npm run xxx,喝一口咖啡,咪哩嘛哩哄,安装包出现(一开始打造这个流程时,剧本可能是「喝一口咖啡,啪,Error 了,又 Error 了」,take it easy,生活需要慢慢品味 —— 来自一位 25 岁的仙风道骨白胡子程序员)。

本文将分以下小节和大家分享「从本地的代码到云端可下载的安装包」这一路的风景,你会有漫步月球般的感觉(因为月球全是坑啊,还没氧气):

  • 第一节是关于目录结构的讨论,合适的目录结构会是一个良好的开端

  • 第二节是之后几个小节的概述,阐述了怎么把这一整个过程分成多个环节,每个环节又大致要做什么事

  • 第三到七节分别详细描述了「配置」、「打包」、「代码签名」、「构建安装包」、「发行安装包」这几个环节要做哪些事,有什么讲究

  • 第八节是简述一些可进一步研究或优化的点

  • 附:这样设计的 gulpfile 文件结构

下面一一展开进行阐述,再次强调,文中很多依赖的技术或包,你都可以尝试替换成自己相中的,不必在意是选「翠花」还是「桂花」,多处处就知道了。


一、目录结构


以下目录结构供参考,没有很详细地展开,因为每个应用可能不同,最想表达的是这是一个「双 package.json 结构」,你可以看到根目录下有一个 package.json,app 目录下还有一个 package.json。

这是因为,我们的应用在运行时需要一些第三方依赖,这些依赖我们需要打包到应用内,也就是说 /app/node_modules 目录内的内容是要被打包到应用内的,用户使用的时候才不会缺失「运行时依赖」,而如果我们只有一个 package.json,那么所有的依赖都被下载和安装到同一个 node_modules 文件夹下,我们没法把我们需要打包进去的依赖树提取出来。所以这样双 package.json 的结构最清晰明了和简单易用,dependencies 和 devDependencies 有了明确划分。

再大致解释下其他目录的作用:

  • app 目录:是我们应用的源码目录,我们所说的打包针对的就是这个目录,其他目录和文件不会被打包进去,而 app 目录内的子目录和文件就见仁见智了,在不同的复杂度下有不同的设置,这里还有一些东西是需要从外面复制进来的,因为不同的平台下你可能需要打包进去的东西是不同的。

    • config:配置文件目录,可能因为你想打包的应用所处的阶段(开发、内测、众测、正式发行)和平台(Windows、Mac),那么可能需要不同的配置,比如一些资源的名称和路径等,这里你可以把不同情况下都一样的配置写到一个配置文件,而根据情况不一样的配置文件是从外部脚本写进来的,这就是为什么你会在 app 目录外面看到一个 config 文件夹的原因

    • plugins:是插件文件夹,你可能需要给自己的应用加一些插件,比如 flash,而一个 flash 插件有 40M 左右,Win(32bit)、Win(64bit) 和 Mac 需要的 flash 插件文件都是不一样的,所以如果全部打包进你的应用,再用「if - else」去选显然是不科学的,Mac 下的应用肯定是用不到 Win 版本的插件的,所以这里的文件也是从外面脚本写进来的

    • view:是视图文件夹,也可以说是渲染进程对应的代码文件夹

  • build_resource:构建资源或工具文件夹,这个文件夹下放打包到发行这一流程中需要用到的资源和工具,比如程序主图标、构建安装包的配置脚本(win)、代码签名工具等

  • deploy:存放部署脚本的文件夹,这里的脚本负责把你的应用安装包上传到云存储(OSS),我们会在 gulp 中的发行环节引入这里写的脚本进行自动上传安装包

dist 和 release:前者是打包和构建安装包这两步的 output 目录,后者是最终我们会上传到云端的安装包目录,构建和发行环节的差别我们后面会讲到


二、把整个流程拆分成段


这个部分没法正向推导,我是从一个乱七八糟的 windows 开发流程开始的,然后修改成一个合适的 windows 开发流程,再因为要兼容 Mac 的开发,再改成现在这样的流程设计的,所以我没法从一开始就说因为什么所以要考虑什么,然后慢慢构建出一个合适的工作流,这是上帝视角,这个偏实践经验的过程一定是实践越多,感受越多的。

所以我会先说我的做法,再说这么做的好处,所用的工具是 gulp(如果不熟悉,可以去 gulp 官网看一下,很容易上手),利用 gulp 的 task 串起整条流程,我把工程中的一个阶段称为一个环节,是为了和应用本身的阶段(开发、内测、众测或正式发行)做一个区分,不然都不知道说的阶段是指啥:

  • 配置环节:设定需要打包构建针对的系统、位数(Mac 版不考虑 32 bit)和这个版本所处的阶段(开发、内存、众测或正式发行)这些变量,然后把相关配置写入配置文件模板,再导入 app 文件夹内相应位置,把其他相应的文件也写入 app 文件夹内相应位置,如此 app 文件夹就 Ready 了。

  • 打包环节:根据不同的平台打出不同的可执行程序,这一步输出的是可运行的程序代码签名环节:客户端特殊的一步,你的应用需要被系统所信任,那就需要代码签名,获取对应平台下的代码签名 CA 然后进行应用签名,这样你的应用才能被系统信任

  • 构建安装包环节:根据不同的系统利用不同的技术和依赖构建安装包,Windows 下的 .exe 和 Mac 下的 .dmg,并且对这两个安装包也需要代码签名,这一步后你的应用可以被分发安装啦

  • 发行环节:对构建的安装包进行最后一步修饰,比如修改合适的文件名,然后上传到云存储服务器,获取到可下载的链接,如此,你的应用已经可以经获取到的 url 访问进行下载安装了

以上每一步,Mac 版和 Windows 版的开发都需要经历,只是所用的方法不同,这样做的好处,一是统一了 Mac 和 Win 下开发工作流的生命周期,二是简单和直观,每一环节目的是什么,输出是什么很明确。

如此,我在 package.json 中的 script 就可以这么写:

... ...
"start": "cross-env NODE_ENV=dev gulp dev",
"packDev": "cross-env NODE_ENV=dev gulp pack",
"buildDev": "cross-env NODE_ENV=dev gulp build",
"releaseDev": "cross-env NODE_ENV=dev gulp release",
... ...

当然这里的 NODE_ENV 你也可以写成命令行参数(我只是习惯了用这个),利用这个参数去指定需要针对的应用阶段,像以上这样就配好了「dev」阶段的相关脚本,可以用 npm run packDev -- --platform="xxxx" --arch="xxxx" --sign 这样形式的命令行去执行不同的 gulp 任务,后面的参数,是需要我们在 gulpfile 文件中解析的,以上 3 个参数分别表示「系统平台」、「系统位数」、「是否需要代码签名」,我们可以在 gulpfile 文件中给这些参数合适的默认值,使操作更人性化。


三、配置环节


目的:一是为之后的环节初始化工作流参数,二是准备好应用文件夹内容(即要打包的目标文件夹 —— app)

做的事:解析命令行参数,初始化工作参数,填充配置文件,把配置文件和相关依赖文件导入到 app 文件夹内合适的地方


1. 初始化工作参数


所用工具:yargs

yargs 是一款优秀的命令行参数解析工具,我们要初始化的工作参数包括以下 3 个:「系统平台」、「系统位数」、「需不需要签名」,你也可以把应用的所处阶段(开发、内测、众测、正式)设计成参数。

// 以下 3 个变量在 gulpfile 内全局声明

// 这里的 detectPlatform() 需要自己写,利用 node 的 os 模块去检测开发机环境从而给出
// 为了理解上直观一些,把 32 位的 win 写成 win32,64 位的 win 写成 win64
// node os.platform() 没有 win64 的返回的,只有在返回 win32 基础上,你再使用 os.arch() 去确定是否是 win64
// 可能的合法值:darwin、win64、win32
platform = yargs.argv.platform || detectPlatform() || 'win32';

// 系统位数,如果是 Mac OS X,不考虑 32 位
// 可能的合法值:x64、ia32
arch = platform === 'darwin' ? 'x64' : (yargs.argv.arch || 'ia32');

// 布尔值,指定是否需要代码签名
needSign = yargs.argv.sign || process.env.NODE_ENV === 'prod' || platform === 'darwin';

看到上面的参数初始化,可能会有疑问,既然已经在 platform 中区分了 win32(32bit) 和 win64(64bit),而且 darwin 下不考虑 32bit(因为 OS X 10.6 之后就全是 64 位的),arch 参数是否多余?这是可以认为是多余的,但是有的话更完整,而且如果你以后又想兼容 linux 了呢?


2. 填充并导入配置文件


所用工具:gulp API、gulp-replace、gulp-rename

首先我会在根目录下的 config 文件夹下放几个不同的配置文件模板,分别对应应用不同的阶段的配置(比如 dev.js、alpha.js、beta.js、prod.js),然后利用 gulp-replace 去替换掉里面的一些占位字符串(也就是填充模板),最后利用 gulp-rename 重命名为比如 env.js 后,利用 gulp.dest 写入文件到 app/config 目录下,于是配置文件 Ready。


3. 二进制文件导入(以 flash 为例)


所用工具:gulp API、del

以 flash 插件为例,首先你要找到需要的插件文件,electron 官网所说的打开 chrome://plugins 已经没法用了,从 chrome 的某个版本开始,chrome://plugins Is Not Available。

所以用系统的搜索功能吧,记得先装下 chrome 浏览器,Mac 搜索「PepperFlashPlayer.plugin」,Windows 搜索「pepflashplayer」,Windows 下如果搜到多个,记得选择和 chrome 目录有关的那个「.dll」文件,此外 win32bit 和 win64bit 所用的 flash 也是不同的,Mac 下的「PepperFlashPlayer.plugin」本质是一个文件夹,整个文件夹都需要。所有的 3 个插件放进根目录下 reserve 文件夹。

接下来需要做的就是,根据不同的平台读不同的 flash 插件( .dll 文件或 .plugin 文件夹)到 app/plugin 文件夹下。

这里有一个需要注意的是,每次你构建时,如果 app/plugin 下的 flash 不是你要的,那么你需要先删除那个旧的,否则你的 app/plugin 文件夹下会躺着一个你不会用的 flash 插件,但会被打包进去,你的文件大小突然多了 40M,我这里用的删除工具是 del。

经过配置环节,app 文件夹已经准备就绪,所以以开发模式(不需要打包)运行应用也就没啥大问题,可以另写一个「dev」的 gulp task,利用 node 的 child_process 模块下的 exec 调用下 electron app --debug 就可以运行应用了,没啥可以多说的,我们继续进入下一步 —— 打包。


四、打包环节


目的:产出一个可执行程序,简单来说,就是能有一个应用,双击能运行起来

做的事:利用 electron-packager 打包,补充应用信息(only for win)


1. 利用 electron-packager 打包


利用 electron-packager 打包,只需要针对不同系统平台给出不同的配置,然后调用其 API 就可以了。

Mac 下各处(Dock、任务栏、进程名等地)展示的应用名字只要指定了 name 选项,就是处处一样的,所以你可以用 name 指定一个中午名字,而且 Mac 下默认编码都是 UTF-8,问题不大。

而对于 Windows,首先其中文默认编码是 GBK 的,而所以如果指定中文名字可能会有奇怪的问题,所以 Windows 应用一般我不填 name 项,这样它会去找你 app 目录下的 package.json 文件中的 productName 或 name 字段值,这个字段一般设置是英文的,第二个不去设置中文的原因是,Windows 下应用的展示名字是 exe 主程序的 FileDescription 配置项决定的,如果不去设置,那么可能你的应用用任务管理器打开,显示的进程是「Electron」,而不是你的应用名字。

关于应用的实际名字和展示名字,Win 和 Mac 下都有自己的一套,这里不细展开。而基于目前的实践,我给的建议是,Mac 下的开发,你可以直接指定 name 为一个你要的中文应用名,而对于 Win,你最好像下面那样操作。


2. 补充应用信息(for win)


所用工具:rcedit

Command line tool to edit resources of exe file on Windows. 翻译过来就是一个用于编辑 exe 文件信息的 windows 命令行工具,当然它已经有了 node 版本,叫 node-rcedit,也就是说你可以用 node 子进程的 exec 去执行,也可以调用 node 版本的 API。

可以这么用:

execSync(`
.\\node_modules\\rcedit\\bin\\rcedit  // 调用 rcedit
./dist/xxxxxx.exe  // 目标文件(刚打包出来的主程序)
--set-version-string "LegalCopyright" "Copyright(C) 2017 Health" // 版权信息
--set-version-string "CompanyName" "仙风道骨养生俱乐部"  // 公司名字
--set-version-string "ProductName" "养生" // 产品名字
--set-version-string "FileDescription" "养生宝典" // 这个很重要,因为这个就是你打开任务管理器看到的进程名字
`);

大部分信息,你可以右键主程序 (.exe) 文件,「属性 —— 详细信息」中看到,这么做还有一个考虑是,这样你的应用看上去会更加规范。

这里肯定有人说,为什么不用 electron-builder,因为我首先接触到的是 electron-packager,我觉得够用(因为我有一台 win 和一台 mac,跨平台打包,不存在的),第二,electron-packager 完成打包的事就够了,后面构建安装包等过程可以让我们有更多的选择,符合本文的工作流设定,每个环节做每个环节该做的事就好,当然你也可以选择 electron-builder,能达到目的就好。


五、代码签名环节


目的:使应用被系统所认可,能正常安装

做的事:给应用进行代码签名


1. 为什么需要代码签名,没有会怎样


代码签名的目的就是为了安全,你的应用一旦经过了代码签名,如果发行过程中被篡改,你的用户会看到系统给出的警告提示,而对于发行方而言,代码签名后,应用才能被系统认可,很大概率不会被杀毒软件做掉,而且如果你要提交一些软件市场,一些软件市场要求应用需要有合法的代码签名。

而如果作为铁头娃的你铁定不签名,这应用就不能跑了么?不是的,还是可以跑的,只不过对你的用户来说很不友好。


  1.1 Windows 下有和没有代码签名的差别


Windows 下代码签名的限制没有 Mac 那么严,你选择「是」都是可以安装使用的,但是从你产品的用户角度,有一个代码签名会更可靠,此外,这样的没有签名的安装包在一些软件市场可能都提交不上去。


  1.2 Mac 下有和没有代码签名的差别


Mac 下有和没有代码签名的差别就很大了,没有合法的代码签名,你的 .dmg 安装包根本没法打开。

如果没有代码签名,Mac 下的 .dmg 安装包打开,首先会提示你「该应用来自身份不明的开发者,是否确认打开」,然后你点「确认」,再根据你的安全设定(系统偏好设置 —— 安全和隐私 —— 允许从以下位置的应用下的设置)去决定,而绝大部分的 Mac 用户都是勾选「App Store 和 被认证的开发者」,于是就算你点了「打开」,直接会告诉你「打不开 XXX,因为它来自身份不明的开发者」,这个时候只能去改变「系统偏好设置 —— 安全和隐私 —— 允许从以下位置的应用下的设置」才能打开。

典型的盗版软件安装方式啊,所以作为一款要发行的产品,我们一定是需要代码签名的。


2. Windows 下的代码签名


总体建议:个人的小项目就不用 Windows 代码签名了,因为很贵,2K+/ 年,而且 Windows 下代码签名没有问题不是非常大(和 Mac 相比),公司的产品,那就必须要的。


  2.1 购买微软代码签名证书


可以向权威的 CA 机构购买代码签名证书,这里就我了解的做一个建议:建议向赛门铁克购买签名普通软件(非驱动)的微软代码签名证书,大概几百刀一年。

背景说明:目前我们用的是沃通的代码签名证书,赛门铁克的只是咨询过,没用过。

就以上的建议做一个解释,为什么我这么建议:

  • 我们需要代码签名,进一步,需要把 Windows 代码签名这一环节也做到自动化流程中,这是我们的需求

  • 沃通的代码签名证书是封死在 U 盘里,所以可认为这是物理证书,更安全,但很不方便,不可能导出来进行签名的

  • 了解到的,赛门铁克颁发的如果是针对普通软件(非驱动的),那么是可以给颁发文件格式的真·电子证书的

  • 意味着沃通的证书我们要签名,需要依靠一个物理 U 盘

  • 最坑爹的:沃通的代码签名时,要手输密码,如果一个 Windows 应用我们选择 SHA1 + SHA256 的签名方式,那么应用和安装包,我们需要输 4 次密码,气到拉闸,他们官方说有自己的命令行,实际是命令行唤起他们的 GUI 图形界面来签名,还不是需要人工操作

所以,显然这和我们的「自动化」目标相去甚远,我建议普通的应用,没有涉及到高度安全的,不要选择购买封死在 U 盘中的 Windows 代码签名证书。


  2.2 签名


当你购买了证书后,就可以利用 signtool命令行进行签名了,命令怎么写,这些都在你购买证书的 CA 网站上找到或者 google 一下,这里要说的就两点:

  • Windows 代码签名我们目前选择 SHA1 签名后再追加 SHA2(SHA256) 签名,这样的组合方式,安全和兼容性最好

  • 代码签名可以在 gulpfile 文件中封装成一个方法(参数是需要签名的文件路径),因为我们会多次调用


  2.3 查看签名信息


查看 Windows 代码签名信息很简单,右键你签名的文件,签名后的文件,属性打开会有一个「数字签名」的 tab,点击切换到「数字签名」可以看到代码签名信息。


3. Mac 下的代码签名


总体建议:Mac 下应用要代码签名,因为很方便,也不是很贵,个人开发者 99 USD 一年,如果公司有 Apple Develop Team,你可以直接加入,关键是 Mac 下如果你不进行可供分发的代码签名,你的应用很难被他人安装啊。


  3.1 利用 Xcode 申请证书,各个证书间差别


证书是可以在 Xcode 下申请的,Xcode —— Preference —— Account 下,选择一个 Team(之前要先加入),如果是独立开发者,就选自己 Apple ID 的那个,点击「Manage Certificates」,弹出的弹窗中左下角点加号,可以选择需要的证书。

我看到之后的第一反应是:尼玛,哪些是我要的啊。下面简单说明下(摘自《Mac App 发布的最后 1km》:

https://sspai.com/post/40269

我们主要需要的就是「Developer ID Application」这个类型的证书,「Mac Development」只是用于开发的,而前者可以供分发,也就是签名后,别人下载安装,就是来自「被认证的开发者」的应用啦。

如果是在一个 Team 中,不是个人独立开发者,那么这个「Developer ID Application」证书的申请你是没有权限的,就算你们 Team 的 Agent 设置你为 admin(管理员),你还是没有权限的,因为一个「Developer ID Application」只有一个 Team 的 agent(owner) 才能申请,你需要做的是利用你 Mac 上的钥匙串工具(具体怎么做,google 下就可以了),生成「CertificateSigningRequest」(简称 CSR),然后发给你的 team agent,让他帮你生成证书,发回给你,你再安装到自己机子上,搞定。

你可以在终端调用 security find-identity -p codesigning -v 来看一下你可用的代码签名证书,其中那个 Developer ID Application 开头的就是我们要的。


  3.2 签名


所用工具:electron-osx-sign

Mac 下的签名简直是红红火火开开心心嘿嘿哈哈啊,你可以从 electron-osx-sign 指导这里获得完全的指导:

https://mintkit.net/electron-userland/electron-osx-sign/guide/

你在这个页面右边可以根据你的项目进行填写,页面最后会根据你的配置,给你一段你都可以直接复制的签名代码,完美。

而且签名还能集成到打包阶段,不过我建议还是拿出来好,比较清真。


  3.3 查看签名信息


Mac 下查看文件签名信息,你可以终端运行 codesign --display --verbose=4 "文件路径"。


六、构建安装包环节


目的:使你的应用可以被安装(如果没有这一步,你能怎么办,压缩整个应用文件夹,然后分发这个压缩包,呃,你能接受也可以啊)

做的事:把经历了打包和签名环节后的应用程序文件夹(Mac 下的.app 其实也是文件夹)打成一个安装包文件

为什么要构建安装包,这有很多的原因,可能你也会想到很多,其中值得强调的两点,一是构建安装包会直接便利于应用的自动更新,具体我们下一篇文章里再说,二是 Win 下安装包的体积相比原先的文件夹,体积明显小很多,在硬盘容积很大的时代,下载体积才是最影响用户体验的,而安装后的体积不是最需要考虑的体积。

安装包这个事和代码签名类似,两个不同的系统(Win 和 Mac)实现完全不同,Windows 下我们习惯.exe 或.msi 这样的安装包格式,习惯点下一步到完成或一键安装,而 Mac 下除了 Store 下载安装的,我们习惯的.dmg 格式的,挂载后打开,将里面的应用拖入到 Application 文件夹就完成了安装。

这里我们实现的就是经典的 Windows exe 安装和 Mac dmg 安装,相比较而言,Windows 下的繁琐得多得多。


1. Windows 下利用 inno setup 进行安装包构建
  1.1 为什么用这个 inno setup


最终说服我使用 inno setup 来构建应用安装包的理由是,VS Code 也是这么做的。因为按照程序这个领域离一个小前端已经很遥远了,对于跨度大的未知东西,一般都会做充足的调研,最后发现 VS Code 也是这么做的,好,干!

而使用了一段时间后,我可以说几点不后悔的理由(当然我没使用过其他的安装包构建工具,所以仅一些偏见):

  • inno setup 应该是 windows 下构建安装程序的老牌工具了,你可以去进他们的官网,一股「老牌可靠」的风格扑面而来,可靠

  • 它有 GUI 和 命令行工具,有 unicode 版本(意味着完全支持中文),gulp 有别人写好的现成的插件(对于中文应用需要修改)

  • 基本使用的话,学习成本不大,基本去找一些案例配置文件去学一下就可以了

  • 进阶使用,需要写 pascal 脚本,但是功能是真的强大

  • 还有一点我感受很好的是,这个工具的支持很好,stackoverflow 上有足够的问答资源,如果还是没有你满意的,官网有一个看上去很很很简陋的论坛,但是很有用啊,我问过 2 个问题,睡一觉起来都有回应了


  1.2 怎么学习 inno setup


先可以自己去搜一下 inno setup,进入官网逛一逛,下载安装一下(记得安装 unicode 版本,即括号里有 u 的版本),浏览后有几个基本认知需要具备:

  • inno setup 是完全根据配置文件(.iss)来构建安装程序的,你用 GUI 其实也是去编写 .iss 文件,然后利用这个配置构建的

  • inno setup 可以用 pascal 脚本控制安装向导的行为,这是进阶的使用方式,足够你安装自己的设想优化安装程序了

  • inno setup 构建出来的安装包运行时可以添加参数,使安装有不同的表现,比如完全静默的后台安装(Amazing,这里的参数对于自动更新很有用)

有了上面的几点认知,可以给出「学习和使用 inno setup 路径」的建议:

  1. 下载安装后,找几篇 inno setup GUI 使用教程,尝试构建一个安装包(要可以安装的)

  2. 找一些 inno setup 配置文件的案例,对于 inno setup 配置方式有一个印象,分多个 [section],每个 [section] 有很多配置项,每个配置项可能有多个字段

  3. 可以把 inno setup 官方文档 浏览一遍,跳过「pascal scripting」部分

  4. 到这里,你应该能看得懂他人的 .iss 文件里除了 [code] 这个 section 外的配置了

  5. 把安装向导的语言换成中文(先要导入中文语言包,再改配置,具体做法也有一些文章说到了,不多说,这一步对于你之后步骤也是有用的)

  6. 可以尝试正式结合到你的 gulp 工作流了


  1.3 怎么结合到 gulp 工作流中


所用工具:修改后的 gulp-inno

如果按照之前的步骤花了个把小时大概学习了下 inno setup 的话,那么到这里你应该可以尝试把 inno setup 构建安装包做到你的 gulp 工作流中了,如果还不熟悉 inno setup 配置文件,没关系,你可以从仿照开始,不要怂,就是干,都到这一步了,谁怂谁尴尬。

配置文件的详解不是这里的重点,所以不再展开,把 inno setup 整合进脚本中,因为它本身提供命令行工具,勤快和好学的你可以根据官方或其他渠道的指导自己封装一个 node 模块,而我就比较懒了,搜到一个已有的 gulp 插件 —— 「gulp-inno」,高兴地一匹。

然而,事情总不会那么顺利,该吃的 shi 躲不掉,该经历的坑绕不过,这才叫「历 shi」。我利用「gulp-inno」根据其指导怎么都不能正确编译,大概提示是有不合法的字符的意思。

明白了,绝壁是「gulp-inno」里包的 inno setup 不是 unicode 版本,所以一旦有中文等字符,就出错了,我看到这个包里的 inno 文件夹完全就是和我的 inno setup 文件夹没差嘛,于是我把我本地安装的 inno setup 文件夹里内容复制替换到 gulp-inno 的 inno 的文件夹内,问题解决。

因为我之前导入过中文语言包,所以我复制过去的时候,中文语言包也复制过去了,可以愉快地配置安装向导界面为中文了。

一旦修改好「gulp-inno」包(替换成 unicode 版本 & 加入简体中文语言包),就可以怎么操作:


  1.4 未来可以做什么


当时还有一个看中 inno setup 的理由是,它可以让我们定制我们的安装向导步骤和外观,也就是说你可以让你的应用也像其他一些优秀的产品一样,在安装的时候可以定制酷炫的外观,可以优化安装流程,支持一键安装,inno setup 还是可以玩出一些花样的,enjoy。


  1.5 对安装包也进行代码签名


同样的,安装包也需要代码签名,利用之前封装的签名方法进行签名就行了。


2. Mac 下的构建 dmg 安装包


所用工具:appdmg

相比于 windows 的安装包构建,Mac 下的构建安装包又是美滋滋啊,你看我下面小标题都没有就知道了。

其余的配置和所以配置影响的内容可以参加 appdmg githug 主页,然后就是自己试试看了。


七、发行环节


目的:使应用可以被下载(上一步只是能被安装,但并不能被下载)

做的事:重命名应用安装包供发行,上传应用安装包到云存储服务器供下载

这一步根据每个人使用的云存储方式不同而需要利用卖方提供的 API 编写合适的脚本去上传你的安装包,因此具体的脚本不做展开,只是有几点最佳实践可以参考:

  • 上传前,把你的安装包文件重命名成符合一定规范的,可能是「应用名 - 版本 - 阶段 - 系统 - 尾数」,可能是「应用名 - 版本 - 系统 - 构建号」,可能是... 这个就自己定,但一定要有一个合适的命名,这样一看到名字就知道这个是啥,不会弄错

  • 你的 OSS 服务器上要针对应用安装包的不同阶段建立不同的文件夹,一方面可以方面管理,另一方面也便于做权限管理

当你上传了你的安装包后,也就意味着这个安装包有了一个下载链接,你可以分发这个链接供用户下载啦,至此终于走完了「代码」到可下载「安装包」的过程,鼓掌。


八、路漫漫


这一路走来看上去已经很有成就感,但实际上还有许多事可以做得更好,不过工程化的东西,逻辑清晰、流程自动化、能满足需求就可以了,而搭好工程,我们需要开始专注于 Electron 应用的功能开发了,才刚刚要迈上红地毯,路还有很长,下期见。

附:gulp 文件和脚本看上去会是怎样的

对之前的工作流做一个小结(如果遇到有一些旧文件覆盖不了,可以自己加一个清理环节或方法,去清理旧文件)

/* gulpfile.js START */
// 此处省略一堆需要引入的依赖

// 工作参数
let platform = 'win32';
let arch = 'ia32';
let needSign = false;

// 配置环节
gulp.task('env', (cb) => {
    // ...
});

// 开发调试
gulp.task('dev', ['env'], (cb) => {
    exec('electron app --debug', (err) => {
        if (err) return cb(err);
        cb();
    });
});

// 打包环节
gulp.task('pack',['env'], (cb) => {
    if (platform === 'darwin') {
        // ...
    } else {
        // ...
    }
});

// 签名环节
gulp.task('sign-pack', ['pack'], (cb) => {
    if (needSign) {
        if (platform === 'win32' || platform === 'win64') {
            // ...
        } else if (platform === 'darwin') {
            // ...
        }
    } else {
        cb();
    }
});

// 构建环节
gulp.task('build', ['sign-pack'], (cb) => {
    if (platform === 'darwin') {
        // ...
    } else {
        // ...
    }
});

// 发行环节
gulp.task('release', ['build'], (cb) => {
    // ...
});

const codeSignForWin = (filePath) => {...};

const codeSignForMac = (filePath) => {...};

const detectPlatform = () => {...};
/* gulpfile.js END */


// package.json 中配脚本
 "scripts": {
    "yarnall": "yarn && (cd app && yarn)",
    "start": "cross-env NODE_ENV=dev gulp dev",
    "packDev": "cross-env NODE_ENV=dev gulp pack",
    "packAlpha": "cross-env NODE_ENV=alpha gulp pack",
    "packProd": "cross-env NODE_ENV=prod gulp pack",
    "buildDev": "cross-env NODE_ENV=dev gulp build",
    "buildAlpha": "cross-env NODE_ENV=alpha gulp build",
    "buildProd": "cross-env NODE_ENV=prod gulp build",
    "releaseDev": "cross-env NODE_ENV=dev gulp release",
    "releaseAlpha": "cross-env NODE_ENV=alpha gulp release",
    "releaseProd": "cross-env NODE_ENV=prod gulp release"
  }
// 可选命令行参数:
//      sign: 是否签名
//      platform: 系统平台
//      arch: 系统位数


作者介绍


摘星,真名赵沈晶,毕业于浙江大学,是一个「不安分」的人,在校期间搞过咖啡店,做过平面设计,折腾过产品经理,最后「跌入」前端开发这个碗里,毕业后进入了酷家乐,目前在做客户端的开发。爱看书,类目广泛,从人文社科到和自己饭碗相关的都看,爱折腾新玩意、新技能、新应用,一切能提高工作效率或生活品质的东西都会去接触。


前端之巅


「前端之巅」是 InfoQ 旗下关注前端技术的垂直社群,加入前端之巅学习群请关注「前端之巅」公众号后回复 “ 加群 ”。投稿请发邮件到 editors@cn.infoq.com,注明 “ 前端之巅投稿 ”。


课程推荐:


【极客时间App】人工智能基础课开课啦!在人工智能成为必修课的当下,每个人都需要一些AI知识来升级自己。但是高大上的人工智能和机器学习如何入门,一直在困扰很多新手。极客时间App现联合王天一教授在开设“人工智能基础课”,王教授将结合自己的积累与思考,为你打开人工智能进阶之路!识别文章底图二维码了解详情↓↓↓

 
前端之巅 更多文章 前端每周清单:2017 JavaScript回顾、Node.js架构模式 ExtJS十年浮沉录 ArchSummit大会直播:大前端技术与管理 Electron开发,如何入坑? 前端每周清单:V8执行流与优化, Pinterest的PWA实践
猜您喜欢 CSharp中一种替换switch语句更优雅的写法 洪小文:以科学的方式赤裸裸地剖析AI(四)| 未来是人工智能+人类智能 用Slipstream构建复杂事件处理应用 谁是世界上最孤独的数? 推荐系统技术之文本相似性计算(三)