diff --git a/docs/api/webview-tag.md b/docs/api/webview-tag.md index 3efa2614a354..9f356cf1abed 100644 --- a/docs/api/webview-tag.md +++ b/docs/api/webview-tag.md @@ -606,6 +606,21 @@ listening to the `channel` event with the [`ipcRenderer`](ipc-renderer.md) modul See [webContents.send](web-contents.md#contentssendchannel-args) for examples. +### `.sendToFrame(frameId, channel, ...args)` + +* `frameId` [number, number] - `[processId, frameId]` +* `channel` String +* `...args` any[] + +Returns `Promise` + +Send an asynchronous message to renderer process via `channel`, you can also +send arbitrary arguments. The renderer process can handle the message by +listening to the `channel` event with the [`ipcRenderer`](ipc-renderer.md) module. + +See [webContents.sendToFrame](web-contents.md#contentssendtoframeframeid-channel-args) for +examples. + ### `.sendInputEvent(event)` * `event` [MouseInputEvent](structures/mouse-input-event.md) | [MouseWheelInputEvent](structures/mouse-wheel-input-event.md) | [KeyboardInputEvent](structures/keyboard-input-event.md) @@ -920,6 +935,7 @@ webview.addEventListener('close', () => { Returns: +* `frameId` [number, number] - pair of `[processId, frameId]`. * `channel` String * `args` any[] diff --git a/lib/browser/guest-view-manager.ts b/lib/browser/guest-view-manager.ts index b2b5f49bfcbb..dec9ddd4011d 100644 --- a/lib/browser/guest-view-manager.ts +++ b/lib/browser/guest-view-manager.ts @@ -161,8 +161,12 @@ const createGuest = function (embedder: Electron.WebContents, embedderFrameId: n }); // Dispatch guest's IPC messages to embedder. - guest.on('ipc-message-host' as any, function (_: Electron.Event, channel: string, args: any[]) { - sendToEmbedder(IPC_MESSAGES.GUEST_VIEW_INTERNAL_DISPATCH_EVENT, 'ipc-message', { channel, args }); + guest.on('ipc-message-host' as any, function (event: Electron.IpcMainEvent, channel: string, args: any[]) { + sendToEmbedder(IPC_MESSAGES.GUEST_VIEW_INTERNAL_DISPATCH_EVENT, 'ipc-message', { + frameId: [event.processId, event.frameId], + channel, + args + }); }); // Notify guest of embedder window visibility when it is ready diff --git a/lib/common/web-view-methods.ts b/lib/common/web-view-methods.ts index 449ee9d3915c..a2cfb328cc46 100644 --- a/lib/common/web-view-methods.ts +++ b/lib/common/web-view-methods.ts @@ -65,6 +65,7 @@ export const asyncMethods = new Set([ 'insertText', 'removeInsertedCSS', 'send', + 'sendToFrame', 'sendInputEvent', 'setLayoutZoomLevelLimits', 'setVisualZoomLevelLimits', diff --git a/spec/webview-spec.js b/spec/webview-spec.js index 1d4dd657bd6d..e1d2ab3d27c0 100644 --- a/spec/webview-spec.js +++ b/spec/webview-spec.js @@ -267,6 +267,24 @@ describe(' tag', function () { expect(args).to.deep.equal([message]); }); + it('.sendToFrame()', async () => { + loadWebView(webview, { + nodeintegration: 'on', + webpreferences: 'contextIsolation=no', + preload: `${fixtures}/module/preload-ipc.js`, + src: `file://${fixtures}/pages/ipc-message.html` + }); + + const { frameId } = await waitForEvent(webview, 'ipc-message'); + + const message = 'boom!'; + webview.sendToFrame(frameId, 'ping', message); + + const { channel, args } = await waitForEvent(webview, 'ipc-message'); + expect(channel).to.equal('pong'); + expect(args).to.deep.equal([message]); + }); + it('works without script tag in page', async () => { const message = await startLoadingWebViewAndWaitForMessage(webview, { preload: `${fixtures}/module/preload.js`, @@ -529,8 +547,9 @@ describe(' tag', function () { webpreferences: 'contextIsolation=no', src: `file://${fixtures}/pages/ipc-message.html` }); - const { channel, args } = await waitForEvent(webview, 'ipc-message'); + const { frameId, channel, args } = await waitForEvent(webview, 'ipc-message'); + expect(frameId).to.be.an('array').that.has.lengthOf(2); expect(channel).to.equal('channel'); expect(args).to.deep.equal(['arg1', 'arg2']); });