封面画师:水卯
Twitter:@Minau_
Electron是GitHub开发的一个开源框架。通过使用Node.js和Chromium的渲染引擎来完成跨平台的桌面GUI应用程序的开发。React是Facebook开发的前端框架。本文主要是为了排Electron的contextBridge上下文隔离的雷。
上下文隔离
以往采用的是ipcMain与ipcRenderer直接进行异步通信,但从Electron 12以来,默认启用了上下文隔离模式,并作为建议安全设置。
关于上下文隔离开启前后的区别,读者可以前往 上下文隔离|Electron 进行了解,文章不再赘述。
contextBridge
contextBridge是用于从预加载脚本将API暴露给渲染进程(Renderer)的模块,也就是说,contextBridge应该被写在你Electron开发的preload.ts(preload.js)文件里。
/* preload.ts */
const { ipcRenderer, contextBridge } = require('electron');
contextBridge.exposeInMainWorld('API', {
send: (channel: string, message: any) => {
if(channel === 'toMain'){
console.log('received');
ipcRenderer.send(channel, message);
}
},
receive: (channel: string, func: any) => {
if (channel === 'fromMain'){
console.log('readytosend');
ipcRenderer.on(channel, (event, args) => func(args));
}
},
});
采用contextBridge的优势是不需要在渲染进程中处理Node.js模块,并能像函数一样进行调用,非常适合React开发,尤其是Hooks使用。
在Electron中,主进程是用Node.js来与OS进行交互的,因此需要在主进程中引入ipcMain模块。
/* main.ts */
import { ipcMain } from 'electron';
/* Your code */
ipcMain.on('toMain', (event, arg: string) => {
console.log(arg);
event.reply('fromMain', 'This is a message from main');
});
此时Electron相关的接口已经设计好,开始在React中进行调用。
/* App.tsx */
import React, { useState } from 'react';
export default function App() {
const [testValue, setTestValue] = useState("Ready");
window.API.receive("fromMain", (arg: string) => { setTestValue(arg) });
return (
{ /* Your code */ }
<button
type="primary"
onClick={() => { window.API.send('toMain', 'testSend') }}
>
Test
</button>
<label>
Input:
<input type="text" value={testValue}/>
</lable>
)
}
此时点击页面上的Test按钮,即可将input控件中的文字从Ready改成This is a message from main
关于TypeScript的问题
在渲染进程的文件中第一次输入window
的时候,TypeScript会提示 Property 'API' does not exist on type 'Window & typeof globalThis'.ts(2339)
,有的解决方案会将window
改成(window as any)
,但这种方案其实是不好的,可以对types这一文件夹下的global.d.ts文件添加如下内容以进行interface全局暴露
/* global.d.ts */
export interface IApi {
send: (arg0: string, arg1: any) => Promise<void>;
receive: (arg0: string, arg1: any) => Promise<void>;
}
declare global {
interface Window {
API: IApi;
}
}
此时即可保证在 TypeScript 编译器在渲染器进程中编写脚本时清楚API
全局window
对象的属性
Comments NOTHING