前言
本文包含打包
、自動更新
、簡易API
、除錯
、程式通訊
等相關知識點,內容較多,可能會引起不適,請酌情檢視(手動滑稽)。
electron
簡介
electron是由Github開發,是一個用Html、css、JavaScript來構建桌面應用程式的開源庫,可以打包為Mac、Windows、Linux系統下的應用。
electron是一個執行時環境,包含Node和Chromium,可以理解成把web應用執行在node環境中
結構
electron主要分為主程式和渲染程式,關係如下圖
electron執行package.json
中的main
欄位標明指令碼的程式稱為主程式
在主程式建立web頁面來展示使用者頁面,一個electron有且只有一個主程式
electron使用Chromium來展示web頁面,每個頁面執行在自己的渲染程式
中
快速開始
接下來,讓程式碼來發聲,雷打不動的hello world
建立資料夾,並執行npm init -y
,生成package.json
檔案,下載electron
模組並新增開發依賴
mkdir electron_hello && cd electron_hello && npm init -y && npm i electron -D
複製程式碼
下載速度過慢或失敗,請嘗試使用cnpm,安裝方式如下
# 下載cnpm
npm install -g cnpm --registry=https://registry.npm.taobao.org
# 下載electron
cnpm i electron -D
複製程式碼
建立index.js,並寫入以下內容
const {app, BrowserWindow} = require('electron')
// 建立全域性變數並在下面引用,避免被GC
let win
function createWindow () {
// 建立瀏覽器視窗並設定寬高
win = new BrowserWindow({ width: 800, height: 600 })
// 載入頁面
win.loadFile('./index.html')
// 開啟開發者工具
win.webContents.openDevTools()
// 新增window關閉觸發事件
win.on('closed', () => {
win = null // 取消引用
})
}
// 初始化後 呼叫函式
app.on('ready', createWindow)
// 當全部視窗關閉時退出。
app.on('window-all-closed', () => {
// 在 macOS 上,除非使用者用 Cmd + Q 確定地退出,
// 否則絕大部分應用及其選單欄會保持啟用。
if (process.platform !== 'darwin') {
app.quit()
}
})
app.on('activate', () => {
// 在macOS上,當單擊dock圖示並且沒有其他視窗開啟時,
// 通常在應用程式中重新建立一個視窗。
if (win === null) {
createWindow()
}
})
複製程式碼
建立index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Hello World!</title>
</head>
<body>
<h1 id="h1">Hello World!</h1>
We are using node
<script>
document.write(process.versions.node)
</script>
Chrome
<script>
document.write(process.versions.chrome)
</script>,
and Electron
<script>
document.write(process.versions.electron)
</script>
</body>
</html>
複製程式碼
最後,修改packge.json
中的main欄位,並新增start命令
{
...
main:'index.js',
scripts:{
"start": "electron ."
}
}
複製程式碼
執行npm run start
後,就會彈出我們的應用來。
除錯
我們知道electron有兩個程式,主程式和渲染程式,開發過程中我們需要怎麼去除錯它們呢?老太太吃柿子,我們們撿軟的來
渲染程式
BrowserWindow 用來建立和控制瀏覽器視窗,我們呼叫它的例項上的API即可
win = new BrowserWindow({width: 800, height: 600})
win.webContents.openDevTools() // 開啟除錯
複製程式碼
除錯起來是和Chrome是一樣的,要不要這麼酸爽
主程式
使用VSCode進行除錯
使用VSCode開啟專案,點選除錯按鈕
點選除錯後的下拉框
選擇新增配置,選擇node
此時會把預設的除錯配置開啟,大概長這樣
什麼?你的不是,不是的話,就直接把下面的複製並替換你的配置
差不多這麼辦,那就把configurations
裡面第二項複製到你的configurations
配置裡面,第一個配置是用來除錯node的
{
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "啟動程式",
"program": "${workspaceFolder}/main.js"
},
{
"name": "Debug Main Process",
"type": "node",
"request": "launch",
"cwd": "${workspaceFolder}",
"runtimeExecutable": "${workspaceFolder}/node_modules/.bin/electron",
"windows": {
"runtimeExecutable": "${workspaceFolder}/node_modules/.bin/electron.cmd"
},
"args" : ["."]
}
]
}
複製程式碼
可以看到${workspaceFolder}
,這是關於VSCode的變數,用來表示當前開啟的資料夾的路徑
修改完配置後,我們除錯皮膚,選擇我們剛才配置的
在程式碼中標記需要除錯的地方,然後點選綠色的小三角,就可以愉快的除錯了
程式通訊
在Electron中, GUI 相關的模組 (如 dialog、menu 等) 僅在主程式中可用, 在渲染程式中不可用。 為了在渲染程式中使用它們, ipc 模組是向主程式傳送程式間訊息所必需的,以下介紹幾種程式間通訊的方法。
哥倆好
ipcMain和ipcRenderer是兩個好基友,通過這兩個模組可以實現程式的通訊。
-
ipcMain 在主程式中使用,用來處理渲染程式(網頁)傳送的同步和非同步的資訊
-
ipcRenderer 在渲染程式中使用,用來傳送同步或非同步的資訊給主程式,也可以用來接收主程式的回覆資訊。
以上兩個模組的通訊,可以理解成釋出訂閱模式
,接下來,我們看下它們具體的使用方法
主程式
const {ipcMain} = require('electron')
// 監聽渲染程式發來的事件
ipcMain.on('something', (event, data) => {
event.sender.send('something1', '我是主程式返回的值')
})
複製程式碼
渲染程式
const { ipcRenderer} = require('electron')
// 傳送事件給主程式
ipcRenderer.send('something', '傳輸給主程式的值')
// 監聽主程式發來的事件
ipcRenderer.on('something1', (event, data) => {
console.log(data) // 我是主程式返回的值
})
複製程式碼
以上程式碼使用的是非同步傳輸訊息,electron也提供了同步傳輸的API。
傳送同步訊息將會阻塞整個渲染程式,你應該避免使用這種方式 - 除非你知道你在做什麼。
切忌用 ipc 傳遞大量的資料,會有很大的效能問題,嚴重會讓你整個應用卡住。
remote模組
使用 remote 模組, 你可以呼叫 main 程式物件的方法, 而不必顯式傳送程式間訊息。
const { dialog } = require('electron').remote
dialog.showMessageBox({type: 'info', message: '在渲染程式中直接使用主程式的模組'})
複製程式碼
webContents
webContents負責渲染和控制網頁, 是 BrowserWindow 物件的一個屬性, 我們使用send方法向渲染器程式傳送非同步訊息。
主程式
const {app, BrowserWindow} = require('electron')
let win
app.on('ready', () => {
win = new BrowserWindow({width: 800, height: 600})
// 載入頁面
win.loadURL('./index.html')
// 導航完成時觸發,即選項卡的旋轉器將停止旋轉,並指派onload事件後。
win.webContents.on('did-finish-load', () => {
// 傳送資料給渲染程式
win.webContents.send('something', '主程式傳送到渲染程式的資料')
})
})
複製程式碼
渲染程式
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<script>
require('electron').ipcRenderer.on('something', (event, message) => {
console.log(message) // 主程式傳送到渲染程式的資料
})
</script>
</body>
</html>
複製程式碼
渲染程式資料共享
更多情況下,我們使用HTML5 API實現,如localStorage、sessionStorage等,也可以使用electron的IPC機制實現
主程式
global.sharedObject = {
someProperty: 'default value'
}
複製程式碼
渲染程式
第一個頁面
require('electron').remote.getGlobal('sharedObject').someProperty = 'new value'
複製程式碼
第二個頁面
console.log(require('electron').remote.getGlobal('sharedObject').someProperty) // new value
複製程式碼
總結
以上四個方法均可實現主程式和渲染程式的通訊,可以發現使用remote
模組是最簡單的,渲染程式程式碼中可以直接使用electron
模組
常用模組
快捷鍵與選單
本地快捷鍵
只有在應用聚焦的時候才會觸發,主要程式碼如下
官方文件親測沒有效果
const { Menu, MenuItem } = require('electron')
const menu = new Menu()
menu.append(new MenuItem({
label: '自定義快捷鍵',
submenu: [
{
label: '測試',
accelerator: 'CmdOrCtrl+P',
click: () => {
console.log('我是本地快捷鍵')
}
}
]
}))
Menu.setApplicationMenu(menu)
複製程式碼
全域性快捷鍵
註冊全域性,無論應用是否聚焦,都會觸發,使用globalShortcut
來註冊, 主要程式碼如下,
const {globalShortcut, dialog} = require('electron')
app.on('read', () => {
globalShortcut.register('CmdOrCtrl+1', () => {
dialog.showMessageBox({
type: 'info',
message: '你按下了全域性註冊的快捷鍵'
})
})
})
複製程式碼
顯示如下,使用了dialog
模組
上下文選單
上下文選單就是我們點選右鍵的時候顯示的選單, 設定在渲染程式裡面
主要程式碼如下
const remote = require('electron').remote; // 通過remote模組使用主程式才能使用的模組
const Menu = remote.Menu;
const MenuItem = remote.MenuItem;
var menu = new Menu();
menu.append(new MenuItem({ label: 'MenuItem1', click: function() { console.log('item 1 clicked'); } }));
menu.append(new MenuItem({ type: 'separator' }));
menu.append(new MenuItem({ label: 'MenuItem2', type: 'checkbox', checked: true }));
window.addEventListener('contextmenu', (e) => {
e.preventDefault();
menu.popup(remote.getCurrentWindow());
}, false);
複製程式碼
應用選單
上文中我們通過Menu
模組建立了本地快捷鍵,應用選單也是用Menu
模組,我們看到長得好像一樣,其實實現起來也差不多,我們這裡使用建立模版的方式來實現,主要程式碼如下:
const {app, Menu} = require('electron')
const template = [
{
label: '操作',
submenu: [{
label: '複製',
accelerator: 'CmdOrCtrl+C',
role: 'copy'
}, {
label: '貼上',
accelerator: 'CmdOrCtrl+V',
role: 'paste'
}, {
label: '重新載入',
accelerator: 'CmdOrCtrl+R',
click: function (item, focusedWindow) {
if (focusedWindow) {
// on reload, start fresh and close any old
// open secondary windows
if (focusedWindow.id === 1) {
BrowserWindow.getAllWindows().forEach(function (win) {
if (win.id > 1) {
win.close()
}
})
}
focusedWindow.reload()
}
}
}]
},
{
label: '載入網頁',
submenu: [
{
label: '優酷',
accelerator: 'CmdOrCtrl+P',
click: () => { console.log('time to print stuff') }
},
{
type: 'separator'
},
{
label: '百度',
}
]
}
]
if (process.platform === 'darwin') {
const name = electron.app.getName()
template.unshift({
label: name,
submenu: [{
label: `關於 ${name}`,
role: 'about'
}, {
type: 'separator'
}, {
label: '服務',
role: 'services',
submenu: []
}, {
type: 'separator'
}, {
label: `隱藏 ${name}`,
accelerator: 'Command+H',
role: 'hide'
}, {
label: '隱藏其它',
accelerator: 'Command+Alt+H',
role: 'hideothers'
}, {
label: '顯示全部',
role: 'unhide'
}, {
type: 'separator'
}, {
label: '退出',
accelerator: 'Command+Q',
click: function () {
app.quit()
}
}]
})
}
app.on('read', () => {
const menu = Menu.buildFromTemplate(template);
Menu.setApplicationMenu(menu);
})
複製程式碼
系統托盤
主要程式碼
const { app, Tray } = require('electron')
/* 省略其他程式碼 */
let tray;
app.on('ready', () => {
tray = new Tray(__dirname + '/build/icon.png');//系統托盤圖示
const contextMenu = Menu.buildFromTemplate([ // 選單項
{label: '顯示', type: 'radio', click: () => {win.show()}},
{label: '隱藏', type: 'radio', click: () => {win.hide()}},
])
// tray.on('click', () => { // 滑鼠點選事件最好和選單隻設定一種
// win.isVisible() ? win.hide() : win.show()
// })
tray.setToolTip('This is my application.') // 滑鼠放上時候的提示
tray.setContextMenu(contextMenu) // 應用選單項
})
複製程式碼
模組一覽
開啟頁面
shell
主程式開啟頁面,會呼叫預設的瀏覽器開啟頁面,使用shell
模組
const { app,shell } = require('electron')
app.on('ready', () => {
shell.openExternal('github.com')
})
複製程式碼
應用啟動後就會使用預設瀏覽器開啟github
頁面
window.open
渲染程式中使用,當前應用開啟頁面
window.open('github.com')
複製程式碼
webview
使用webview
可以在一個獨立的 frame 和程式裡顯示外部 web 內容
直接在index.html中使用即可
<webview id="foo" src="https://www.github.com/" style="display:inline-flex; width:640px; height:480px"></webview>
複製程式碼
模組一覽
QA
其他應用模組和API請下載
模版
electron-forge
electron-forge包含vue
、react
、Angular
等開箱即用的模版。
npm i -g electron-forge
electron-forge init my-app template=react
cd my-app
npm run start
複製程式碼
目錄結構如下
.compilerc
是electron-compile
的配置檔案,和.babelrc
類似
electron-compile是一種轉換規則,支援在應用程式中編譯js和css
electron-react-boilerplate
如果你不希望任何工具,而想要簡單地從一個模板開始構建,react-electron模版可以瞭解下。
electron-react-boilerplate 是雙package.json
配置專案, 目錄如下
electron-vue
electron-vue充分利用 vue-cli 作為腳手架工具,加上擁有 vue-loader 的 webpack、electron-packager 或是 electron-builder,以及一些最常用的外掛,如vue-router、vuex 等等。
目錄結構如下
更多模版
更多模版請訪問
打包
怎麼將我們開發好的應用打包成.app
或.exe
的執行檔案,這就涉及到了重要的打包環節,
這裡使用electron-quick-start專案進行打包
目前,主流的打包工具有兩個electron-packager和electron-builder
Mac打包window安裝包需下載wine
brew install wine
如果有丟失元件,按照報錯資訊進行下載即可
electron-packager
electron-packager把你的electron打包成可執行檔案(.app, .exe, etc)
執行npm i electron-packager -D
進行安裝
electron-packager .
快速打包
打包詳解
electron-packager <sourcedir> <appname> --platform=<platform> --arch=<arch> --out=out --icon=assets/app.ico --asar --overwrite --ignore=.git
複製程式碼
- sourcedir 專案入口 根據package.json的目錄
- appname 包名
- platform 構建平臺 包含
darwin, linux, mas, win32 all
- arch 構建架構 包含
ia32,x64,armv7l,arm64
- out 打包後的地址
- icon 打包圖示
- asar 是否生成app.asar, 不然就是自己的原始碼
- overwrite 覆蓋上次打包
- ignore 不進行打包的檔案
第一次打包需要下載二進位制的包耗時會久一些,以後走快取就快的多了。
打包後目錄為
其中electron-quick-start
可以直接開啟執行
快取地址
- Mac
~/Library/Caches/electron/
- Windows
$LOCALAPPDATA/electron/Cache
or~/AppData/Local/electron/Cache/
- Linux
$XDG_CACHE_HOME
or~/.cache/electron/
electron-builder
electron-builder是一個完整的解決方案,對於macos、windows、linux下的electron app,它可以提供打包及構建的相關功能。同時,它還提供開箱即用的“自動更新”功能支援
npm i electron-builder -D
下載
electron-builder
打包
出現如下
同樣是第一次打包時間會比較長,彆著急,靜候佳音。
會預設打包在dist
目錄,包含如下
mac
檔案裡有執行時檔案
,預設使用asar方式進行打包
electron-builder --dir
只會生成包檔案,對測試有用
坑坑坑
第一次打包的時候會比較慢,如果你和我手欠直接退出了,再次打包的時候,恭喜你,出錯了。報錯資訊如下
• electron-builder version=20.28.2
• loaded configuration file=package.json ("build" field)
• description is missed in the package.json appPackageFile=/Users/shisan/Documents/self/you-app/package.json
• writing effective config file=dist/builder-effective-config.yaml
• no native production dependencies
• packaging platform=darwin arch=x64 electron=2.0.7 appOutDir=dist/mac
• cannot unpack electron zip file, will be re-downloaded error=zip: not a valid zip file
⨯ zip: not a valid zip file
Error: /Users/shisan/Documents/self/you-app/node_modules/app-builder-bin/mac/app-builder exited with code 1
at ChildProcess.childProcess.once.code (/Users/shisan/Documents/self/you-app/node_modules/builder-util/src/util.ts:254:14)
at Object.onceWrapper (events.js:272:13)
at ChildProcess.emit (events.js:180:13)
at maybeClose (internal/child_process.js:936:16)
at Process.ChildProcess._handle.onexit (internal/child_process.js:220:5)
From previous event:
at unpack (/Users/shisan/Documents/self/you-app/node_modules/app-builder-lib/out/electron/ElectronFramework.js:191:18)
at Object.prepareApplicationStageDirectory (/Users/shisan/Documents/self/you-app/node_modules/app-builder-lib/src/electron/ElectronFramework.ts:148:50)
at /Users/shisan/Documents/self/you-app/node_modules/app-builder-lib/src/platformPackager.ts:179:21
at Generator.next (<anonymous>)
From previous event:
at MacPackager.doPack (/Users/shisan/Documents/self/you-app/node_modules/app-builder-lib/src/platformPackager.ts:166:165)
at /Users/shisan/Documents/self/you-app/node_modules/app-builder-lib/src/macPackager.ts:88:63
at Generator.next (<anonymous>)
From previous event:
at MacPackager.pack (/Users/shisan/Documents/self/you-app/node_modules/app-builder-lib/src/macPackager.ts:80:95)
at /Users/shisan/Documents/self/you-app/node_modules/app-builder-lib/src/packager.ts:376:24
at Generator.next (<anonymous>)
at xfs.stat (/Users/shisan/Documents/self/you-app/node_modules/fs-extra-p/node_modules/fs-extra/lib/mkdirs/mkdirs.js:56:16)
at /Users/shisan/Documents/self/you-app/node_modules/graceful-fs/polyfills.js:287:18
at FSReqWrap.oncomplete (fs.js:171:5)
From previous event:
at Packager.doBuild (/Users/shisan/Documents/self/you-app/node_modules/app-builder-lib/src/packager.ts:344:39)
at /Users/shisan/Documents/self/you-app/node_modules/app-builder-lib/src/packager.ts:314:57
at Generator.next (<anonymous>)
at /Users/shisan/Documents/self/you-app/node_modules/graceful-fs/graceful-fs.js:99:16
at /Users/shisan/Documents/self/you-app/node_modules/graceful-fs/graceful-fs.js:43:10
at FSReqWrap.oncomplete (fs.js:153:20)
From previous event:
at Packager._build (/Users/shisan/Documents/self/you-app/node_modules/app-builder-lib/src/packager.ts:285:133)
at /Users/shisan/Documents/self/you-app/node_modules/app-builder-lib/src/packager.ts:281:23
at Generator.next (<anonymous>)
From previous event:
at Packager.build (/Users/shisan/Documents/self/you-app/node_modules/app-builder-lib/src/packager.ts:238:14)
at build (/Users/shisan/Documents/self/you-app/node_modules/app-builder-lib/src/index.ts:58:28)
at build (/Users/shisan/Documents/self/you-app/node_modules/electron-builder/src/builder.ts:227:10)
at then (/Users/shisan/Documents/self/you-app/node_modules/electron-builder/src/cli/cli.ts:42:48)
at runCallback (timers.js:763:18)
at tryOnImmediate (timers.js:734:5)
at processImmediate (timers.js:716:5)
From previous event:
at Object.args [as handler] (/Users/shisan/Documents/self/you-app/node_modules/electron-builder/src/cli/cli.ts:42:48)
at Object.runCommand (/Users/shisan/Documents/self/you-app/node_modules/yargs/lib/command.js:237:44)
at Object.parseArgs [as _parseArgs] (/Users/shisan/Documents/self/you-app/node_modules/yargs/yargs.js:1085:24)
at Object.get [as argv] (/Users/shisan/Documents/self/you-app/node_modules/yargs/yargs.js:1000:21)
at Object.<anonymous> (/Users/shisan/Documents/self/you-app/node_modules/electron-builder/src/cli/cli.ts:25:28)
at Module._compile (internal/modules/cjs/loader.js:654:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:665:10)
at Module.load (internal/modules/cjs/loader.js:566:32)
at tryModuleLoad (internal/modules/cjs/loader.js:506:12)
at Function.Module._load (internal/modules/cjs/loader.js:498:3)
at Function.Module.runMain (internal/modules/cjs/loader.js:695:10)
at startup (internal/bootstrap/node.js:201:19)
at bootstrapNodeJSCore (internal/bootstrap/node.js:516:3)
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! you-app@1.0.0 dist: `electron-builder --mac --x64`
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the you-app@1.0.0 dist script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.
npm ERR! A complete log of this run can be found in:
npm ERR! /Users/shisan/.npm/_logs/2018-08-22T06_28_55_102Z-debug.log
✖ Error building interactive interface
複製程式碼
問題是在下載.zip包的時候,中斷了操作,以後所有執行打包的時候,找不到那個檔案(或者是殘缺的檔案)就報錯了,需要手動清除下快取 快取路徑在~/Library/Caches/electron/
常用引數
electron-builder
配置檔案寫在package.json
中的build
欄位中
"build": {
"appId": "com.example.app", // 應用程式id
"productName": "測試", // 應用名稱
"directories": {
"buildResources": "build", // 構建資源路徑預設為build
"output": "dist" // 輸出目錄 預設為dist
},
"mac": {
"category": "public.app-category.developer-tools", // 應用程式類別
"target": ["dmg", "zip"], // 目標包型別
"icon": "build/icon.icns" // 圖示的路徑
},
"dmg": {
"background": "build/background.tiff or build/background.png", // 背景影像的路徑
"title": "標題",
"icon": "build/icon.icns" // 圖示路徑
},
"win": {
"target": ["nsis","zip"] // 目標包型別
}
}
複製程式碼
使用electron-package或者electron-builder進行打包,就不需要asar手動打包了,這兩個工具已經整合進去了,以下內容只做瞭解即可
asar
簡介
asar是一種將多個檔案合併成一個檔案的類 tar 風格的歸檔格式。 Electron 可以無需解壓整個檔案,即可從其中讀取任意檔案內容。
使用
上面我們看到使用electron-package
進行打包的時候,可以新增--asar
引數, 它的作用就是將我們的原始碼打包成asar格式, 不使用的話就是我們的原始碼。
依舊使用electron-quick-start
模版, 使用electron-package
進行打包
打包後目錄中選擇應用,右鍵顯示包內容
依次開啟路徑 Contents -> Resources -> app
就可以看到我們的原檔案了
使用electron-package . --asar
進行打包,再次檢視app中的原始檔已經打包成asar
檔案了
常用命令
- 打包
asar pack|p <dir> <ouput>
複製程式碼
如 asar ./ app.asar
- 解壓
asar extract|e <archive> <output>
複製程式碼
如 asar e app.asar ./
事實上,就算使用了asar打包方式,我們的原始碼依舊是暴露的,使用asar解壓仍然能輕易解密,使用webpack將程式碼壓縮混淆才是王道。
自動更新
我們使用electron-builder和electron-updater來完成應用的自動更新, 並不是electron裡面的autoUpdater
流程
建立證照
無論使用哪種方式進行自動更新,程式碼簽名是必不可少的,我們使用建立本地的證照來進行測試自動更新
在其他中找到鑰匙串訪問
依次選擇 鑰匙串訪問
-> 證照助理
-> 建立證照
,建立一個新的證照
起個響亮的名字,證照型別選擇程式碼簽名
,然後點選建立
建立完成後在鑰匙串中找到它
右鍵,選擇更改信任設定,將信任設定成始終信任
程式碼簽名
-
沒有程式碼簽名
-
程式碼簽名
設定環境變數
執行sudo vi ~/.bash_profile
, 新增變數
export CSC_NAME="electron_update"
複製程式碼
執行source ~/.bash_profile
過載變數檔案
執行echo $CSC_NAME
檢視變數有沒有生效,沒有生效的話,執行上面命令過載檔案
多次過載,依舊獲取不到變數,直接退出終端,再次登入終端即可
打包程式碼
使用electron-builder
進行打包,專案使用electron-quick-start
我們先新增打包的build
配置, 在package.json
中新增
"build": {
"appId": "org.electron.com",
"publish": [
{
"provider": "generic",
"url": "http://172.28.86.36:8080/"
}
],
"productName": "我的",
"directories": {
"output": "dist"
},
"mac": {
"target": [
"dmg",
"zip"
]
},
"win": {
"target": [
"nsis",
"zip"
]
},
"dmg": {
"backgroundColor": "red",
"title": "made",
"contents": [
{
"x": 400,
"y": 128,
"type": "link",
"path": "/Applications"
}
]
}
}
複製程式碼
前面,我們說過了build
欄位中各個引數的含義,這裡就不贅述了,這裡新增了publish
欄位,它是配置我們自動更新的資訊,url是伺服器地址。
伺服器我們可以使用http-server模組, 快速搭建一個靜態伺服器
執行打包後,輸出
主要看下latest-mac.yml
檔案
可以看到version
欄位,用來表明當前應用的版本,那這個欄位是從哪來的呢?
沒錯就是我們的package.json
檔案中version
欄位
自動更新
在主程式中寫入以下程式碼
const {app, BrowserWindow, ipcMain} = require('electron')
const { autoUpdater } = require('electron-updater')
// 本地伺服器地址
const feedURL = `http://172.28.82.40:8080/`
let mainWindow
function createWindow () { // 建立視窗
mainWindow = new BrowserWindow({width: 800, height: 600})
mainWindow.loadFile('index.html')
mainWindow.on('closed', function () {
mainWindow = null
})
}
app.on('ready', createWindow)
app.on('window-all-closed', function () {
if (process.platform !== 'darwin') {
app.quit()
}
})
app.on('activate', function () {
if (mainWindow === null) {
createWindow()
}
})
// 監聽自定義update事件
ipcMain.on('update', (e, arg) => {
checkForUpdate()
})
const checkForUpdate = () => {
// 設定檢查更新的 url,並且初始化自動更新
autoUpdater.setFeedURL(feedURL)
// 監聽錯誤
autoUpdater.on('error', message => {
sendUpdateMessage('err', message)
})
// 當開始檢查更新的時候觸發
autoUpdater.on('checking-for-update', message => {
sendUpdateMessage('checking-for-update', message);
})
//
autoUpdater.on('download-progress', function(progressObj) {
sendUpdateMessage('downloadProgress', progressObj);
});
// 更新下載完成事件
autoUpdater.on('update-downloaded', function(event, releaseNotes, releaseName, releaseDate, updateUrl, quitAndUpdate) {
ipcMain.on('updateNow', (e, arg) => {
autoUpdater.quitAndInstall();
});
sendUpdateMessage('isUpdateNow');
});
// 向服務端查詢現在是否有可用的更新
autoUpdater.checkForUpdates();
}
// 傳送訊息觸發message事件
function sendUpdateMessage(message, data) {
mainWindow.webContents.send('message', { message, data });
}
複製程式碼
然後更改我們的渲染程式的程式碼
const {ipcRenderer} = require ('electron');
const button = document.querySelector('#button')
const ul = document.querySelector('ul')
button.onclick = () => {
ipcRenderer.send('update')
}
ipcRenderer.on('message', (event, {message,data }) => {
let li = document.createElement('li')
li.innerHTML = message + " <br>data:" + JSON.stringify(data) +"<hr>";
ul.appendChild(li)
if (message === 'isUpdateNow') {
if (confirm('是否現在更新?')) {
ipcRenderer.send('updateNow');
}
}
})
複製程式碼
頁面程式碼
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Hello World!</title>
</head>
<body>
<h1>Hello World!</h1>
<h1>當前版本是1.0.3</h1>
<ul>
<li>生命週期過程展示</li>
</ul>
<button id="button">點選我</button>
<script>
// You can also require other files to run in this process
require('./renderer.js')
</script>
</body>
</html>
複製程式碼
這裡使用按鈕點選事件觸發更新操作。
直接打包,安裝這個1.0.3
的版本。
然後將package.json
的檔案中的version
欄位更改成1.0.5
,將index.html的更改成1.0.5
,進行打包。
隨便找個地方建立個資料夾,如test
將打包的檔案移動到test
中,執行http-server ./
,搭建服務
當我們點選按鈕的時候,就可以進行更新應用了,如下圖
點選ok後,靜候片刻,更新完後就開啟了最新版本的應用
以上就完成了electron的自動更新。
最後
本文所有程式碼請戳github瞭解更多
ocr相關demo借(chao)鑑(xi)了Jartto
的electron-ocr
,下文有連結。
參考
Electron 打包Mac安裝包程式碼簽名問題解決方案
文中所說簽名均需要是買了Apple開發者賬號的。