feat: use the app protocol instead of the file protocol (#2991)

* feat: load from app protocol

* fix: protocol path parsing
This commit is contained in:
DIYgod 2025-03-07 18:50:29 +08:00 committed by GitHub
parent a5cf9adec1
commit 047c423987
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 31 additions and 10 deletions

View File

@ -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

View File

@ -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

View File

@ -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) {