成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

用 Electron 打造 Win/Mac 應(yīng)用,從「代碼」到可下載的「安裝包」,可能比你想得麻煩一

LdhAndroid / 4452人閱讀

摘要:三配置環(huán)節(jié)目的一是為之后的環(huán)節(jié)初始化工作流參數(shù),二是準(zhǔn)備好應(yīng)用文件夾內(nèi)容即要打包的目標(biāo)文件夾做的事解析命令行參數(shù),初始化工作參數(shù),填充配置文件,把配置文件和相關(guān)依賴文件導(dǎo)入到文件夾內(nèi)合適的

首發(fā)于酷家樂前端博客,作者@摘星(segmentfault @StinsonZhao)

我們能從很多地方學(xué)習(xí)到怎么起一個 Electron 項目,有些還會介紹怎么打包或構(gòu)建你的代碼,但距離「真正地發(fā)行一款 Electron 產(chǎn)品」這一目標(biāo),還有很多工作需要做...

這是 Electron 系列文章的第二篇,這一篇文章將和大家分享我是怎么去構(gòu)建自動化的 Electron 開發(fā)構(gòu)建工程的,說白了,就是怎么把敲的代碼變成一個用戶可以下載安裝的包,當(dāng)然隨著之后應(yīng)用復(fù)雜度的提升和技術(shù)再選型,工程體系可能隨時會重構(gòu)或演進(jìn),但至少可以給大家一些參考,歡迎留言交流。

這是一篇很長的文章(手冊),寫得比較「唐僧」(知我者可以說我寫得比較用心),至少會花你一天時間(沒開玩笑),適用場景是「用 Electron 打造 Windows 或 Mac 應(yīng)用」,是的,你沒看錯,同時會講清楚兼容 Win 和 Mac 兩個系統(tǒng)的流程。文中提及的技術(shù)方案絕對不是最佳的(我保證),因為幾乎每隔幾天我都會發(fā)現(xiàn)某個環(huán)節(jié)可以做得更好,但要明白要唱多大的戲,就先搭多大的臺,夠用就好,不要為了搭臺耽誤演出時間

工程自動化,應(yīng)該是所有開發(fā)者的一種基礎(chǔ)追求,當(dāng)你搭建建好工程體系,以后你將專注于產(chǎn)品功能的開發(fā),而不會花大量不必要的時間去手動構(gòu)建。作為前端,可能我們已經(jīng)熟悉了 web 應(yīng)用的構(gòu)建和部署,但是客戶端程序有其本身的特點,相比較 web 應(yīng)用最大也是我認(rèn)為最根本的一點區(qū)別在于「你的應(yīng)用是被用戶下載過去安裝在用戶本地再跑起來的」。

這一區(qū)別對工程的影響在于,你不可能把你的代碼部署到「用戶的電腦」,你需要構(gòu)建安裝包,你需要針對不同的用戶系統(tǒng)構(gòu)建不同的安裝包,你需要讓你的應(yīng)用被系統(tǒng)認(rèn)為是安全的...

本文需要做的是,把客戶端的打包構(gòu)建發(fā)行這一流程做到像「把大象放進(jìn)冰箱」一樣的簡單:打開命令行,敲一個 npm run xxx,喝一口咖啡,咪哩嘛哩哄,安裝包出現(xiàn)(一開始打造這個流程時,劇本可能是「喝一口咖啡,啪,Error 了,又 Error 了」,take it easy,生活需要慢慢品味 —— 來自一位25歲的仙風(fēng)道骨白胡子程序員)。

本文將分以下小節(jié)和大家分享「從本地的代碼到云端可下載的安裝包」這一路的風(fēng)景,你會有漫步月球般的感覺(因為月球全是坑啊,還沒氧氣):

第一節(jié)是關(guān)于目錄結(jié)構(gòu)的討論,合適的目錄結(jié)構(gòu)會是一個良好的開端

第二節(jié)是之后幾個小節(jié)的概述,闡述了怎么把這一整個過程分成多個環(huán)節(jié),每個環(huán)節(jié)又大致要做什么事

第三到七節(jié)分別詳細(xì)描述了「配置」、「打包」、「代碼簽名」、「構(gòu)建安裝包」、「發(fā)行安裝包」這幾個環(huán)節(jié)要做哪些事,有什么講究

第八節(jié)是簡述一些可進(jìn)一步研究或優(yōu)化的點

附:這樣設(shè)計的 gulpfile 文件結(jié)構(gòu)

下面一一展開進(jìn)行闡述,再次強調(diào),文中很多依賴的技術(shù)或包,你都可以嘗試替換成自己相中的,不必在意是選「翠花」還是「桂花」,多處處就知道了。

一、目錄結(jié)構(gòu)

以下目錄結(jié)構(gòu)供參考,沒有很詳細(xì)地展開,因為每個應(yīng)用可能不同,最想表達(dá)的是這是一個「雙 package.json 結(jié)構(gòu)」,你可以看到根目錄下有一個package.json,app目錄下還有一個package.json

/       // 項目根目錄
├── app/                // 應(yīng)用源碼目錄,打包就針對app目錄進(jìn)行打包
│   ├── assets/                     // 應(yīng)用需要的圖片、icon等資源
│   ├── config/                     // 配置文件存放
│   ├── consts/                     // 應(yīng)用運行需要的常量,如ipcChanel
│   ├── lib/                        // 引入的庫文件,如jquery
│   ├── plugins/                    // 應(yīng)用運行需要的插件,如flash
│   ├── utils/                      // 常用的工具方法
│   ├── view/                       // 視圖,html、css和js
│   ├── app_config.js               // 整個app的配置,引入config文件夾下文件
│   ├── main.js                     // 應(yīng)用入口
│   ├── package.json                // 內(nèi)部的package,定義應(yīng)用的版本、運行依賴等
│   └── yarn.lock                   
├── build_resource/     // 構(gòu)建需要的一些工具、資源或者腳本的目錄
├── config/             // 環(huán)境配置文件目錄,會選擇一個寫入到app/config
├── deploy/             // 部署腳本,用戶部署文件到cdn或上傳文件到OSS
├── reserve/            // 保留目錄,存放一些文件用于寫入到app內(nèi)
├── dist/               // 打包和構(gòu)建的目標(biāo)目錄
├── release/            // 發(fā)行的目標(biāo)目錄
├── .gitignore
├── gulpfile.js         // gulp配置
├── package.json        // 外部package.json,用于定義開發(fā)依賴和腳本
└── yarn.lock

