进程之间的通信
主进程向渲染进程通信
-
主进程发送
webContents.send( channel , ...args )
-
渲染接收
ipcRenderer.on( channel , handler )
实例如下:
// main
let win = null;
app.on("ready", () => {
win = new BrowserWindow({
width: 1200,
height: 800
});
win.webContents.send("action", "new");
});
// renderer
import { ipcRenderer } from "electron";
ipcRenderer.on("action", arg => {
// do somethig
});
渲染进程向主进程通信
-
Callback
的写法ipcRenderer.send(channel,..args)
ipMain.on(channel,listener)
-
Promise
的写法(Electron7.0 后,请求处理+响应模式)ipcRenderer.invoke(channel,..args)
ipMain.handle(channel,listener)
渲染进程之间的通信
页面间(渲染进程于渲染进程之间的通信)准要在一下两种场景中存在:
- 通知事件
- ipcRenderer.sendTo()
- 数据共享
- web 技术(storage, indexDB)
- remote
首先需要获得另一个子窗口的id(webContentsId)
我们在 main.js
里面把子窗口的 id 通过一个对象存储起来,然后在渲染进程里面我们可以获取使用:
// main
let win;
let win2;
app.on("ready", () => {
win = new BrowserWindow({
width: 300,
height: 300,
webPreferences: {
enableRemoteModule: true,
nodeIntegration: true
}
});
win.loadFile("./index.html");
win2 = new BrowserWindow({
width: 300,
height: 300,
webPreferences: {
enableRemoteModule: true,
nodeIntegration: true
}
});
win2.loadFile("./index2.html");
global.sharedObject = {
win2WebContentsId: win2.webContents.id
};
});
// index.js
let sharedObject = remote.getGlobal("sharedObject");
let win2WebContentsId = sharedObject.win2WebContentsId;
ipcRenderer.sendTo(win2WebContentsId, "do-some-work", 1);
// index2.js
ipcRenderer.on("do-some-work", (e, a) => {
alert("renderer2 handle some work" + a);
});
ipcMain
从主进程到渲染进程的异步通信。
ipcMain
是一个 EventEmitter
的实例。 当在主进程中使用时,它处理从渲染器进程(网页)发送出来的异步和同步信息。 从渲染器进程发送的消息将被发送到该模块。
发送消息
主进程向渲染进程发送消息,查阅webContents.send获取更多信息。
-
发送时间时,时间名称为
channel
。 -
回复同步消息时,通过
event.returnValue
。 -
可用通过
event.reply(...)
将异步消息发送至发送者。
下面是在渲染和主进程之间发送和处理消息的一个例子:
// 在主进程中.
const { ipcMain } = require("electron");
ipcMain.on("asynchronous-message", (event, arg) => {
console.log(arg); // prints "ping"
event.reply("asynchronous-reply", "pong");
});
ipcMain.on("synchronous-message", (event, arg) => {
console.log(arg); // prints "ping"
event.returnValue = "pong";
});
//在渲染器进程 (网页) 中。
const { ipcRenderer } = require("electron");
console.log(ipcRenderer.sendSync("synchronous-message", "ping")); // prints "pong"
ipcRenderer.on("asynchronous-reply", (event, arg) => {
console.log(arg); // prints "pong"
});
ipcRenderer.send("asynchronous-message", "ping");
方法
IpcMain 模块有以下方法来侦听事件:
ipcMain.handle(channel,listener)
channel
String-
listener
Function <Promiseany> event
IpcMainInvokeEvent...args
any[]
::: tip ipcRender.invoke( ) 和 ipcMain.handle( ) 需要配套使用 :::
示例如下:
// renderer
async function notification() {
const res = await ipcRenderer.invoke("notification");
if (res === "rest") {
} else if (res === "work") {
}
}
// main
ipcMain.handle("notification", async () => {
let result = await new Promise(resolve => {
// do something
resolve("work");
});
return result;
});
ipcRenderer
从渲染器进程到主进程的异步通信。
ipcRenderer
是一个 EventEmitter
的实例。 你可以使用它提供的一些方法从渲染进程 (web 页面) 发送同步或异步的消息到主进程。 也可以接收主进程回复的消息。
方法
ipcRenderer
模块使用以下方法来监听事件和发送消息:
ipcRenderer.invoke(channel, ..args)
channel
String...args
any[]
返回 Promise<any>
- Resolves with the response from the main process.
ipcRenderer.sendTo(webContentsId, channel, ...args)
webContentsId
Numberchannel
String...args
any[]
向指定的子窗口发送某个事件
desktopCapturer
通过[navigator.mediaDevices.getUserMedia] API ,可以访问那些用于从桌面上捕获音频和视频的媒体源信息。
捕获桌面流
下面的示例演示如何从标题为 Electron 的桌面窗口捕获视频:
// renderer process
onMounted(async () => {
const sources = await desktopCapturer.getSources({ types: ["screen"] });
navigator.webkitGetUserMedia(
{
audio: false,
video: {
mandatory: {
chromeMediaSource: "desktop",
chromeMediaSourceId: sources[0].id,
minWidth: 1280,
maxWidth: 1280,
minHeight: 720,
maxHeight: 720
}
}
},
stream => {
play(stream);
},
err => {
console.error(err);
}
);
});
const play = stream => {
const oVideo = video.value; //dom
oVideo.srcObject = stream;
oVideo.onloadedmetadata = () => {
oVideo.play();
};
};
::: tip
-
若要从
desktopCapturer
提供的源捕获视频, 则传递给[navigator.mediaDevices.getUserMedia]
的约束必须包括chromeMediaSource
:"desktop"
和audio
:false
。 -
要从整个桌面同时捕获音频和视频, 传递给
[navigator.mediaDevices.getUserMedia]
的约束必须包括 chromeMediaSource: ‘ desktop ‘, 同时用于 audio 和 video, 但不应包括 chromeMediaSourceId 约束。 :::
audio: {
mandatory: {
chromeMediaSource: 'desktop'
}
},
video: {
mandatory: {
chromeMediaSource: 'desktop'
}
}
}
录屏
::: tip
首先通过desktopCapturer
获取桌面的视频和音频流,然后传递给MediaRecorder
进行录制,结束录制时保存视频文件
:::
<button @click="start">start</button><br />
<button @click="stop">stop</button>
捕获桌面流
let recorder;
const start = async () => {
const sources = await desktopCapturer.getSources({ types: ["screen"] });
navigator.webkitGetUserMedia(
{
audio: false,
video: {
mandatory: {
chromeMediaSource: "desktop",
chromeMediaSourceId: sources[0].id,
minWidth: 1280,
maxWidth: 1280,
minHeight: 720,
maxHeight: 720
}
}
},
stream => {
record(stream);
},
err => {
console.error(err);
}
);
};
开始记录
const record = stream => {
recorder = new MediaRecorder(stream);
recorder.start();
recorder.ondataavailable = event => {
const blob = new Blob([event.data], {
type: "video/mp4"
});
saveMedia(blob);
};
recorder.onerror = err => {
console.error(err);
};
};
点击结束录制的时候 通过
recorder.stop()
会触发recorder.ondataavailable()
方法。当我们拿到文件流对象的时候后就可以进行保存。
const saveMedia = blob => {
const reader = new FileReader();
reader.onload = () => {
const buffer = new Buffer(reader.result);
const index = Math.random() * 10;
fs.writeFile(
`C:\\Users\\Administrator\\Desktop\\${index}.mp4`,
buffer,
(err, res) => {
if (err) {
console.error(err);
return;
} else {
alert("save success");
}
}
);
};
reader.readAsArrayBuffer(blob);
};
const stop = () => {
recorder.stop();
};