feat(deeplink): implement custom deep link handling and remove electron-app-universal-protocol-client

This commit is contained in:
Elysia
2026-01-18 00:45:25 +08:00
parent a476db84ee
commit c7b3257a2c
5 changed files with 99 additions and 18 deletions

View File

@@ -45,7 +45,6 @@ jobs:
- name: Install Dependencies - name: Install Dependencies
run: | run: |
npm install -G node-gyp@11.1.0
npm install npm install
- name: Build Release Files - name: Build Release Files

91
electron/main/deeplink.ts Normal file
View File

@@ -0,0 +1,91 @@
import { app } from "electron";
type Query = Record<string, string>;
export type Listener = (query: Query) => any;
class ListenersMap {
private map: Map<string, Set<Listener>> = new Map();
add(action: string, listener: Listener) {
if (!this.map.has(action)) {
this.map.set(action, new Set());
}
this.map.get(action)!.add(listener);
return this.map.get(action)!.size;
}
remove(action: string, listener: Listener) {
const listeners = this.map.get(action);
if (!listeners) return 0;
listeners.delete(listener);
if (listeners.size === 0) {
this.map.delete(action);
return 0;
}
return listeners.size;
}
emit(action: string, query: Query) {
const actionListeners = this.map.get(action);
if (!actionListeners) return 0;
actionListeners.forEach((listener) => listener(query));
return actionListeners.size;
}
}
const protocols = ["apmstore"];
const listeners = new ListenersMap();
export const deepLink = {
on: (event: string, listener: Listener) => {
const count = listeners.add(event, listener);
console.log(
`Deep link: listener added for event ${event}. Total event listeners: ${count}`
);
},
off: (event: string, listener: Listener) => {
const count = listeners.remove(event, listener);
console.log(
`Deep link: listener removed for event ${event}. Total event listeners: ${count}`
);
},
once: (event: string, listener: Listener) => {
const onceListener: Listener = (query) => {
deepLink.off(event, onceListener);
listener(query);
};
deepLink.on(event, onceListener);
},
};
app.on("second-instance", (_e, commandLine) => {
const target = commandLine.find((arg) =>
protocols.some((protocol) => arg.startsWith(protocol + "://"))
);
if (!target) return;
console.log(`Deep link: protocol link got: ${target}`);
try {
const url = new URL(target);
const action = url.hostname;
console.log(`Deep link: action found: ${action}`);
const query: Query = {};
url.searchParams.forEach((value, key) => {
query[key] = value;
});
console.log(`Deep link: query found: ${JSON.stringify(query)}`);
const emitCount = listeners.emit(action, query);
console.log(`Deep link: emitted for ${emitCount} listeners`);
} catch (error) {
console.error(`Deep link: error parsing URL: ${error}`);
}
});

View File

@@ -1,5 +1,6 @@
import { dialog } from 'electron' import { dialog } from 'electron'
import { deepLink } from './deeplink';
export async function handleUrlScheme(requestUrl: string) { deepLink.on("event", (query) => {
console.log('Handling URL scheme request:', requestUrl); console.log(`Deep link: event "event" fired with query: ${JSON.stringify(query)}`);
} });

View File

@@ -3,14 +3,15 @@ import { createRequire } from 'node:module'
import { fileURLToPath } from 'node:url' import { fileURLToPath } from 'node:url'
import path from 'node:path' import path from 'node:path'
import os from 'node:os' import os from 'node:os'
import { electronAppUniversalProtocolClient } from 'electron-app-universal-protocol-client'
import { handleUrlScheme } from './handle-url-scheme.js' import './handle-url-scheme.js'
// Assure single instance application
if (!app.requestSingleInstanceLock()) { if (!app.requestSingleInstanceLock()) {
app.exit(0); app.exit(0);
} }
const require = createRequire(import.meta.url) const require = createRequire(import.meta.url)
const __dirname = path.dirname(fileURLToPath(import.meta.url)) const __dirname = path.dirname(fileURLToPath(import.meta.url))
@@ -83,17 +84,6 @@ async function createWindow() {
return { action: 'deny' } return { action: 'deny' }
}) })
// win.webContents.on('will-navigate', (event, url) => { }) #344 // win.webContents.on('will-navigate', (event, url) => { }) #344
// Initialize universal protocol client
electronAppUniversalProtocolClient.on(
'request',
handleUrlScheme
);
await electronAppUniversalProtocolClient.initialize({
protocol: 'apmstore',
mode: 'development', // Make sure to use 'production' when script is executed in bundled app
});
} }
app.whenReady().then(createWindow) app.whenReady().then(createWindow)

View File

@@ -29,7 +29,7 @@
"@dotenvx/dotenvx": "^1.51.4", "@dotenvx/dotenvx": "^1.51.4",
"@vitejs/plugin-vue": "^5.0.4", "@vitejs/plugin-vue": "^5.0.4",
"electron": "^39.2.7", "electron": "^39.2.7",
"electron-app-universal-protocol-client": "^2.1.1", "electron-app-universal-protocol-client": "github:witcher112/electron-app-universal-protocol-client",
"electron-builder": "^24.13.3", "electron-builder": "^24.13.3",
"typescript": "^5.4.2", "typescript": "^5.4.2",
"vite": "^5.1.5", "vite": "^5.1.5",