這是因為,我們的應(yīng)用在運行時需要一些第三方依賴,這些依賴我們需要打包到應(yīng)用內(nèi),也就是說/app/node_modules目錄內(nèi)的內(nèi)容是要被打包到應(yīng)用內(nèi)的,用戶使用的時候才不會缺失「運行時依賴」,而如果我們只有一個package.json,那么所有的依賴都被下載和安裝到同一個node_modules文件夾下,我們沒法把我們需要打包進(jìn)去的依賴樹提取出來。所以這樣雙 package.json的結(jié)構(gòu)最清晰明了和簡單易用,dependenciesdevDependencies有了明確劃分。

再大致解釋下其他目錄的作用:

app目錄:是我們應(yīng)用的源碼目錄,我們所說的打包針對的就是這個目錄,其他目錄和文件不會被打包進(jìn)去,而app目錄內(nèi)的子目錄和文件就見仁見智了,在不同的復(fù)雜度下有不同的設(shè)置,這里還有一些東西是需要從外面復(fù)制進(jìn)來的,因為不同的平臺下你可能需要打包進(jìn)去的東西是不同的。

config:配置文件目錄,可能因為你想打包的應(yīng)用所處的階段(開發(fā)、內(nèi)測、眾測、正式發(fā)行)和平臺(Windows、Mac),那么可能需要不同的配置,比如一些資源的名稱和路徑等,這里你可以把不同情況下都一樣的配置寫到一個配置文件,而根據(jù)情況不一樣的配置文件是從外部腳本寫進(jìn)來的,這就是為什么你會在app目錄外面看到一個config文件夾的原因

plugins:是插件文件夾,你可能需要給自己的應(yīng)用加一些插件,比如 flash,而一個 flash 插件有 40M 左右,Win(32bit)、Win(64bit) 和 Mac 需要的 flash 插件文件都是不一樣的,所以如果全部打包進(jìn)你的應(yīng)用,再用「if - else」去選顯然是不科學(xué)的,Mac 下的應(yīng)用肯定是用不到 Win 版本的插件的,所以這里的文件也是從外面腳本寫進(jìn)來的

view:是視圖文件夾,也可以說是渲染進(jìn)程對應(yīng)的代碼文件夾

build_resource:構(gòu)建資源或工具文件夾,這個文件夾下放打包到發(fā)行這一流程中需要用到的資源和工具,比如程序主圖標(biāo)、構(gòu)建安裝包的配置腳本(win)、代碼簽名工具等

deploy:存放部署腳本的文件夾,這里的腳本負(fù)責(zé)把你的應(yīng)用安裝包上傳到云存儲(OSS),我們會在 gulp 中的發(fā)行環(huán)節(jié)引入這里寫的腳本進(jìn)行自動上傳安裝包

distrelease:前者是打包和構(gòu)建安裝包這兩步的 output 目錄,后者是最終我們會上傳到云端的安裝包目錄,構(gòu)建和發(fā)行環(huán)節(jié)的差別我們后面會講到

二、把整個流程拆分成段

這個部分沒法正向推導(dǎo),我是從一個亂七八糟的 windows 開發(fā)流程開始的,然后修改成一個合適的 windows 開發(fā)流程,再因為要兼容 Mac 的開發(fā),再改成現(xiàn)在這樣的流程設(shè)計的,所以我沒法從一開始就說因為什么所以要考慮什么,然后慢慢構(gòu)建出一個合適的工作流,這是上帝視角,這個偏實踐經(jīng)驗的過程一定是實踐越多,感受越多的。

所以我會先說我的做法,再說這么做的好處,所用的工具是 gulp(如果不熟悉,可以去 gulp 官網(wǎng)看一下,很容易上手),利用 gulp 的 task 串起整條流程,我把工程中的一個階段稱為一個環(huán)節(jié),是為了和應(yīng)用本身的階段(開發(fā)、內(nèi)測、眾測或正式發(fā)行)做一個區(qū)分,不然都不知道說的階段是指啥

配置環(huán)節(jié):設(shè)定需要打包構(gòu)建針對的系統(tǒng)、位數(shù)(Mac 版不考慮 32 bit)和這個版本所處的階段(開發(fā)、內(nèi)存、眾測或正式發(fā)行)這些變量,然后把相關(guān)配置寫入配置文件模板,再導(dǎo)入 app 文件夾內(nèi)相應(yīng)位置,把其他相應(yīng)的文件也寫入 app 文件夾內(nèi)相應(yīng)位置,如此 app 文件夾就 Ready 了。

打包環(huán)節(jié):根據(jù)不同的平臺打出不同的可執(zhí)行程序,這一步輸出的是可運行的程序

代碼簽名環(huán)節(jié):客戶端特殊的一步,你的應(yīng)用需要被系統(tǒng)所信任,那就需要代碼簽名,獲取對應(yīng)平臺下的代碼簽名 CA 然后進(jìn)行應(yīng)用簽名,這樣你的應(yīng)用才能被系統(tǒng)信任

構(gòu)建安裝包環(huán)節(jié):根據(jù)不同的系統(tǒng)利用不同的技術(shù)和依賴構(gòu)建安裝包,Windows 下的 .exe 和 Mac下的 .dmg,并且對這兩個安裝包也需要代碼簽名,這一步后你的應(yīng)用可以被分發(fā)安裝啦

