electron渲染进程与webview远程访客页面通讯

  • 邢毅彪
  • 4 Minutes
  • 2019年1月16日

前言

在项目中, 如果我们的项目业务层代码部署在服务器上, 需要用iframe或webview的方式将我们的业务代码引入到electron项目中, 使业务代码的更新发版独立与我们的electron版本。这样无疑是有很多好处的, 其中之一便是, 我们杜绝了eletron用户版本更新覆盖率的问题。之前我们一直使用iframe引入的我们的业务代码。但是,当我们因某些功能需要, 将electron升级在3.x以后, 却意外发现iframe里的webRtc代码无法获得用户设备的权限。经过一番踩坑之后, 最终发现可能是electron在某个版本更新后调整了iframe的安全策略,无奈只能换为webview 标签引入。

遇到的问题

Iframe引入是我们采用的postMessage的方式与electron渲染进程通信, 当我们换为webview之后, 官方文档的示例是使用ipcRenderer与渲染进程通信, 这里有一个很大的坑, 网上能搜到的大多数教程都是基于此, 但是ipcRenderer是electron导入的包,这会造成我们部署与服务器的业务代码,根本无法run。折腾一番之后, 最终选择了使用preload导入一个brige脚本代码,将渲染进程的ipcRenderer注入到业务代码的window全局对象里,进行通讯。

具体实现

首先是在渲染进程的html里面通过preload的方式引入我们的brige脚本,如下

1
<webview src=“https://xxx” preload=“path/to/inject.js”></webview>
1
2
3
4
5
6
// inject.js
const { ipcRenderer } = require('electron')

window.$brige = {
ipcRenderer
}
// renderer.js
const webview = document.querySelector('webview')

webview.addEventListener('dom-ready', () => {
    // webview.openDevTools() // electron webview的控制台需要单独打开, 否则只看到渲染进程的控制台
})

// 监听webview发送的事件,事件名称如官方文档所示,固定为ipc-message
webview.addEventListener('ipc-message', (evt) => {
    console.log(evt.channel)
    const { type } = evt.channel
    if (type === 'from-web') {
        webview.send('from-electron', 'hello web') // 向webview发送事件
    }
})
// 访客页
const { $brige } = window
if ($brige) {
    const action = {
        type: 'from-web',
        payload: 'hello electron',
    }
    $brige.ipcRenderer.sendToHost(action) // 发送给渲染进程,不需要命名事件名
    // 监听渲染进程发送的事件
    $brige.ipcRenderer.on('from-electron', (evt, data) => {
        console.log(data)
    })
}

写在最后

这个例子仅仅为了解决实际开发中的某一个问题,但是却延展出一个很好的思路, preload可以将很多node这边渲染进程的东西最后全部注入到全局的window对象上, 这样可以使业务层拥有更多的能力,却依然保有热更新,热替换的能力。

访问量