一、Webview
Electron 中 webview 是 electron 框架自带的组件,用于加载 web 应用。与 web 通信的原理如下:
webview => web
// webview 发送
webview.send('channel_name_in_react_component', args);
// web 监听
ipcRenderer.on('channelNamel', (event, args) {
// do whatever
});
web => webview ``` // web 发送 import {ipcRenderer} from ‘electron’ ipcRenderer.sendToHost(‘channelName’, …args)
// webview 监听 webview.addEventListener(‘ipc-message’, onIpcMessage)
function onIpcMessage(event) { const {args, channel} = event console.log(channel, args) }
这些逻辑一般封装在一个 bridge.js 里,然后让 webview 预加载这个文件
```javascript
// bridge.js
const { ipcRenderer } = require("electron");
const SupportedMethods = ["send"];
class WebViewBridge {
constructor() {
window.WebView = window.CommonWebView = this.getWebView();
this.listen();
}
getWebView() {
const WebView = {};
SupportedMethods.forEach((api) => {
WebView[api] = (params) => {
this._webviewMessageSender(api, params);
};
});
return WebView;
}
_webviewMessageSender(method, params) {
try {
params = JSON.parse(params);
} catch (e) {
console.error(`
[WebViewBridge] PARSE BASE64 ERROR
params: ${params}
e: ${e}
`);
return;
}
ipcRenderer.sendToHost(method, params.arguments[0]);
}
listen() {
ipcRenderer.on("electron-webview-channel", (event, callbackName, data) => {
try {
console.log("==", event, callbackName, data);
window[callbackName](data);
} catch (e) {
console.error(`
[WebViewBridge] CALLBACK ERROR
callbackName: ${callbackName}
data: ${data}
detail: ${e}
`);
}
});
}
}
new WebViewBridge();
- 使用 webview 时要注意开启两点: ```javascript const win = new BrowserWindow({ width: 800, height: 600, webPreferences: { nodeIntegration: true, webviewTag: true, // 1、启用 webview }, });
<!DOCTYPE html>
<a name="hWLIC"></a>
## 二、BrowserWindow
主进程使用<br />1、用于在主进程创建和控制浏览器窗口,可以创建出无边框窗口(可以自定义header)、透明窗口(用于制作不规则界面)、父子窗口、模态窗口<br />2、往往需要通过 -webkit-app-region 设置可拖拽区域:
```html
<body style="-webkit-app-region: drag"></body>
button {
-webkit-app-region: no-drag;
}
3、为避免闪烁,展示窗口的时机应该在 ready-to-show 或者 did-finish-load 事件之后
const { BrowserWindow } = require('electron')
const win = new BrowserWindow({ show: false })
win.once('ready-to-show', () => {
win.show() // 如果还是有白屏现象,可以换成 did-finish-load 事件
})
4、常用事件
- close、closed 将要关闭和已经关闭
- blur、focus、show、hide、maxmize、unmaxmize、minimize、restore
5、常用静态方法
- getAllWindows
- getFocusedWindow
- fromWebContents
- fromBrowserView
- fromId
6、常用属性和方法
- id
- webContents
- close() 和用户点击关闭按钮效果一样,关闭操作可能被 web 取消
- destroy() 强制关闭窗口,只会触发 closed;不会触发 close、beforeunload、unload
- focus()、blur()、isFocused()、isDestroyed()、isVisible()、isModal()、minimize()、restore()
- show()、hide()
- loadUrl(url,options) url 可以是远程地址 (例如 http://),也可以是 file:// 协议的本地HTML文件的路径. 与 webContents.loadUrl(url,options) 功能相似: ```javascript // 确保 url 符合要求 const url = require(‘url’).format({ protocol: ‘file’, slashes: true, pathname: require(‘path’).join(__dirname, ‘index.html’) })
win.loadURL(url)
- loadFile(file) 与 webContents.loadFile(file) 功能相似:
<a name="QJcuk"></a>
## 三、webContents
主进程使用<br />1、webContents 是 EventEmitter. 负责渲染和控制网页, 是 BrowserWindow 对象的一个属性。
```javascript
const { BrowserWindow } = require('electron')
const win = new BrowserWindow({ width: 800, height: 1500 })
win.loadURL('http://github.com')
const contents = win.webContents
console.log(contents)
2、可以通过 electron 直接引入
const { webContents } = require('electron')
console.log(webContents)
3、常用静态方法
- getAllWebContents(),包含所有Windows,webviews,opened devtools 和 devtools 扩展背景页的 web 内容
- getFocusedWebContents()
- fromId()
4、常用事件
- dom-ready
- did-finish-load
- render-process-gone
- plugin-crashed
- destroyed
- ipc-message IPC 通信
5、常用实例方法和属性
- downloadURL() 下载文件,开始后会触发对应 session 的 will-download 事件 ```javascript // 触发下载 win.webContents.downloadURL(url)
// 监听 will-download session.defaultSession.on(‘will-download’, (event, item, webContents) => { // 监听 item 的 pause、resume、cancel、updated、done 等事件处理下载逻辑 })
- goBack()
- goForward()
- canGoBack()
- canGoForward()
- setUserAgent()
- postMessage() 主进程发送事件,渲染进程接受 ipcRender.on
- id
- session
- userAgent
<a name="SsBDI"></a>
## 四、session
主进程使用<br />管理浏览器会话、cookie、缓存、代理设置等。
```javascript
const { BrowserWindow } = require('electron')
const win = new BrowserWindow({ width: 800, height: 600 })
win.loadURL('http://github.com')
const ses = win.webContents.session
console.log(ses.getUserAgent())
1、静态方法和属性
- fromPartition(partition),如果 partition 以 persist:开头, 该页面将使用持续的 session,并在所有页面生效,且使用同一个partition. 如果没有 persist: 前缀, 页面将使用 in-memory session. 如果没有设置partition,app 将返回默认的session。
- defaultSession 应用程序的默认session对象
2、实例属性和方法
- clearStorageData(options),可以清除:appcache, cookies, filesystem, indexdb, localstorage, shadercache, websql, serviceworkers, cachestorage
- setUserAgent()
- loadExtention() 设置扩展程序 ```javascript const { app, session } = require(‘electron’) const path = require(‘path’)
app.on(‘ready’, async () => { await session.loadExtension( path.join(__dirname, ‘react-devtools’), // allowFileAccess is required to load the devtools extension on file:// URLs. { allowFileAccess: true } ) // Note that in order to use the React DevTools extension, you’ll need to // download and unzip a copy of the extension. })
- cookies
```javascript
import { Cookie, CookiesGetFilter, CookiesSetDetails, session } from 'electron';
import { fileURLToPath } from 'url';
const SessionPartition = 'persist:my-app';
/**
* PersistentSession
* Session 持久化管理
*/
class PersistentSession {
private _session: session | null = null;
init() {
if (this._session) {
return;
}
this._session = session.fromPartition(SessionPartition, { cache: false });
// workaround in https://github.com/electron/electron/issues/23757
this._session.protocol.registerFileProtocol('file', (request, callback) => {
callback({ path: fileURLToPath(request.url) });
});
}
get session(): session {
if (!this._session) {
this.init();
}
return this._session;
}
get partition(): string {
if (!this._session) {
this.init();
}
return SessionPartition;
}
async getCookies(filter: CookiesGetFilter): Promise<Cookie[]> {
try {
return await this.session.cookies.get(filter);
} catch (error) {
return [];
}
}
async setCookies(details: CookiesSetDetails): Promise<void> {
try {
await this.session.cookies.set(details);
} catch (error) {}
}
async removeCookies(url: string, name: string): Promise<void> {
try {
await this.session.cookies.remove(url, name);
} catch (error) {}
}
async clearAllCookies(): Promise<void> {
try {
await this.session.clearStorageData({ storages: ['cookies'] });
} catch (error) {}
}
async flushCookies(): Promise<void> {
try {
await this.session.cookies.flushStore();
} catch (error) {}
}
}
export const persistentSession = new PersistentSession();
- webRequest 可以设置拦截,如加些请求 header
参考:
Electron webview完全指南
BrowserWindow