發(fā)行環(huán)節(jié):對構(gòu)建的安裝包進(jìn)行最后一步修飾,比如修改合適的文件名,然后上傳到云存儲服務(wù)器,獲取到可下載的鏈接,如此,你的應(yīng)用已經(jīng)可以經(jīng)獲取到的 url 訪問進(jìn)行下載安裝了

以上每一步,Mac 版和 Windows 版的開發(fā)都需要經(jīng)歷,只是所用的方法不同,這樣做的好處,一是統(tǒng)一了 Mac 和 Win 下開發(fā)工作流的生命周期,二是簡單和直觀,每一環(huán)節(jié)目的是什么,輸出是什么很明確。

如此,我在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",
... ...

當(dāng)然這里的NODE_ENV你也可以寫成命令行參數(shù)(我只是習(xí)慣了用這個),利用這個參數(shù)去指定需要針對的應(yīng)用階段,像以上這樣就配好了「dev」階段的相關(guān)腳本,可以用npm run packDev -- --platform="xxxx" --arch="xxxx" --sign這樣形式的命令行去執(zhí)行不同的 gulp 任務(wù),后面的參數(shù),是需要我們在 gulpfile 文件中解析的,以上3個參數(shù)分別表示「系統(tǒng)平臺」、「系統(tǒng)位數(shù)」、「是否需要代碼簽名」,我們可以在 gulpfile 文件中給這些參數(shù)合適的默認(rèn)值,使操作更人性化。

三、配置環(huán)節(jié)

目的:一是為之后的環(huán)節(jié)初始化工作流參數(shù),二是準(zhǔn)備好應(yīng)用文件夾內(nèi)容(即要打包的目標(biāo)文件夾 —— app)

做的事:解析命令行參數(shù),初始化工作參數(shù),填充配置文件,把配置文件和相關(guān)依賴文件導(dǎo)入到app文件夾內(nèi)合適的地方

1. 初始化工作參數(shù)

所用工具:yargs

yargs 是一款優(yōu)秀的命令行參數(shù)解析工具,我們要初始化的工作參數(shù)包括以下 3 個:「系統(tǒng)平臺」、「系統(tǒng)位數(shù)」、「需不需要簽名」,你也可以把應(yīng)用的所處階段(開發(fā)、內(nèi)測、眾測、正式)設(shè)計成參數(shù)。

// 以下 3 個變量在 gulpfile 內(nèi)全局聲明

// 這里的 detectPlatform() 需要自己寫,利用 node 的 os 模塊去檢測開發(fā)機環(huán)境從而給出
// 為了理解上直觀一些,把 32 位的 win 寫成 win32,64 位的 win 寫成 win64
// node os.platform() 沒有 win64 的返回的,只有在返回 win32 基礎(chǔ)上,你再使用 os.arch() 去確定是否是win64
// 可能的合法值:darwin、win64、win32
platform = yargs.argv.platform || detectPlatform() || "win32";

// 系統(tǒng)位數(shù),如果是 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";

看到上面的參數(shù)初始化,可能會有疑問,既然已經(jīng)在platform中區(qū)分了 win32(32bit) 和 win64(64bit),而且darwin下不考慮 32bit(因為 OS X 10.6 之后就全是 64 位的),arch參數(shù)是否多余?這是可以認(rèn)為是多余的,但是有的話更完整,而且如果你以后又想兼容 linux 了呢?

2. 填充并導(dǎo)入配置文件

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

首先我會在根目錄下的 config 文件夾下放幾個不同的配置文件模板,分別對應(yīng)應(yīng)用不同的階段的配置(比如dev.js、alpha.js、beta.js、prod.js),然后利用gulp-replace去替換掉里面的一些占位字符串(也就是填充模板),最后利用gulp-rename重命名為比如env.js后,利用gulp.dest寫入文件到 app/config 目錄下,于是配置文件 Ready。

3. 二進(jìn)制文件導(dǎo)入(以 flash 為例)

所用工具:gulp API、del

以 flash 插件為例,首先你要找到需要的插件文件,electron 官網(wǎng)所說的打開chrome://plugins已經(jīng)沒法用了,從 chrome 的某個版本開始,chrome://plugins Is Not Available。

所以用系統(tǒng)的搜索功能吧,記得先裝下 chrome 瀏覽器,Mac 搜索「PepperFlashPlayer.plugin」,Windows 搜索「pepflashplayer」,Windows下如果搜到多個,記得選擇和 chrome 目錄有關(guān)的那個「.dll」文件,此外 win32bit 和 win64bit 所用的 flash 也是不同的,Mac 下的「PepperFlashPlayer.plugin」本質(zhì)是一個文件夾,整個文件夾都需要。所有的3個插件放進(jìn)根目錄下 reserve 文件夾。

接下來需要做的就是,根據(jù)不同的平臺讀不同的 flash 插件( .dll 文件或 .plugin 文件夾)到 app/plugin 文件夾下。

這里有一個需要注意的是,每次你構(gòu)建時,如果 app/plugin 下的 flash 不是你要的,那么你需要先刪除那個舊的,否則你的 app/plugin 文件夾下會躺著一個你不會用的 flash 插件,但會被打包進(jìn)去,你的文件大小突然多了 40M,我這里用的刪除工具是 del。

經(jīng)過配置環(huán)節(jié),app文件夾已經(jīng)準(zhǔn)備就緒,所以以開發(fā)模式(不需要打包)運行應(yīng)用也就沒啥大問題,可以另寫一個「dev」的 gulp task,利用 node 的child_process模塊下的exec調(diào)用下electron app --debug就可以運行應(yīng)用了,沒啥可以多說的,我們繼續(xù)進(jìn)入下一步 —— 打包。

四、打包環(huán)節(jié)

目的:產(chǎn)出一個可執(zhí)行程序,簡單來說,就是能有一個應(yīng)用,雙擊能運行起來

做的事:利用electron-packager打包,補充應(yīng)用信息(only for win)

1. 利用electron-packager打包

