Electron小记

1,202 阅读4分钟

文章编写日期: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的包

参考链接

newsn.net/say/electro… juejin.im/post/5bc53a…