From 047c423987ecb510e2be7982f46fc65e7634cbea Mon Sep 17 00:00:00 2001 From: DIYgod Date: Fri, 7 Mar 2025 18:50:29 +0800 Subject: [PATCH] feat: use the app protocol instead of the file protocol (#2991) * feat: load from app protocol * fix: protocol path parsing --- apps/desktop/src/main/src/index.ts | 15 ++++++++++++++- apps/desktop/src/main/src/init.ts | 13 ++++++++++++- apps/desktop/src/main/src/window.ts | 13 +++++-------- 3 files changed, 31 insertions(+), 10 deletions(-) diff --git a/apps/desktop/src/main/src/index.ts b/apps/desktop/src/main/src/index.ts index 16e65b5ce..606e97e1e 100644 --- a/apps/desktop/src/main/src/index.ts +++ b/apps/desktop/src/main/src/index.ts @@ -1,3 +1,5 @@ +import url from "node:url" + import { electronApp, optimizer } from "@electron-toolkit/utils" import { callWindowExpose } from "@follow/shared/bridge" import { APP_PROTOCOL } from "@follow/shared/constants" @@ -5,7 +7,7 @@ import { env } from "@follow/shared/env.desktop" import { createBuildSafeHeaders } from "@follow/utils/headers" import { IMAGE_PROXY_URL } from "@follow/utils/img-proxy" import { parse } from "cookie-es" -import { app, BrowserWindow, session } from "electron" +import { app, BrowserWindow, net, protocol, session } from "electron" import squirrelStartup from "electron-squirrel-startup" import { DEVICE_ID } from "./constants/system" @@ -16,6 +18,7 @@ import { handleUrlRouting } from "./lib/router" import { store } from "./lib/store" import { registerAppTray } from "./lib/tray" import { setBetterAuthSessionCookie, updateNotificationsToken } from "./lib/user" +import { logger } from "./logger" import { registerUpdater } from "./updater" import { cleanupOldRender } from "./updater/hot-updater" import { @@ -71,6 +74,16 @@ function bootstrap() { // initialization and is ready to create browser windows. // Some APIs can only be used after this event occurs. app.whenReady().then(async () => { + protocol.handle("app", (request) => { + try { + const urlObj = new URL(request.url) + return net.fetch(url.pathToFileURL(urlObj.pathname).toString()) + } catch { + logger.error("app protocol error", request.url) + return new Response("Not found", { status: 404 }) + } + }) + // Default open or close DevTools by F12 in development // and ignore CommandOrControl + R in production. // see https://github.com/alex8088/electron-toolkit/tree/master/packages/utils diff --git a/apps/desktop/src/main/src/init.ts b/apps/desktop/src/main/src/init.ts index 5604c161c..8c12f89b4 100644 --- a/apps/desktop/src/main/src/init.ts +++ b/apps/desktop/src/main/src/init.ts @@ -5,7 +5,7 @@ import { PushReceiver } from "@eneris/push-receiver" import { APP_PROTOCOL } from "@follow/shared/constants" import { env } from "@follow/shared/env.desktop" import type { MessagingData } from "@follow/shared/hono" -import { app, nativeTheme, Notification, shell } from "electron" +import { app, nativeTheme, Notification, protocol, shell } from "electron" import contextMenu from "electron-context-menu" import { getIconPath } from "./helper" @@ -61,6 +61,17 @@ export const initializeAppStage1 = () => { registerPushNotifications() clearCacheCronJob() checkAndCleanCodeCache() + + protocol.registerSchemesAsPrivileged([ + { + scheme: "app", + privileges: { + standard: true, + bypassCSP: true, + supportFetchAPI: true, + }, + }, + ]) } let contextMenuDisposer: () => void diff --git a/apps/desktop/src/main/src/window.ts b/apps/desktop/src/main/src/window.ts index 0a7265513..6e2189848 100644 --- a/apps/desktop/src/main/src/window.ts +++ b/apps/desktop/src/main/src/window.ts @@ -112,7 +112,7 @@ export function createWindow( const handleExternalProtocol = async (e: Event, url: string, window: BrowserWindow) => { const { protocol } = new URL(url) - const ignoreProtocols = ["http", "https", APP_PROTOCOL, "file", "code", "cursor"] + const ignoreProtocols = ["http", "https", APP_PROTOCOL, "file", "code", "cursor", "app"] if (ignoreProtocols.includes(protocol.slice(0, -1))) { return } @@ -149,14 +149,11 @@ export function createWindow( // Production entry const dynamicRenderEntry = loadDynamicRenderEntry() logger.info("load dynamic render entry", dynamicRenderEntry) - const appLoadEntry = dynamicRenderEntry || path.resolve(__dirname, "../renderer/index.html") + const appLoadFileEntry = dynamicRenderEntry || path.resolve(__dirname, "../renderer/index.html") + const appLoadEntry = `app://follow.is${appLoadFileEntry}${options?.extraPath || ""}` - window.loadFile(appLoadEntry, { - hash: options?.extraPath, - }) - logger.log(appLoadEntry, { - hash: options?.extraPath, - }) + window.loadURL(appLoadEntry) + logger.log("load URL", appLoadEntry) } if (isWindows) {