利用electron-packager打包,只需要針對不同系統(tǒng)平臺給出不同的配置,然后調(diào)用其 API 就可以了。

// Mac
const options = {
    dir: "./app",
    name: "應(yīng)用名字",
    platform: "darwin",
    arch: arch, // 這就是工作參數(shù) arch
    overwrite: true,
    appVersion: "Copyright(C) 2017 Qunhe",
    asar: {
        unpackDir: "plugins" // plugins 內(nèi)的文件我們不希望打進(jìn) asar 格式包內(nèi)
    },
    out: "./dist",
    icon: "./build_resource/logo.icns" // Mac 下 icon 格式是 .icns
};

// Win
const options = {
    dir: "./app",
    platform: "win32", // 不管是 32bit 還是 64bit 的 win,這里都是 win32
    arch: arch, // 這里依靠 x64 或 ia32 去區(qū)分位數(shù)
    overwrite: true,
    asar: {
        unpackDir: "plugins"
    },
    out: "./dist",
    icon: "./build_resource/logo.ico" // Win 下 icon 格式是 .ico
};

Mac 下各處(Dock、任務(wù)欄、進(jìn)程名等地)展示的應(yīng)用名字只要指定了name選項,就是處處一樣的,所以你可以用 name 指定一個中午名字,而且 Mac 下默認(rèn)編碼都是 UTF-8,問題不大。

而對于 Windows,首先其中文默認(rèn)編碼是 GBK 的,而所以如果指定中文名字可能會有奇怪的問題,所以 Windows 應(yīng)用一般我不填name項,這樣它會去找你 app 目錄下的 package.json 文件中的productNamename字段值,這個字段一般設(shè)置是英文的,第二個不去設(shè)置中文的原因是,Windows 下應(yīng)用的展示名字是 exe 主程序的FileDescription配置項決定的,如果不去設(shè)置,那么可能你的應(yīng)用用任務(wù)管理器打開,顯示的進(jìn)程是「Electron」,而不是你的應(yīng)用名字。

關(guān)于應(yīng)用的實際名字和展示名字,Win 和 Mac 下都有自己的一套,這里不細(xì)展開。而基于目前的實踐,我給的建議是,Mac 下的開發(fā),你可以直接指定name為一個你要的中文應(yīng)用名,而對于 Win,你最好像下面那樣操作。

2. 補充應(yīng)用信息(for win)

所用工具:rcedit

Command line tool to edit resources of exe file on Windows. 翻譯過來就是一個用于編輯 exe 文件信息的windows 命令行工具,當(dāng)然它已經(jīng)有了 node 版本,叫 node-rcedit,也就是說你可以用 node 子進(jìn)程的exec去執(zhí)行,也可以調(diào)用 node 版本的 API。

可以這么用:

execSync(`
.
ode_modules
ceditin
cedit  // 調(diào)用rcedit
./dist/xxxxxx.exe  // 目標(biāo)文件(剛打包出來的主程序)
--set-version-string "LegalCopyright" "Copyright(C) 2017 Health" // 版權(quán)信息
--set-version-string "CompanyName" "仙風(fēng)道骨養(yǎng)生俱樂部"  // 公司名字
--set-version-string "ProductName" "養(yǎng)生" // 產(chǎn)品名字
--set-version-string "FileDescription" "養(yǎng)生寶典" // 這個很重要,因為這個就是你打開任務(wù)管理器看到的進(jìn)程名字
`);

大部分信息,你可以右鍵主程序(.exe)文件,「屬性 —— 詳細(xì)信息」中看到,這么做還有一個考慮是,這樣你的應(yīng)用看上去會更加規(guī)范。

這里肯定有人說,為什么不用electron-builder,因為我首先接觸到的是electron-packager,我覺得夠用(因為我有一臺 win 和一臺 mac,跨平臺打包,不存在的),第二,electron-packager完成打包的事就夠了,后面構(gòu)建安裝包等過程可以讓我們有更多的選擇,符合本文的工作流設(shè)定,每個環(huán)節(jié)做每個環(huán)節(jié)該做的事就好,當(dāng)然你也可以選擇electron-builder,能達(dá)到目的就好。

五、代碼簽名環(huán)節(jié)

目的:使應(yīng)用被系統(tǒng)所認(rèn)可,能正常安裝

做的事:給應(yīng)用進(jìn)行代碼簽名

1. 為什么需要代碼簽名,沒有會怎樣

代碼簽名的目的就是為了安全,你的應(yīng)用一旦經(jīng)過了代碼簽名,如果發(fā)行過程中被篡改,你的用戶會看到系統(tǒng)給出的警告提示,而對于發(fā)行方而言,代碼簽名后,應(yīng)用才能被系統(tǒng)認(rèn)可,很大概率不會被殺毒軟件做掉,而且如果你要提交一些軟件市場,一些軟件市場要求應(yīng)用需要有合法的代碼簽名。

而如果作為鐵頭娃的你鐵定不簽名,這應(yīng)用就不能跑了么?不是的,還是可以跑的,只不過對你的用戶來說很不友好。

1.1 Windows 下有和沒有代碼簽名的差別

Windows 下代碼簽名的限制沒有 Mac 那么嚴(yán),你選擇「是」都是可以安裝使用的,但是從你產(chǎn)品的用戶角度,有一個代碼簽名會更可靠,此外,這樣的沒有簽名的安裝包在一些軟件市場可能都提交不上去。

1.2 Mac 下有和沒有代碼簽名的差別

Mac 下有和沒有代碼簽名的差別就很大了,沒有合法的代碼簽名,你的 .dmg 安裝包根本沒法打開。

