diff options
-rw-r--r-- | packages/main/src/index.ts | 7 | ||||
-rw-r--r-- | packages/service-preload/src/index.ts | 41 |
2 files changed, 36 insertions, 12 deletions
diff --git a/packages/main/src/index.ts b/packages/main/src/index.ts index 4a51518..b134002 100644 --- a/packages/main/src/index.ts +++ b/packages/main/src/index.ts | |||
@@ -219,8 +219,8 @@ function createWindow(): Promise<unknown> { | |||
219 | webContents.send(MainToRendererIpcMessage.SharedStorePatch, patch); | 219 | webContents.send(MainToRendererIpcMessage.SharedStorePatch, patch); |
220 | }); | 220 | }); |
221 | 221 | ||
222 | ipcMain.on(ServiceToMainIpcMessage.ApiExposedInMainWorld, (event) => { | 222 | ipcMain.handle(ServiceToMainIpcMessage.ApiExposedInMainWorld, (event) => { |
223 | event.returnValue = event.sender.id == browserView.webContents.id | 223 | return event.sender.id == browserView.webContents.id |
224 | ? serviceInject | 224 | ? serviceInject |
225 | : null; | 225 | : null; |
226 | }); | 226 | }); |
@@ -229,7 +229,8 @@ function createWindow(): Promise<unknown> { | |||
229 | try { | 229 | try { |
230 | switch (channel) { | 230 | switch (channel) { |
231 | case ServiceToMainIpcMessage.ApiExposedInMainWorld: | 231 | case ServiceToMainIpcMessage.ApiExposedInMainWorld: |
232 | // Synchronous message must be handled with `ipcMain.on` | 232 | // Asynchronous message with reply must be handled in `ipcMain.handle`, |
233 | // otherwise electron emits a no handler registered warning. | ||
233 | break; | 234 | break; |
234 | case ServiceToMainIpcMessage.SetUnreadCount: | 235 | case ServiceToMainIpcMessage.SetUnreadCount: |
235 | console.log('Unread count:', unreadCount.parse(args[0])); | 236 | console.log('Unread count:', unreadCount.parse(args[0])); |
diff --git a/packages/service-preload/src/index.ts b/packages/service-preload/src/index.ts index e42c406..d1ea13c 100644 --- a/packages/service-preload/src/index.ts +++ b/packages/service-preload/src/index.ts | |||
@@ -27,13 +27,36 @@ if (webFrame.parent === null) { | |||
27 | webFrame.insertCSS('html { background-color: #fff; }'); | 27 | webFrame.insertCSS('html { background-color: #fff; }'); |
28 | } | 28 | } |
29 | 29 | ||
30 | const injectSource = webSource.safeParse(ipcRenderer.sendSync(ServiceToMainIpcMessage.ApiExposedInMainWorld)); | 30 | /** |
31 | if (injectSource.success) { | 31 | * Fetches and executes the service inject script in the isolated world. |
32 | webFrame.executeJavaScriptInIsolatedWorld(0, [ | 32 | * |
33 | injectSource.data, | 33 | * The service inject script relies on exposed APIs, so this function can only |
34 | ]).catch((err) => { | 34 | * be called after APIs have been exposed via `contextBridge` to the main world. |
35 | console.log('Failed to inject source:', err); | 35 | * |
36 | }); | 36 | * We have to call `executeJavaScriptInIsolatedWorld` from the service preload script, |
37 | } else { | 37 | * beause there is no way currently (electron 16) to execute a script on a |
38 | console.log('Invalid source to inject:', injectSource.error); | 38 | * `WebFrameMain` in the main process by specifying a `WebSource`. |
39 | * Calling `executeJavaScriptInInsolatedWorld` on a `WebContents` in the main process | ||
40 | * will always inject the script into the _top-level_ frame, but here we | ||
41 | * are injecting into the _current_ frame instead. | ||
42 | * As a tradeoff, the promise returned by `executeJavaScriptInIsolatedWorld` | ||
43 | * will resolve to `unknown` (instead of rejecting) even if the injected script fails, | ||
44 | * because chromium doesn't dispatch main world errors to isolated worlds. | ||
45 | * | ||
46 | * @return A promise that only rejects if we fail to fetch the inject script. | ||
47 | * @see https://www.electronjs.org/docs/latest/api/web-frame#webframeexecutejavascriptinisolatedworldworldid-scripts-usergesture-callback | ||
48 | * @see https://www.electronjs.org/docs/latest/api/web-frame-main#frameexecutejavascriptcode-usergesture | ||
49 | * @see https://www.electronjs.org/docs/latest/api/web-contents#contentsexecutejavascriptinisolatedworldworldid-scripts-usergesture | ||
50 | */ | ||
51 | async function fetchAndExecuteInjectScript(): Promise<void> { | ||
52 | const apiExposedResponse = await ipcRenderer.invoke( | ||
53 | ServiceToMainIpcMessage.ApiExposedInMainWorld, | ||
54 | ); | ||
55 | const injectSource = webSource.parse(apiExposedResponse); | ||
56 | // Isolated world 0 is the main world. | ||
57 | return webFrame.executeJavaScriptInIsolatedWorld(0, [injectSource]); | ||
39 | } | 58 | } |
59 | |||
60 | fetchAndExecuteInjectScript().catch((err) => { | ||
61 | console.log('Failed to fetch inject source:', err); | ||
62 | }); | ||