在某種狀況下,咱們可能但願咱們的客戶端程序儘量接二連三的運行在咱們的系統中,並保持穩定。web
如下幾種方式能夠幫助咱們作到這一點:api
electron爲咱們提供了監聽程序崩潰的事件:微信
Event: 'crashed' 返回: event Event killed Boolean 當渲染進程崩潰或被結束時觸發
此事件是用來家庭渲染進程崩潰的,可是當主進程意外崩潰時也會觸發該事件。app
在監測到程序崩潰後,咱們要讓程序從新啓動,此時咱們要首先判斷window對象是否被銷燬,也就是主進程是否被殺死,仍是渲染進程崩潰,同時做出不一樣的處理。electron
當mainWin被銷燬時咱們直接重啓整個應用,使用以下api:ide
app.relaunch([options]) options Object (可選) args String execPath String (可選) 從當前實例退出,重啓應用。 默認狀況下,新的實例會和當前實例使用相同的工做目錄以及命令行參數。 當設置了 args 參數時, args 將做爲命令行參數傳遞。 當設置了 execPath ,execPath 將被執行以從新啓動,而不是當前的應用程序。 請注意, 此方法在執行時不會退出當前的應用程序, 你須要在調用 app.relaunch 方法後再執行 app. quit 或者 app.exit 來讓應用重啓。
只是渲染進程崩潰,咱們只需將其餘窗體銷燬,而後從新load咱們的主窗口。oop
崩潰重啓邏輯:測試
if (mainWin.isDestroyed()) { app.relaunch(); app.exit(0); } else { BrowserWindow.getAllWindows().forEach((w) => { if (w.id !== mainWin.id) w.destroy(); }); mainWin.reload(); }
固然,咱們還要記錄一下程序的崩潰日誌,咱們要確保日誌接口發出成功後再重啓咱們的程序:ui
下面是程序崩潰後的完整邏輯:spa
import { BrowserWindow, app, dialog} from 'electron'; const mainWindow = BrowserWindow.fromId(global.mainId); mainWindow.webContents.on('crashed', () => { const options = { type: 'error', title: '進程崩潰了', message: '這個進程已經崩潰.', buttons: ['重載', '退出'], }; recordCrash().then(() => { dialog.showMessageBox(options, (index) => { if (index === 0) reloadWindow(mainWindow); else app.quit(); }); }).catch((e) => { console.log('err', e); }); }) function recordCrash() { return new Promise(resolve => { // 崩潰日誌請求成功.... resolve(); }) } function reloadWindow(mainWin) { if (mainWin.isDestroyed()) { app.relaunch(); app.exit(0); } else { BrowserWindow.getAllWindows().forEach((w) => { if (w.id !== mainWin.id) w.destroy(); }); mainWin.reload(); } }
寫好代碼以後,咱們能夠直接在控制檯輸入 process.crash()
來進行測試,或者直接在任務管理器殺掉咱們的進程進行測試。
開機自啓是保證咱們的程序能長時間在機器上運行很重要的一點。
電腦上有不少程序都設置了開機自啓動,好比qq,微信,迅雷等,他們都是經過修改註冊表來實現的,咱們能夠看一下注冊表 \\Software\\Microsoft\\Windows\\CurrentVersion\\Run
:
因此咱們也要將咱們程序的路徑寫到這裏。
發現了一個很是好的寫註冊表的模塊,winreg
注意mac不能使用這個模塊,因此首先要判斷是否爲window再引用這個模塊。
藉助這個模塊咱們能夠很是簡單的修改註冊表:
const WinReg = require('winreg'); const startOnBoot = { enableAutoStart: function (name, file, callback) { var key = getKey(); key.set(name, WinReg.REG_SZ, file, callback || noop); }, disableAutoStart: function (name, callback) { var key = getKey(); key.remove(name, callback || noop); }, getAutoStartValue: function (name, callback) { var key = getKey(); key.get(name, function (error, result) { if (result) { callback(result.value); } else { callback(null, error); } }); } }; function noop() { } const RUN_LOCATION = '\\Software\\Microsoft\\Windows\\CurrentVersion\\Run'; function getKey() { return new WinReg({ hive: WinReg.HKCU, //CurrentUser, key: RUN_LOCATION }); } export default function autoStart() { startOnBoot.getAutoStartValue('MY_CLIENT_AUTOSTART', function (value) { if (!value) { startOnBoot.enableAutoStart('MY_CLIENT_AUTOSTART', process.execPath, function () { console.log('開機自動啓設置'); }); } }); }
執行完程序以後,再看註冊表,發現咱們程序的路徑已經寫進去了:
而後電腦重啓後你的程序就自動啓動了。
向qq和微信同樣,有的時候咱們並不想讓用戶經過點關閉按鈕的時候就關閉程序,而是把程序最小化到托盤,在托盤上作真正的退出操做。
首先要監聽窗口的關閉事件,阻止用戶關閉操做的默認行爲。
mainWindow.on('close', (event) => { mainWindow.hide(); event.preventDefault(); });
然而這時你發現,這只是最小化了程序,任務欄里程序依然存在,咱們須要讓程序在任務欄裏也消失:
mainWindow.on('close', (event) => { mainWindow.hide(); mainWindow.setSkipTaskbar(true); event.preventDefault(); });
這時程序就再也找不到了,任務托盤中也沒有咱們的程序,因此咱們要先建立好任務托盤,並作好事件監聽:
function createTray() { const mainWindow = BrowserWindow.fromId(global.mainId); tray = new Tray(path.join(global.__dirname, 'icon.ico')); const contextMenu = Menu.buildFromTemplate([ { label: '退出', click: () => { mainWindow.destroy(); app.quit(); } }, ]) tray.setToolTip('個人客戶端') tray.setContextMenu(contextMenu) tray.on('click', () => { if (mainWindow.isVisible()) { mainWindow.hide(); mainWindow.setSkipTaskbar(false); } else { mainWindow.show(); mainWindow.setSkipTaskbar(true); } }) }
以上這些操做爲咱們的程序又增長了好幾層的防禦措施,咱們的程序就不會那麼垂手可得的掛掉啦!