如果沒有代碼簽名,Mac 下的 .dmg 安裝包打開,首先會提示你「該應(yīng)用來自身份不明的開發(fā)者,是否確認(rèn)打開」,然后你點「確認(rèn)」,再根據(jù)你的安全設(shè)定(系統(tǒng)偏好設(shè)置 —— 安全和隱私 —— 允許從以下位置的應(yīng)用下的設(shè)置)去決定,而絕大部分的 Mac 用戶都是勾選「App Store 和 被認(rèn)證的開發(fā)者」,于是就算你點了「打開」,直接會告訴你「打不開XXX,因為它來自身份不明的開發(fā)者」,這個時候只能去改變「系統(tǒng)偏好設(shè)置 —— 安全和隱私 —— 允許從以下位置的應(yīng)用下的設(shè)置」才能打開。

典型的盜版軟件安裝方式啊,所以作為一款要發(fā)行的產(chǎn)品,我們一定是需要代碼簽名的。

2. Windows 下的代碼簽名

總體建議:個人的小項目就不用 Windows 代碼簽名了,因為很貴,2K+/年,而且 Windows 下代碼簽名沒有問題不是非常大(和 Mac 相比),公司的產(chǎn)品,那就必須要的。

2.1 購買微軟代碼簽名證書

可以向權(quán)威的 CA 機構(gòu)購買代碼簽名證書,這里就我了解的做一個建議:建議向賽門鐵克購買簽名普通軟件(非驅(qū)動)的微軟代碼簽名證書,大概幾百刀一年。

背景說明:目前我們用的是沃通的代碼簽名證書,賽門鐵克的只是咨詢過,沒用過。

就以上的建議做一個解釋,為什么我這么建議:

我們需要代碼簽名,進(jìn)一步,需要把 Windows 代碼簽名這一環(huán)節(jié)也做到自動化流程中,這是我們的需求

沃通的代碼簽名證書是封死在 U 盤里,所以可認(rèn)為這是物理證書,更安全,但很不方便,不可能導(dǎo)出來進(jìn)行簽名的

了解到的,賽門鐵克頒發(fā)的如果是針對普通軟件(非驅(qū)動的),那么是可以給頒發(fā)文件格式的真·電子證書的

意味著沃通的證書我們要簽名,需要依靠一個物理U盤

最坑爹的:沃通的代碼簽名時,要手輸密碼,如果一個 Windows 應(yīng)用我們選擇 SHA1 + SHA256 的簽名方式,那么應(yīng)用和安裝包,我們需要輸4次密碼,氣到拉閘,他們官方說有自己的命令行,實際是命令行喚起他們的 GUI 圖形界面來簽名,還不是需要人工操作

所以,顯然這和我們的「自動化」目標(biāo)相去甚遠(yuǎn),我建議普通的應(yīng)用,沒有涉及到高度安全的,不要選擇購買封死在 U 盤中的 Windows 代碼簽名證書。

2.2 簽名

當(dāng)你購買了證書后,就可以利用signtool 命令行進(jìn)行簽名了,命令怎么寫,這些都在你購買證書的 CA 網(wǎng)站上找到或者 google 一下,這里要說的就兩點:

Windows 代碼簽名我們目前選擇 SHA1 簽名后再追加 SHA2(SHA256) 簽名,這樣的組合方式,安全和兼容性最好

代碼簽名可以在 gulpfile 文件中封裝成一個方法(參數(shù)是需要簽名的文件路徑),因為我們會多次調(diào)用

2.3 查看簽名信息

查看 Windows 代碼簽名信息很簡單,右鍵你簽名的文件,簽名后的文件,屬性打開會有一個「數(shù)字簽名」的 tab,點擊切換到「數(shù)字簽名」可以看到代碼簽名信息。

3. Mac 下的代碼簽名

總體建議:Mac 下應(yīng)用要代碼簽名,因為很方便,也不是很貴,個人開發(fā)者 99 USD 一年,如果公司有 Apple Develop Team,你可以直接加入,關(guān)鍵是 Mac 下如果你不進(jìn)行可供分發(fā)的代碼簽名,你的應(yīng)用很難被他人安裝啊。

3.1 利用 Xcode 申請證書,各個證書間差別

證書是可以在 Xcode 下申請的,Xcode —— Preference —— Account 下,選擇一個Team(之前要先加入),如果是獨立開發(fā)者,就選自己 Apple ID 的那個,點擊「Manage Certificates」,彈出的彈窗中左下角點加號,可以選擇需要的證書。

我看到之后的第一反應(yīng)是:尼瑪,哪些是我要的啊。下面簡單說明下(摘自Mac App 發(fā)布的最后 1km):

Developer Certificate

Mac Development :這個只用來開發(fā),Debug,不是正式發(fā)布的版本

Production Certificate

Mac App Store

Mac App Distribution :這個用于 Xcode 自己把 .app 文件上傳到 Mac App Store

Mac Installer Distribution :這個沒用過,但可以肯定的,也是上傳 Mac App Store 用的

Developer ID

Developer ID Application:這個用于開發(fā)者使用開發(fā)者帳號簽名,導(dǎo)出一個線下發(fā)布版本的 .app 文件,脫離了蘋果的 Mac App Store。

Developer ID Installer:用于開發(fā)者打包,同時加上開發(fā)者帳號簽名,打包工具在下面介紹。

我們主要需要的就是「Developer ID Application」這個類型的證書,「Mac Development」只是用于開發(fā)的,而前者可以供分發(fā),也就是簽名后,別人下載安裝,就是來自「被認(rèn)證的開發(fā)者」的應(yīng)用啦。

如果是在一個 Team 中,不是個人獨立開發(fā)者,那么這個「Developer ID Application」證書的申請你是沒有權(quán)限的,就算你們 Team 的 Agent 設(shè)置你為 admin(管理員),你還是沒有權(quán)限的,因為一個「Developer ID Application」只有一個 Team 的 agent(owner) 才能申請,你需要做的是利用你 Mac 上的鑰匙串工具(具體怎么做,google 下就可以了),生成「CertificateSigningRequest」(簡稱 CSR),然后發(fā)給你的 team agent,讓他幫你生成證書,發(fā)回給你,你再安裝到自己機子上,搞定。

你可以在終端調(diào)用security find-identity -p codesigning -v來看一下你可用的代碼簽名證書,其中那個Developer ID Application開頭的就是我們要的。

