electron程序保護措施(崩潰監控,開機自啓,托盤關閉)

image

在某種情況下,我們可能希望我們的客戶端程序儘可能連續不斷的運行在我們的系統中,並保持穩定。

以下幾種方式可以幫助我們做到這一點:

1.崩潰監控

electron爲我們提供了監聽程序崩潰的事件:

Event: 'crashed'
返回:

event Event
killed Boolean
當渲染進程崩潰或被結束時觸發

此事件是用來家庭渲染進程崩潰的,但是當主進程意外崩潰時也會觸發該事件。

在監測到程序崩潰後,我們要讓程序重新啓動,此時我們要首先判斷window對象是否被銷燬,也就是主進程是否被殺死,還是渲染進程崩潰,同時作出不同的處理。

當mainWin被銷燬時我們直接重啓整個應用,使用如下api:

app.relaunch([options])
options Object (可選)

args String
execPath String (可選)
從當前實例退出,重啓應用。

默認情況下,新的實例會和當前實例使用相同的工作目錄以及命令行參數。 當設置了 args 參數時, args 將作爲命令行參數傳遞。 當設置了 execPath ,execPath 將被執行以重新啓動,而不是當前的應用程序。

請注意, 此方法在執行時不會退出當前的應用程序, 你需要在調用 app.relaunch 方法後再執行 app. quit 或者 app.exit 來讓應用重啓。

只是渲染進程崩潰,我們只需將其他窗體銷燬,然後重新load我們的主窗口。

崩潰重啓邏輯:

  if (mainWin.isDestroyed()) {
    app.relaunch();
    app.exit(0);
  } else {
    BrowserWindow.getAllWindows().forEach((w) => {
      if (w.id !== mainWin.id) w.destroy();
    });
    mainWin.reload();
  }

當然,我們還要記錄一下程序的崩潰日誌,我們要確保日誌接口發出成功後再重啓我們的程序:

下面是程序崩潰後的完整邏輯:

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()來進行測試,或者直接在任務管理器殺掉我們的進程進行測試。

2.開機自啓

開機自啓是保證我們的程序能長時間在機器上運行很重要的一點。

電腦上有很多程序都設置了開機自啓動,比如qq,微信,迅雷等,他們都是通過修改註冊表來實現的,我們可以看一下註冊表 \\Software\\Microsoft\\Windows\\CurrentVersion\\Run:

image

所以我們也要將我們程序的路徑寫到這裏。

發現了一個非常好的寫註冊表的模塊,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('開機自動啓設置'); });
    }
  });
}

執行完程序之後,再看註冊表,發現我們程序的路徑已經寫進去了:

image

然後電腦重啓後你的程序就自動啓動了。

3.托盤關閉

向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);
      }
    })
  }

以上這些操作爲我們的程序又增加了好幾層的防護措施,我們的程序就不會那麼輕而易舉的掛掉啦!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章