-
前言
本文通过从0开始编写一个electron小项目,使读者能够在短时间内了解electron项目的开发和基础概念
-
环境准备
nodeJs
使用淘宝镜像或者公司镜像安装electron
检查是否安装成功 官方demo npm install & npm start
-
项目初始化
项目通过create-react-app工具结合electron,新建一个react-electron项目
目录初始化
- 初始化一个react-app,并手动添加main.js文件
- 此时目录结构如下(preload.js 之后介绍)
3. 在package.json新增 "main": "./main.js"
4. 启动脚本里新增 "electron-start": "electron ."
5. 至此,目录准备完成
main.js(可以直接复制官方demo里的main)
const {app, ipcMain, BrowserWindow} = require('electron')
const debug = require('electron-debug')
const path = require('path')
function createWindow () {
const mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
preload: path.join(__dirname, 'preload_render.js'),
javascript: true, // javascript Boolean (可选) - 是否启用 JavaScript 支持。 默认值为 true。
nodeIntegration: true, // nodeIntegration Boolean (可选) - 是否启用Node integration. 默认值为 false.
webSecurity: false,
// 当设置为 false, 它将禁用同源策略 (通常用来测试网站), 如果此选项不是由开发者设置的,还会把 allowRunningInsecureContent设置为 true. 默认值为 true
contextIsolation: false
// 此项为true的话在App.js中无法通过window.require来引用electron包
// Boolean (可选) - 是否在独立 JavaScript 环境中运行 Electron API和指定的preload 脚本. 默认为 true。
}
})
mainWindow.loadURL('http://localhost:3000')
debug.openDevTools(mainWindow)
}
ipcMain.on('asynchronous-message', (event, arg) => {
console.log('main:', arg) // prints "ping"
event.reply('asynchronous-reply', 'pong' + arg)
})
ipcMain.handle('handle-message', async () => {
const result = await Promise.resolve('123');
return result;
})
app.whenReady().then(() => {
createWindow()
app.on('activate', function () {
if (BrowserWindow.getAllWindows().length === 0) createWindow()
})
})
app.on('window-all-closed', function () {
if (process.platform !== 'darwin') app.quit()
})
启动项目
npm run start 启动react项目
npm run electron-start 启动 electron main进程
然后就能看到我们本地的客户端加载了react页面
至此,项目初始化成功!
💥 hello world部分 到此结束
-
electron基本概念介绍
主进程(main.js)
每个 Electron 应用都有一个单一的主进程,作为应用程序的入口点。 主进程在 Node.js 环境中运行,这意味着它具有 require 模块和使用所有 Node.js API 的能力。
窗口进程
使用BrowserWindow创建的窗口
需要配置窗口大小、控制、Web相关配置等等
应用程序生命周期
主进程还能通过 Electron 的 app 模块来控制您应用程序的生命周期。
例如:初始化完成时 --> ready
关闭前 --> before-quit 等等
不同事件在Mac和Winodws上会有差异
原生api
渲染器进程(Renderer)
每个BrowserWindow有单独的render进程,通过ipcRenderer模块与主进程通信
预加载脚本(对应preload_render.js文件)
每个渲染进程优先于网页内容加载的脚本,有可以访问Node API,共享window,但不能向window中注入东西
-
主进程、渲染进程间通信
主进程(main.js中通信部分)
通过ipcMain进行监听,用2种方式举例 on和handle
const { ipcMain } = require('electron')
ipcMain.on('asynchronous-message', (event, arg) => {
console.log(arg) // prints "ping"
event.reply('asynchronous-reply', 'pong')
})
ipcMain.handle('handle-message', async () => {
const result = await Promise.resolve('123');
return result;
})
渲染进程(App.js)(业务组件,一些数据与main进行通信)
在这里每次点击时给main进程发送一个消息,然后收到返回后更改view
import React, { useCallback, useEffect, useState } from 'react';
import logo from './logo.svg';
import './App.css';
const { ipcRenderer } = window.require('electron')
const App = () => {
const [clickTime, setClickTime] = useState(0);
const [echo, setEcho] = useState('');
const sendMsg = useCallback(() => {
ipcRenderer.send('asynchronous-message', clickTime)
}, [clickTime]);
useEffect(() => {
ipcRenderer.on('asynchronous-reply', (event, arg) => {
console.log('renderer:', arg)
setClickTime((clickTime) => clickTime += 1)
setEcho(arg)
})
ipcRenderer.invoke('handle-message').then((res) => {
console.log('handle-message:', res)
})
}, [])
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p onClick={sendMsg}>
click to send Msg
</p>
<p>
echo : {echo}
</p>
</header>
</div>
);
}
export default App;
分别启动渲染进程和主进程
结果
完成App与Main之间的通信
main和renderer的消息打印
💥至此,简单的主、渲染进程间通信完成
-
项目打包,生成安装文件
安装打包工具electron-builder
- 首先
npm run build打包App.js 生成build文件夹 - 改变
main.js中引用的路径资源
// 原来 使用loadURL
mainWindow.loadURL('http://localhost:3000')
// 现在 使用loadFile加载文件
mainWindow.loadFile('./build/index.html')
- 执行 electron-builder --mac,需要在package中进行打包配置(或者单独配置json文件)
Windows 和 mac 配置有所区别
"build": {
"productName":"electronDemo",
"appId": "tzz.electron",
"copyright":"xxxx",
"directories": {
"output": "dist"
},
"asar": false,
"mac": {
"icon": "src/icon.png"
},
"extends": null,
// 此处要写入要打包的文件,否则打包出来找不到对应文件
"files": ["build/", "main.js", "package.json", "preload.js"]
}
- 安装输出文件夹
dist里的dmg文件,打开app - 看到我们想要的结果
至此整个项目的开发就结束啦,可以正常在电脑上使用了