3.2 簽名

所用工具:electron-osx-sign

Mac 下的簽名簡直是紅紅火火開開心心嘿嘿哈哈啊,你可以從electron-osx-sign 指導(dǎo)這里獲得完全的指導(dǎo),你在這個頁面右邊可以根據(jù)你的項目進(jìn)行填寫,頁面最后會根據(jù)你的配置,給你一段你都可以直接復(fù)制的簽名代碼,完美。

而且簽名還能集成到打包階段,不過我建議還是拿出來好,比較清真。

3.3 查看簽名信息

Mac 下查看文件簽名信息,你可以終端運行codesign --display --verbose=4 "文件路徑"。

六、構(gòu)建安裝包環(huán)節(jié)

目的:使你的應(yīng)用可以被安裝(如果沒有這一步,你能怎么辦,壓縮整個應(yīng)用文件夾,然后分發(fā)這個壓縮包,呃,你能接受也可以?。?/p>

做的事:把經(jīng)歷了打包和簽名環(huán)節(jié)后的應(yīng)用程序文件夾(Mac 下的.app其實也是文件夾)打成一個安裝包文件

為什么要構(gòu)建安裝包,這有很多的原因,可能你也會想到很多,其中值得強調(diào)的兩點,一是構(gòu)建安裝包會直接便利于應(yīng)用的自動更新,具體我們下一篇文章里再說,二是 Win 下安裝包的體積相比原先的文件夾,體積明顯小很多,在硬盤容積很大的時代,下載體積才是最影響用戶體驗的,而安裝后的體積不是最需要考慮的體積。

安裝包這個事和代碼簽名類似,兩個不同的系統(tǒng)(Win 和 Mac)實現(xiàn)完全不同,Windows 下我們習(xí)慣.exe.msi這樣的安裝包格式,習(xí)慣點下一步到完成或一鍵安裝,而 Mac 下除了 Store 下載安裝的,我們習(xí)慣的.dmg格式的,掛載后打開,將里面的應(yīng)用拖入到Application文件夾就完成了安裝。

這里我們實現(xiàn)的就是經(jīng)典的 Windows exe 安裝和 Mac dmg 安裝,相比較而言,Windows 下的繁瑣得多得多。

1. Windows 下利用 inno setup 進(jìn)行安裝包構(gòu)建 1.1 為什么用這個 inno setup

最終說服我使用 inno setup 來構(gòu)建應(yīng)用安裝包的理由是,VS Code 也是這么做的。因為按照程序這個領(lǐng)域離一個小前端已經(jīng)很遙遠(yuǎn)了,對于跨度大的未知東西,一般都會做充足的調(diào)研,最后發(fā)現(xiàn) VS Code 也是這么做的,好,干!

而使用了一段時間后,我可以說幾點不后悔的理由(當(dāng)然我沒使用過其他的安裝包構(gòu)建工具,所以僅一些偏見):

inno setup 應(yīng)該是 windows 下構(gòu)建安裝程序的老牌工具了,你可以去進(jìn)他們的官網(wǎng),一股「老牌可靠」的風(fēng)格撲面而來,可靠

它有 GUI 和 命令行工具,有 unicode 版本(意味著完全支持中文),gulp 有別人寫好的現(xiàn)成的插件(對于中文應(yīng)用需要修改)

基本使用的話,學(xué)習(xí)成本不大,基本去找一些案例配置文件去學(xué)一下就可以了

進(jìn)階使用,需要寫 pascal 腳本,但是功能是真的強大

還有一點我感受很好的是,這個工具的支持很好,stackoverflow 上有足夠的問答資源,如果還是沒有你滿意的,官網(wǎng)有一個看上去很很很簡陋的論壇,但是很有用啊,我問過 2 個問題,睡一覺起來都有回應(yīng)了

1.2 怎么學(xué)習(xí) inno setup

先可以自己去搜一下 inno setup,進(jìn)入官網(wǎng)逛一逛,下載安裝一下(記得安裝 unicode 版本,即括號里有 u 的版本),瀏覽后有幾個基本認(rèn)知需要具備:

inno setup 是完全根據(jù)配置文件(.iss)來構(gòu)建安裝程序的,你用 GUI 其實也是去編寫 .iss 文件,然后利用這個配置構(gòu)建的

inno setup 可以用 pascal 腳本控制安裝向?qū)У男袨?,這是進(jìn)階的使用方式,足夠你安裝自己的設(shè)想優(yōu)化安裝程序了

inno setup 構(gòu)建出來的安裝包運行時可以添加參數(shù),使安裝有不同的表現(xiàn),比如完全靜默的后臺安裝(Amazing,這里的參數(shù)對于自動更新很有用)

有了上面的幾點認(rèn)知,可以給出「學(xué)習(xí)和使用 inno setup 路徑」的建議:

下載安裝后,找?guī)灼?inno setup GUI 使用教程,嘗試構(gòu)建一個安裝包(要可以安裝的)

找一些 inno setup 配置文件的案例,對于 inno setup 配置方式有一個印象,分多個[section],每個[section]有很多配置項,每個配置項可能有多個字段

可以把 inno setup 官方文檔 瀏覽一遍,跳過「pascal scripting」部分

到這里,你應(yīng)該能看得懂他人的 .iss 文件里除了 [code] 這個 section 外的配置了

把安裝向?qū)У恼Z言換成中文(先要導(dǎo)入中文語言包,再改配置,具體做法也有一些文章說到了,不多說,這一步對于你之后步驟也是有用的)

可以嘗試正式結(jié)合到你的 gulp 工作流了

1.3 怎么結(jié)合到 gulp 工作流中

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

如果按照之前的步驟花了個把小時大概學(xué)習(xí)了下 inno setup 的話,那么到這里你應(yīng)該可以嘗試把 inno setup 構(gòu)建安裝包做到你的 gulp 工作流中了,如果還不熟悉 inno setup 配置文件,沒關(guān)系,你可以從仿照開始,不要慫,就是干,都到這一步了,誰慫誰尷尬。

