本文已参与「新人创作礼」活动, 一起开启掘金创作之路。
在electron应用中,会集成许多第三方应用,比如某些模块是单独的开发的,需要嵌套在electron应用的工作台中,而面对这种情况,我在electron官方文档中找到了
<webview>
标签,在一个独立的 frame 和进程里显示外部 web 内容
electron文档webview
。这里有些需要注意的点,
默认情况下,Electron >= 5禁用
webview
标签。 在构造
BrowserWindow
时,需要通过设置
webviewTag
webPreferences选项来启用标签。 更多信息请参看
BrowserWindows 的构造器文档
。
在集成外部应用到electron应用中后,有时会不可避免的,需要实现第三方应用与electron应用本身的通信。比如第三方应用想要从应用内独立出来,由独立窗口方式显示,又或者需要第三方应用内跳转至另一个应用内等,接下来我就给大家讲述下electron应用与webview间的通信。
二、实施方案
要实现两者间的通信,我们需要一下几个Api方法。
<webview>
标签的监听事件
ipc-message
<webview>
标签的属性
preload
好了,关键方法说完了,接下来咱们就开始实现。
首先我们先写一个给webview中第三方应用预置方法的文件。
// webviewPreload.js
const { ipcRenderer } = require('electron')
* @description 第三方应用向webview发送信息
* @param {String} channel 事件名称
* @param {String} params 传递的参数
global.sendMessageToHost = ({channel = 'ping', args}) => {
ipcRenderer.sendToHost(channel, params)
然后我们将这个文件路径存入全局变量中,这里我将webviewPreload.js文件放在了public文件夹中。
这里要注意preload仅支持file:
和asar:
协议
如果不写file协议或者用相对路径引入就会报如下错误Only "file:" protocol is supported in "preload" attribute.
,因此一定要写全路径并加上协议。
// background.js
global.shareObject = {
webviewPreload = `file://${__static}/webviewPreload.js`
之后我们在electron应用的webview标签处注入这个js文件,并设置相应的监听
<template>
<webview id="myWebView" :src="outsideUrl" nodeintegration allowpopups :preload="preloadPath" />
</template>
import { remote } from "electron";
export default {
data () {
return {
outsideUrl: '',
preloadPath: ''
created () {
this.preloadPath = remote.getGlobal('shareObject').webviewPreload
mounted () {
this.eventHandler()
methods: {
eventHandler () {
const webview = document.querySelector('#myWebView')
webview.addEventListener('ipc-message', event => {
// 这里我们就能接收到嵌入这个webview标签的应用发出的事件和参数了
console.log('来自远方的呼唤', event.channel, '=>', event.args)
接下来是第三方应用调用的
<template>
<div @click="useWebview()">我是按钮</div>
</template>
<script setup>
const useWebview = () => {
let params = {
channel: '协议好的事件名称',
args: '参数'
try {
// 调用注入方法
global.sendMessageToHost(params)
} catch (error) {
console.log(error)
</script>
以上 我们就实现了electron应用与嵌入到webview
中的第三方应用通信功能。
说来惭愧,在没有看到这个方法之前,我都是用另外一种很奇怪的方式,去实现的与webview
通信的方式。
铛~ 铛~ 铛!!!
这个方法就是webview
的另一个监听,就是console-message
具体查看,以下是官网内容
Event: 'console-message'
level
Integer - 日志级别,从0到3。 按顺序匹配 verbose
, info
, warning
和 error
.
message
string - 实际控制台消息
line
Integer - 触发控制台消息的源代码行号。
sourceId
string
Fired when the guest window logs a console message.
The following example code forwards all log messages to the embedder's console without regard for log level or other properties.
这里我是怎么做的呢,就是通过这个监听,跟第三方应用的开发者约定好,相关协议内容,在进行判断他要做什么,如下
<template>
<webview id="myWebView" :src="outsideUrl" allowpopups />
</template>
export default {
data () {
return {
outsideUrl: ''
mounted () {
this.eventHandler()
methods: {
eventHandler () {
const webview = document.querySelector('#myWebView')
webview.addEventListener('console-message', event => {
console.log('Guest page logged a message:', e.message)
// 格式
// project(项目名) - action(事件) - params(参数)
// project@{action: *****, params: {key: value}}
const index = e.message.indexOf('@')
const projectName = e.message.split('@')[0]
const content = index !== -1 ? e.message.substr(index + 1) : ''
if (projectName === 'public') {
const defaultContent = JSON.parse(content)
if (defaultContent.action === '约定的协议') {
// 要做的事情
第三方应用那边是这样写的
userWebview () {
const obj = {
action: '协议,比如getList',
params: '参数'
console.error('public@' + JSON.stringify(obj))
这就是我之前的实现方式,虽然怪异,但是实现了,哈哈哈~
本篇完结撒花! 感谢观看!希望能帮助到你!