Electron 在 Windows 关联文件启动
对于可以读取本地文件的桌面程序来说,通过关联文件的方式启动也是常见的功能,比如本地的播放器或各种编辑器,可以在资源管理器双击对应的文件来启动程序。
在 Windows 中,可以通过写注册表的方式来关联文件启动,下面关联 .abc
后缀的文件,双击 .abc
后缀的文件就启动程序和读取文件。
因为我使用的是 Windows,我这里只测试了 Windows,Linux 和 macOS 不一定适用!
初始化一个 Electron 程序
创建一个存放项目的目录,在项目目录打开命令行,输入:
npm init -y
Electron 需要打包成 Windows 安装包才能关联文件,在开发模式直接运行和打包为免安装的程序都无法关联。
下面安装 electron 和 electron-builder:
npm install electron electron-builder --save-dev
安装完成后在 package.json
的 scripts
中加入运行和打包命令:
{
"scripts": {
"start": "electron .",
"pack": "electron-builder --dir",
"dist": "electron-builder"
}
}
完成基本的窗口界面
在项目跟目录创建一个 main.js
或 index.js
作为主进程的入口文件,然后创建一个窗口:
const {app, BrowserWindow} = require('electron');
const fs = require('fs');
let mainWindow = null;
app.on('ready', async () => {
// 创建窗口
mainWindow = new BrowserWindow({
width: 800,
height: 500,
webPreferences: {
webSecurity: false,
contextIsolation: true,
preload: path.join(__dirname, 'preload.js')
}
});
// 加载html
await mainWindow.loadFile(path.join(__dirname, 'assets', 'index.html'));
// 窗口关闭
mainWindow.on('close', () => {
mainWindow = null;
});
});
因为安全原因,现在的 Electron 已经无法在渲染进程中引入 Electron 和 Node 模块使用。
官方推荐的方式是主进程通过 preload 把 ipc 通信相关的功能暴露给渲染进程,渲染进程如果需要操作 Electron 或 Node 就通过 ipc 和主进程通信,由主进程来调用 Electron 和 Node API。
我上面设置的 preload
配置文件在项目根目录下的 preload.js
,下面在根目录创建一个 preload.js
,把 ipc 的部分功能暴露给渲染进程:
const { contextBridge, ipcRenderer } = require('electron');
contextBridge.exposeInMainWorld('electronAPI', {
onResponse: (channel, listener) => {
ipcRenderer.on(channel, listener);
},
'ipc-invoke': (channel, listener) => {
ipcRenderer.invoke(channel, listener);
}
});
上面的 Electron API 会被挂载到 window.electronAPI
。
我这里会把前端的 HTML CSS JS 放到项目目录下的 assets
目录,下面在 assets
目录下创建 index.html
,加入基本的 HTML 和一个 textarea
:
<div id="box">
<textarea id="text-box"></textarea>
</div>
这个 textarea
用来显示打开的文件。
完成后可以尝试输入:
npm run start
启动 Electron。
关联文件
下面关联 .abc
后缀的文件,双击 .abc
的文件就启动程序然后读取文件显示。
上面在入口文件已经完成了窗口的创建,下面还是在 index.js
入口文件读取文件:
const {app, BrowserWindow, dialog} = require('electron');
const path = require('path');
const fs = require('fs');
let filePathToOpen = null; // 存储文件路径
// 判断一下是否包括命令参数和程序是否打包
if (process.argv.length >= 2 && app.isPackaged) {
// 获取打开的文件路径
const openFilePath = process.argv[1];
if (openFilePath && path.isAbsolute(openFilePath)) {
filePathToOpen = openFilePath;
}
}
let mainWindow = null;
app.on('ready', async () => {
// 创建窗口
mainWindow = new BrowserWindow({
width: 800,
height: 500,
webPreferences: {
webSecurity: false,
contextIsolation: true,
preload: path.join(__dirname, 'preload.js')
}
});
// 加载html
await mainWindow.loadFile(path.join(__dirname, 'assets', 'index.html'));
// 如果有文件路径就读取文件
if (filePathToOpen) {
fs.readFile(filePathToOpen, 'utf-8', (error, data) => {
// 出错就弹窗显示错误信息
if (error) {
dialog.showMessageBoxSync(mainWindow, {
type: 'error',
title: '读取文件出错',
message: `无法读取文件:${filePathToOpen}`,
detail: error.message,
buttons: ['关闭'],
defaultId: 0,
noLink: true
});
return false;
}
// 成功读取文件内容就把文件内容发送到渲染进程
mainWindow.webContents.send('file-content', data);
});
}
// 窗口关闭
mainWindow.on('close', () => {
mainWindow = null;
});
});
在 Windows 中,从关联后缀的文件打开时,可以通过 process.argv[1]
获取文件的位置,比如关联了 .abc
后缀的文件,双击 .abc
文件启动程序时,就可以通过 process.argv[1]
获取该 .abc
文件的位置。
我上面使用的 fs.readFile
是完全读取整个文件,对于小文件可以用这种方式,但是对于一些大文件可能就需要部分读取。
创建一个 JS 文件,在前端的 HTML 中引入,用于显示主进程传过来的内容:
const textBox = document.querySelector('#text-box');
// 监听处理主进程传过来的内容
window.electronAPI.onResponse('file-content', (ev, result) => {
// 在 textarea 中显示打开的文件
textBox.value = result;
});
上面使用 document.querySelector('#text-box')
获取的就是前端 HTML 中的 textarea
。
打包
打包是关联文件中比较重要的部分,只有打包了才能关联文件启动。
electron-builder 的打包需要在 package.json
中的 build
中配置,下面是一个包含关联文件的 Windows 打包配置:
{
"build": {
"appId": "electron-open-file",
"productName": "electron-open-file",
"icon": "assets/favicon.ico",
"copyright": "Copyright © 2024",
"compression": "maximum",
"asar": true,
"win": {
"icon": "assets/logo.ico",
"target": "nsis",
"legalTrademarks": "changbin1997"
},
"nsis": {
"oneClick": false,
"perMachine": true,
"allowToChangeInstallationDirectory": true,
"createDesktopShortcut": true,
"createStartMenuShortcut": false
},
"directories": {
"output": "release"
},
"files": [
"index.js",
"preload.js",
"assets/**/*",
"package.json",
"!**/node_modules/*",
"!node_modules/**/node_modules/*",
"!package-lock.json",
"!screenshots/**/*",
"!**/.*",
"!**/*.map",
"!**/test?(s)/**/*",
"!**/*.{md,txt,log,o,hprof,orig,pyc,pyo,rbc,pdb,ilk,bak}",
"!**/._*",
"!README.md",
"!LICENSE"
],
"fileAssociations": [
{
"ext": "abc",
"name": "abc file",
"description": "点击打开 .abc 文件",
"icon": "assets/logo.ico"
}
]
}
}
上面把 Electron 程序打包为 Windows 安装包,打包完成后会在项目目录下的 release
输出打包的程序。
下面是详细的配置说明:
appId
和 productName
是程序 ID 和程序名称。
icon
是默认的程序图标,我的所有图标文件都存放在 assets
目录。
compression
设置打包的压缩率,我这里的 maximum
是高压缩,打包的时间会稍长一些,打包后的程序也要更小。
asar
设置把资源文件打包到 .asar
文件中,可以减少打包后的程序目录中的文件数量。
win
是 Windows 相关的打包配置。
win.icon
程序图标,最好使用 256*256 的 .ico
图标。
win.target
设置打包目标,我设置的 nsis
是打包为 .exe
的安装包,你也可以打包成 .msi
的安装包。
win.legalTrademarks
是商标信息。
nsis
是安装包配置。
nsis.oneClick
是否使用一键安装,我这里没有使用一键安装,可以自己选择安装目录。
nsis.perMachine
是为所有用户安装,如果设置为 false
就是为当前用户安装,程序会默认安装到当前用户的用户目录。
nsis.allowToChangeInstallationDirectory
允许更改默认的安装位置。
nsis.createDesktopShortcut
安装完成后创建桌面快捷方式。
nsis.createStartMenuShortcut
安装完成后创建开始菜单快捷方式。
directories.output
是设置打包完成后的输出位置。
files
可以设置要打包的文件和要排除的文件,我这里打包的文件包括:
index.js
Electron 入口文件package.json
preload.js
用于暴露 Electron 和 Node API 给渲染进程assets
目录中的所有文件,也就是前端渲染进程使用的文件
其它包含 !
都是不用打包的文件。
fileAssociations
是配置文件关联,需要传入一个数组,一个程序可以关联多个后缀的文件。
fileAssociations.ext
要关联的文件后缀。
fileAssociations.name
用于文件属性和气球提示显示的文件类型名称。
fileAssociations.description
用于气球提示和文件属性显示的文件描述。
fileAssociations.icon
关联文件使用的图标。
我上面关联了 .abc
后缀的文件,程序安装后,所有 .abc
后缀的文件都会显示我设置的 logo.ico
图标。
初始化项目的时候,在 scripts
中加入了 pack
和 dist
两条打包相关的命令,其中:
npm run pack
可以把程序打包为一个目录,目录中有可以直接运行的免安装 exe 程序。
使用:
npm run dist
可以打包为 Windows 安装包。
打包的时候你需要有一个比较好的国际互联网连接,如果你无法访问 Github 之类的网站,可能无法成功打包,如果网速较慢打包的速度也会比较慢。
考虑到随着 electron 和 electron-builder 的版本更新,一些 API 和配置可能会改变,下面是我这里演示使用的完整 package.json
:
{
"name": "electron-open-file",
"version": "1.0.0",
"description": "点击打开 .abc 文件",
"main": "index.js",
"scripts": {
"start": "electron .",
"pack": "electron-builder --dir",
"dist": "electron-builder"
},
"keywords": [],
"author": "changbin1997",
"license": "ISC",
"devDependencies": {
"electron": "^37.2.6",
"electron-builder": "^26.0.12"
},
"build": {
"appId": "electron-open-file",
"productName": "electron-open-file",
"icon": "assets/favicon.ico",
"copyright": "Copyright © 2024",
"compression": "maximum",
"asar": true,
"win": {
"icon": "assets/logo.ico",
"target": "nsis",
"legalTrademarks": "changbin1997"
},
"nsis": {
"oneClick": false,
"perMachine": true,
"allowToChangeInstallationDirectory": true,
"createDesktopShortcut": true,
"createStartMenuShortcut": false
},
"directories": {
"output": "release"
},
"files": [
"index.js",
"preload.js",
"assets/**/*",
"package.json",
"!**/node_modules/*",
"!node_modules/**/node_modules/*",
"!package-lock.json",
"!screenshots/**/*",
"!**/.*",
"!**/*.map",
"!**/test?(s)/**/*",
"!**/*.{md,txt,log,o,hprof,orig,pyc,pyo,rbc,pdb,ilk,bak}",
"!**/._*",
"!README.md",
"!LICENSE"
],
"fileAssociations": [
{
"ext": "abc",
"name": "abc file",
"description": "点击打开 .abc 文件",
"icon": "assets/logo.ico"
}
]
}
}
在 devDependencies
中有 electron 和 electron-builder 的版本信息。
查看最终效果
打包完成后把打包的程序安装到电脑上,创建一个 .abc
后缀的文件,如果配置没有错误的话,应该可以看到 .abc
后缀的文件图标就是关联文件配置的图标。
下面使用自带的 Windows 记事本打开 .abc
文件,添加一些内容:
可以查看一下 .abc
文件的文件属性:
在打开方式中可以看到上面配置的 electron-open-file。
双击 .abc
文件就会启动关联的 Electron 程序,然后读取文件显示:
我在前端 HTML 文件中用了一个 textarea
来显示读取的文件内容。
当你卸载了程序后,关联后缀的文件图标也会变为默认图标。
版权声明:本文为原创文章,版权归 Changbin's Blog 所有,转载请联系博主获得授权。
本文地址:https://www.misterma.com/archives/953/
如果对本文有什么问题或疑问都可以在评论区留言,我看到后会尽量解答。