文章编写日期:2019-08-05 16:40:15
最近搞了一把Electron,特把实现功能的思路以及中间遇到的问题整理如下
list
1: 选择技术方案 2: 客户端load一个第三方链接 3: 设置自定义UA 4: 设置右键菜单(刷新、启动开发者工具) 5: 监听第三方链接内的路由跳转,当跳转到某个特定链接的时候,启动另外一个渲染进程 6: 注入cookie 7: native和web交互 8: 拦截关闭窗口事件 9: 拦截web页面内的所有http请求 10: 打包
1. 技术方案
该方案是基于Electron-webpack + react + Electron-builder(Electron打包工具)构建的
2. load第三方链接
Electron启动的时候会先启动一个主进程,一个Electron应用总是有且只有一个主进程, 在主进程中运行的脚本通过创建web页面来展示用户界面为渲染进程
2.1) load一个远程连接
const window = new BrowserWindow({
resizable: false,
width,
height,
maximizable: false,
useContentSize: false,
title: 'sayabc',
webPreferences: {
nodeIntegration: false,
allowRunningInsecureContent: true
}
})
window.loadURL(LOGIN_URL)
2.2) load一个本地的html
window.loadURL(formatUrl({
pathname: path.join(__dirname, '../../index.html'),
protocol: 'file',
slashes: true
}))
需要注意的点 BrowserWindow webPreferences内的nodeIntegration需要手动设置为false,去掉引入页面nodejs功能的加持,如果不设置为false,会导致页面中只能通过require引入,否则会报错
3. 设置自定义UA
3.1) 给渲染进程设置UA
window.webContents.setUserAgent("Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.80 Safari/537.36 Electron")
3.2) 给渲染进程中的webview设置UA
<webview id="webview" src="https://www.baidu.com"></webview>
var webview = document.getElementById("webview");
webview.setUserAgent("Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.80 Safari/537.36 Electron")
4. 设置右键菜单(刷新、启动开发者工具)
在Electron的桌面应用上绑定右键事件分为两种情况: 4.1)渲染进程设置右键菜单
const menu = new Menu()
menu.append(new MenuItem({ label: 'go back', click() {
mainWindow.webContents.goBack()
} }
))
menu.append(new MenuItem({ type: 'separator' }))
menu.append(new MenuItem({ label: 'reload', click() { mainWindow.webContents.reload() } }))
menu.append(new MenuItem({ type: 'separator' }))
menu.append(new MenuItem({ label: 'Inspect Element', click () {
mainWindow.webContents.openDevTools()
}
}))
// 渲染进程监听右键事件,显示出对应菜单
mainWindow.webContents.on("context-menu", function(pageInfo) {
mainMenu.popup(mainWindow)
})
mainMenu = menu
4.2)渲染进程中的webview设置右键菜单 webview设置右键菜单,需要在渲染进程中监听右键事件 -> 通知主进程 -> 显示菜单列表
// 渲染进程
<webview id="webview" src="https://www.baidu.com"></webview>
import { ipcRenderer } from 'electron'
var webview = document.getElementById("webview");
// webview监听右键事件
webview.getWebContents().on("context-menu", function(pageInfo) {
// 发送对应的type通知主进程做对应的操作
ipcRenderer.send('send-webview-context-menu')
})
// 主进程监听渲染进程发送的type
import { ipcMain } from 'electron'
ipcMain.on('send-webview-context-menu', (event) => {
const win = BrowserWindow.fromWebContents(event.sender)
curWebview = win
// 显示对应的菜单list
mainMenu.popup(win)
})
5. 监听第三方链接内的路由跳转,当跳转到某个特定链接的时候,启动另外一个渲染进程
监听页面内的链接跳转主要依赖 主进程上的 will-navigate事件做到的
// 依赖url-parse对url进行解析
import urlParse from 'url-parse'
window.webContents.on('will-navigate', (event, url) => {
// url为当前跳转的链接
const triggerUrl = new urlParse(url)
// 当跳转的链接如果等于目标链接
if (triggerUrl.pathname === CLASSROOM_STUDENT.url) {
// 启动另外一个渲染进程
createOtherProcess(triggerUrl.query)
// 阻止链接继续跳转
event.preventDefault()
}
})
webview上也有此事件,可以监听webview内的链接跳转
6. webview内注入js代码
// 此处是注入的cookie
webview.executeJavaScript('document.cookie="testcookie=1234567"')
7. native和web的交互
native和web 交互的大致思路是利用webview标签的preload属性,给web页面注入一个js文件,这个js文件可以调用electron和nodejs的api
<webview id="webview" src="https://www.baidu.com" preload={`file:///Users/sss/workspace/clientSdk.js`}></webview>
// clientSdk.js
// 如下代码会注入到https://www.baidu.com内,当baidu.com内调用
// window.bridgeHandlerElectron.testNativeApi(data)方法时
// 会触发ipcRenderer.sendToHost通知webview
const { ipcRenderer, webContents } = require('electron')
window.bridgeHandlerElectron = {}
window.bridgeHandlerElectron.testNativeApi = function (data) {
console.log('enterNativeRoom', data)
// 此处是重点,要调用sendToHost不能调用send
// sendToHost在webview内能监听到该type
// send只能在Electron主进程内监听到
ipcRenderer.sendToHost('testNativeApi', data)
}
// 渲染进程监听第三方链接
webview.addEventListener('ipc-message', (event) => {
console.log('event.channel', event.channel, event.args[0])
// ipc-message监听,被webview加载页面传来的信息
if (event.channel === 'testNativeApi') {
this.testNativeApi()
}
})
8. 拦截关闭窗口事件
监听桌面应用左上角的关闭事件
window.on('close', (event) => {
console.log('I do not want to be closed')
// 当点击左上角的关闭事件时,会先判断另外一个渲染进程是否存在
// 如果存在先关闭另外一个渲染进程
if (childBrowserView) {
mainWindow.setBrowserView(null)
childBrowserView.destroy()
childBrowserView = null
event.preventDefault()
}
})
9. 拦截web页面内的所有http请求
// 拦截渲染进程内的所有http请求
import { session } from 'electron'
session.defaultSession.webRequest.onBeforeRequest({}, (details, callback) => {
if (details.url.indexOf('.js') > -1) {
console.log('details', details)
}
callback({})
})
10. 打包
打包是基于electron-builder,由于我做的demo中引入某个c++模块,这个模块是32位的(此处可能描述不准确),导致不能直接在mac上打出windows包。如果想要打出windows包,需要安装32位的node重新build,所以当前场景 只能在windows机器上打包出windows的包