electron程序保护措施(崩溃监控,开机自启,托盘关闭)

image

在某种状况下,咱们可能但愿咱们的客户端程序尽量接二连三的运行在咱们的系统中,并保持稳定。web

如下几种方式能够帮助咱们作到这一点:api

1.崩溃监控

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()来进行测试,或者直接在任务管理器杀掉咱们的进程进行测试。

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

以上这些操做为咱们的程序又增长了好几层的防御措施,咱们的程序就不会那么垂手可得的挂掉啦!

相关文章
相关标签/搜索