配置文件的詳解不是這里的重點,所以不再展開,把 inno setup 整合進(jìn)腳本中,因為它本身提供命令行工具,勤快和好學(xué)的你可以根據(jù)官方或其他渠道的指導(dǎo)自己封裝一個 node 模塊,而我就比較懶了,搜到一個已有的 gulp 插件 —— 「gulp-inno」,高興地一匹。

然而,事情總不會那么順利,該吃的shi躲不掉,該經(jīng)歷的坑繞不過,這才叫「歷shi」。我利用「gulp-inno」根據(jù)其指導(dǎo)怎么都不能正確編譯,大概提示是有不合法的字符的意思。

明白了,絕壁是「gulp-inno」里包的 inno setup 不是 unicode 版本,所以一旦有中文等字符,就出錯了,我看到這個包里的 inno 文件夾完全就是和我的 inno setup 文件夾沒差嘛,于是我把我本地安裝的 inno setup 文件夾里內(nèi)容復(fù)制替換到 gulp-inno 的 inno 的文件夾內(nèi),問題解決。

因為我之前導(dǎo)入過中文語言包,所以我復(fù)制過去的時候,中文語言包也復(fù)制過去了,可以愉快地配置安裝向?qū)Ы缑鏋橹形牧恕?/p>

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

// 1. 準(zhǔn)備 iss 文件:填充你的 iss 配置文件模板,并輸出到 dist 目錄下

const appInfo = require("./app/package.json"); // 所有和應(yīng)用相關(guān)的信息從 package.json 讀取
const bom = require("gulp-bom"); // 這是為了解析中文的
const outputName = 
`${appInfo.name}-${platform}-${appInfo.version}-${process.env.NODE_ENV}`;
const outputIssName = 
`${appInfo.name}-${platform}-${process.env.NODE_ENV}.iss`

gulp
    .src(`./build_resource/installer_win_config_${platform}.iss`)
    .pipe(bom())
    .pipe(replace("${version}", appInfo.version))
    .pipe(replace("${appExe}", `${appInfo.name}.exe`))
    .pipe(replace("${sourcePath}", `${appInfo.name}-${platform}`))
    .pipe(replace("${outputName}",outputName))
    .pipe(rename(outputIssName))
    .pipe(gulp.dest("./dist"))
    .on("end", () => {
        // .iss file is ready
    })

// 2. 交給 inno setup

const inno = require("my-gulp-inno"); // 修改后的 gulp-inno

gulp
    .src(`./dist/${outputIssName}`)
    .pipe(inno())
    .on("end", () => {
        // you have an installer now
    });
1.4 未來可以做什么

當(dāng)時還有一個看中 inno setup 的理由是,它可以讓我們定制我們的安裝向?qū)Р襟E和外觀,也就是說你可以讓你的應(yīng)用也像其他一些優(yōu)秀的產(chǎn)品一樣,在安裝的時候可以定制酷炫的外觀,可以優(yōu)化安裝流程,支持一鍵安裝,inno setup 還是可以玩出一些花樣的,enjoy。

1.5 對安裝包也進(jìn)行代碼簽名

同樣的,安裝包也需要代碼簽名,利用之前封裝的簽名方法進(jìn)行簽名就行了。

2. Mac 下的構(gòu)建 dmg 安裝包

所用工具:appdmg

相比于 windows 的安裝包構(gòu)建,Mac 下的構(gòu)建安裝包又是美滋滋啊,你看我下面小標(biāo)題都沒有就知道了。

// 因為 appdmg 在 windows 下不能下載安裝的,所以放在外部 package.json 的 optionalDependencies 下
// 在 gulp 腳本中需要做 try...catch 處理,否則當(dāng)你回到 windows 下使用這份 gulp 時會出報錯
let appdmg;
try {
    appdmg = require("appdmg");
} catch (err) {
    appdmg = null;
}

const dmg = appdmg({
    // 打出的目標(biāo) dmg
    target: `dist/balabala.dmg`,
    // 基準(zhǔn)目錄,以下的資源都基于這個目錄
    basepath: __dirname,
    // 具體的選項
    specification: {
        // dmg 打開后的窗口名字
        // 注意不要給中文,給中文會導(dǎo)致下面的 background 無效,不明白, github 上也有人提了這個 issue
        title: `myapp`,
        // dmg 掛載后的圖標(biāo),出現(xiàn)在桌面上
        icon: "xxx.icns",
        // 背景圖,如果同時存在 bg.png 和 [email protected],appdmg 會根據(jù)用戶屏幕自己找合適的圖
        background: "bg.png",
        // 里面所有icon的尺寸
        "icon-size": 96,
        // 窗口設(shè)置
        window: {
            size: {
                width: 550,
                height: 320
            }
        },
        // 里面的內(nèi)容,x 是指這個 icon 中心距離窗口最左邊的距離,y 是指這個 icon 中心距離窗口頂部的距離
        // 這里可以指定一個name項,不要給中文,會導(dǎo)致圖標(biāo)異常
        contents: [
            { "x": 400, "y": 128, "type": "link", "path": "/Applications" },
            { "x": 150, "y": 128, "type": "file", "path": "你的應(yīng)用.app" }
        ],
        // 對 dmg 進(jìn)行代碼簽名
        "code-sign": {
            "signing-identity": "你的代碼簽名證書"
        }
    }
});
dmg.on("finish", function () {
    // you have a dmg now
});
dmg.on("error", function (err) {
    // error
});

其余的配置和所以配置影響的內(nèi)容可以參加 appdmg githug 主頁,然后就是自己試試看了。

七、發(fā)行環(huán)節(jié)

目的:使應(yīng)用可以被下載(上一步只是能被安裝,但并不能被下載)

做的事:重命名應(yīng)用安裝包供發(fā)行,上傳應(yīng)用安裝包到云存儲服務(wù)器供下載

