1、常见的导致 Electron 应用崩溃原因
1.1 、JavaScript 层可能导致的崩溃
1)传给 WebGL 渲染的ArrayBuffer,实际宽或高为零
2)图片宽或高为零,传给 Canvas 绘制
3)Electron 12 及以下版本,来自 node.js C++ add-on 层的 ArrayBuffer,必须复制一次,否则渲染进程会崩溃。相关 Bug 地址:https://github.com/electron/electron/issues/15538
1.2、设备访问权限
Mac 下未做摄像头、麦克风授权,直接访问时,可能导致 Electron 应用崩溃。针对此问题,可参照 腾讯云实时音视频 官网场景问题规避。
1.3、C++ 层导致的崩溃
存在 Node.js C++ add-on 相关的代码时,这一层导致应用程序崩溃的可能行极大,常见原因有:
1)空指针访问
2)数组越界
3)Node.js C++ add-on API 错误调用、参数错误等
2、Electron 应用崩溃处理方法
2.1、JavaScript 层导致崩溃
针对 JavaScritpt 导致崩溃,需要找到崩溃出现路径,一步步调试基本可以发现问题原因,做一些防御性编程就可以规避。
2.2、Node.js C++ add-on 层导致的崩溃
这一次导致的崩溃问题,一般比较难排查,特别是针对前端开发人员,这里给出的解决方案是:
(1)开起 Electron Crash Reporter 功能,获取崩溃堆栈,分析堆栈内容;
(2)监听 Electron crash 相关事件,记录crash 日志。
2.2.1、开启 Electron Crash Reporter
开起后,可以收集 Electron 应用的崩溃堆栈,Electron Crash Reporter 支持将崩溃堆栈上传到在线的第三方服务平台,用户也可以通过配置上传自己的服务器(服务端需要自己开发),也可以只生成崩溃堆栈文件在本地,用于排查崩溃问题。下面将只介绍如何生成崩溃堆栈文件到本地。
2.2.1.1、开启崩溃堆栈文件生成,并获取崩溃文件存放路径
需要在 main 进程的 JavaScript 代码中,在一开始的位置添加如下代码,开启 Electron Crash Reporter 捕获功能。
const { app, BrowserWindow, crashReporter, ipcMain, systemPreferences } = require('electron');
const path = require('path');
// 获取崩溃堆栈文件存放路径
let crashFilePath = '';
let crashDumpsDir = '';
try {
// electron 低版本
crashFilePath = path.join(app.getPath('temp'), app.getName() + ' Crashes');
console.log('————————crash path:', crashFilePath);
// electron 高版本
crashDumpsDir = app.getPath('crashDumps');
console.log('————————crashDumpsDir:', crashDumpsDir);
} catch (e) {
console.error('获取崩溃文件路径失败', e);
}
// 开启crash捕获
crashReporter.start({
productName: 'Your-Application-Name',
companyName: 'Your-Company-Name',
submitURL: 'https://www.xxx.com', // 上传到服务器的地址
uploadToServer: false, // 不上传服务器
ignoreSystemCrashHandler: false, // 不忽略系统自带的崩溃处理,为 true 时表示忽略,崩溃时不会生成崩溃堆栈文件
});
以上代码不能保证每次崩溃,都收集到崩溃堆栈,但如果崩溃较频繁,很可能在某次崩溃时生成,如果发现生成了崩溃堆栈,一定不要视而不见,对于偶现的崩溃问题,崩溃堆栈文件对定位排查问题很有帮助。
2.2.1.2、将崩溃堆栈文件存放目录写到渲染进程日志
通过安装包执行的应用,Electron 主进程的日志通常看不到或者不好查阅(可借助 Node.js 文件 API 写本地日志文件),可以将崩溃堆栈文件的存放路径打印到渲染进程的控制台,方便查询。实现方式参阅下方代码。
主进程 窗口加载完页面后,增加如下代码:
mainWindow.webContents.on('did-finish-load', function(event){
mainWindow.webContents.send('crash-file-path', `${crashFilePath} or ${crashDumpsDir}`);
});
渲染进程 preload 中增加如下代码:
const { ipcRenderer } = require('electron');
ipcRenderer.on('crash-file-path', (event, args) => {
console.warn('crash-file-path:', args);
});
崩溃文件示例及崩溃文件路径日志示例 如下图,崩溃文件可能在崩溃文件存放目录下的 new、completed、pending 目录下:
2.2.2、监听 Electron 渲染进程和 GPU 进程崩溃事件
Electron 提供了监听渲染进程和 GPU 进程崩溃的事件接口,监听这些事件,可以知道何时发生了崩溃,但崩溃的具体原因一般看不出来,需要获取崩溃堆栈的 dump 文件。
在 Electron main 进程的启动脚本,增加如下代码,监听奔溃事件,可以把这些日志写入本地文件。
注意:此时渲染进程可能已经崩溃,不能发送给渲染进程打印到窗口的控制台,崩溃事件的日志最好写到本地文件或者发送个服务端。
app.on('gpu-process-crashed', (event, kill) => {
console.warn('app:gpu-process-crashed', event, kill);
});
app.on('renderer-process-crashed', (event, webContents, kill) => {
console.warn('app:renderer-process-crashed', event, webContents, kill);
});
app.on('render-process-gone', (event, webContents, details) => {
console.warn('app:render-process-gone', event, webContents, details);
});
app.on('child-process-gone', (event, details) => {
console.warn('app:child-process-gone', event, details);
});
注意:event 和 webContents 对象直接写文件,可以 JSON.stringify() 后写入。
2.2.3 崩溃堆栈文件分析
崩溃堆栈文件的分析,需要 Node.js C++ add-on 程序编译时的符号文件,WIndows下为 pdb 文件,Mac 下为 dSYM 文件,需要找相关的 C++ 开发人员处理。分析奔溃堆栈文件需要提供:奔溃堆栈文件、SDK 版本号、操作系统平台信息、SDK本地日志(非必须,最好提供)。