這一步根據(jù)每個人使用的云存儲方式不同而需要利用賣方提供的 API 編寫合適的腳本去上傳你的安裝包,因此具體的腳本不做展開,只是有幾點最佳實踐可以參考:

上傳前,把你的安裝包文件重命名成符合一定規(guī)范的,可能是「應(yīng)用名-版本-階段-系統(tǒng)-尾數(shù)」,可能是「應(yīng)用名-版本-系統(tǒng)-構(gòu)建號」,可能是...這個就自己定,但一定要有一個合適的命名,這樣一看到名字就知道這個是啥,不會弄錯

你的 OSS 服務(wù)器上要針對應(yīng)用安裝包的不同階段建立不同的文件夾,一方面可以方面管理,另一方面也便于做權(quán)限管理

當(dāng)你上傳了你的安裝包后,也就意味著這個安裝包有了一個下載鏈接,你可以分發(fā)這個鏈接供用戶下載啦,至此終于走完了「代碼」到可下載「安裝包」的過程,鼓掌。

八、路漫漫

這一路走來看上去已經(jīng)很有成就感,但實際上還有許多事可以做得更好,不過工程化的東西,邏輯清晰、流程自動化、能滿足需求就可以了,而搭好工程,我們需要開始專注于 Electron 應(yīng)用的功能開發(fā)了,才剛剛要邁上紅地毯,路還有很長,下期見。

附:gulp 文件和腳本看上去會是怎樣的

對之前的工作流做一個小結(jié)(如果遇到有一些舊文件覆蓋不了,可以自己加一個清理環(huán)節(jié)或方法,去清理舊文件)

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

// 工作參數(shù)
let platform = "win32";
let arch = "ia32";
let needSign = false;

// 配置環(huán)節(jié)
gulp.task("env", (cb) => {
    // ...
});

// 開發(fā)調(diào)試
gulp.task("dev", ["env"], (cb) => {
    exec("electron app --debug", (err) => {
        if (err) return cb(err);
        cb();
    });
});

// 打包環(huán)節(jié)
gulp.task("pack",["env"], (cb) => {
    if (platform === "darwin") {
        // ...
    } else {
        // ...
    }
});

// 簽名環(huán)節(jié)
gulp.task("sign-pack", ["pack"], (cb) => {
    if (needSign) {
        if (platform === "win32" || platform === "win64") {
            // ...
        } else if (platform === "darwin") {
            // ...
        }
    } else {
        cb();
    }
});

// 構(gòu)建環(huán)節(jié)
gulp.task("build", ["sign-pack"], (cb) => {
    if (platform === "darwin") {
        // ...
    } else {
        // ...
    }
});

// 發(fā)行環(huán)節(jié)
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"
  }
// 可選命令行參數(shù):
//      sign: 是否簽名
//      platform: 系統(tǒng)平臺
//      arch: 系統(tǒng)位數(shù)

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/89589.html

相關(guān)文章

  • 前端每周清單第 53 期:Go 與 WebAssembly, React Suspense 演練,

    摘要:開發(fā)教程步步為營,掌握基礎(chǔ)技能發(fā)布機器學(xué)習(xí)速成課程為了幫助更多的人了解與學(xué)習(xí)機器學(xué)習(xí)相關(guān)的知識技能,發(fā)布了人工智能學(xué)習(xí)網(wǎng)站。更多相關(guān)內(nèi)容參考數(shù)據(jù)科學(xué)與機器學(xué)習(xí)實戰(zhàn)手冊。 showImg(https://segmentfault.com/img/remote/1460000013586587); 前端每周清單專注前端領(lǐng)域內(nèi)容,以對外文資料的搜集為主,幫助開發(fā)者了解一周前端熱點;分為新聞熱...

    lbool 評論0 收藏0
  • 基于electron制作個node壓縮圖片的桌面應(yīng)

    摘要:壓縮圖片桌面應(yīng)用基于制作一個壓縮圖片的桌面應(yīng)用下載地址項目源碼準(zhǔn)備工作我們來整理一下我們需要做什么壓縮圖片模塊獲取文件路徑桌面應(yīng)用生成壓縮圖片我們需要使用這個庫來壓縮圖片,這里我們把這個庫封裝成壓縮模塊。 壓縮圖片桌面應(yīng)用imagemin-electron 基于electron制作一個node壓縮圖片的桌面應(yīng)用 下載地址:https://github.com/zenoslin/imag...

    bigdevil_s 評論0 收藏0
  • Electron,玩玩具的心態(tài)開始,打造款越來越優(yōu)秀的桌面客戶端產(chǎn)品

    摘要:首發(fā)于酷家樂前端博客標(biāo)題是我以第一視角基于開發(fā)客戶端產(chǎn)品的體驗,我將在之后分一系列文章向有興趣的朋友一步一步介紹我是怎么從玩玩具的心態(tài)開始接觸到去開發(fā)客戶端產(chǎn)品,最后隨著業(yè)務(wù)和功能的復(fù)雜度提升再不斷地優(yōu)化客戶端。 首發(fā)于酷家樂前端博客 標(biāo)題是我以第一視角基于 Electron 開發(fā)客戶端產(chǎn)品的體驗,我將在之后分一系列文章向有興趣的朋友一步一步介紹我是怎么從玩玩具的心態(tài)開始接觸 Ele...

    Markxu 評論0 收藏0
  • VS Code上手與超實插件安利

    摘要:軟件跨平臺支持以及,運行流暢,可謂是微軟的良心之作微軟有這個宇宙最強,自然也不會弱宇宙最強編輯器說到代碼編輯器,我們有必要提一提還有。 原文鏈接:VS Code上手與超實用插件安利 工欲善其事必先利其器 Visual Studio Code (簡稱 VS Code / VSC) 是一款免費開源的現(xiàn)代化輕量級代碼編輯器,支持幾乎所有主流的開發(fā)語言的語法高亮、智能代碼補全、自定義熱鍵、括號...

    miracledan 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<