feat: support url scheme to launch app

Closes #159
This commit is contained in:
talksik
2026-04-13 10:41:11 -07:00
parent f676baf8b3
commit ae91145762
2 changed files with 42 additions and 0 deletions
+3
View File
@@ -12,6 +12,9 @@ const config: ForgeConfig = {
asar: true,
icon: './assets/flowy',
appBundleId: 'live.flowy.llink',
protocols: [
{ name: 'llink', schemes: ['llink'] },
],
extendInfo: {
NSMicrophoneUsageDescription: 'llink needs microphone access to record audio messages.',
NSCameraUsageDescription: 'llink needs camera access to record video messages.',
+39
View File
@@ -25,6 +25,21 @@ if (process.platform === 'darwin' && !app.isPackaged) {
app.dock?.setIcon(path.join(__dirname, '../../assets/icon.png'));
}
// Single-instance lock: on Windows/Linux, clicking a llink:// URL launches a new
// process. The lock makes the losing instance quit and fires `second-instance` on
// the primary, so we focus the existing window instead of spawning a duplicate.
// macOS uses `open-url` instead and doesn't need this, but the lock is harmless.
if (!app.requestSingleInstanceLock()) {
app.quit();
}
// Register llink:// as the default handler for this app. macOS also gets this
// declaratively via CFBundleURLTypes (forge.config.ts `protocols`); Windows relies
// on this runtime call (Squirrel doesn't register protocols on install).
if (!app.isDefaultProtocolClient('llink')) {
app.setAsDefaultProtocolClient('llink');
}
let mainWindow: BrowserWindow | null = null;
let autoplayWindow: BrowserWindow | null = null;
let huddleWindow: BrowserWindow | null = null;
@@ -438,6 +453,8 @@ ipcMain.on('app:set-dock-badge', (_event, count: number) => {
}
});
ipcMain.handle('app:get-version', () => app.getVersion());
ipcMain.handle('link:fetch-metadata', async (_event, url: string) => {
if (typeof url !== 'string') return null;
try {
@@ -517,5 +534,27 @@ app.on('activate', () => {
}
});
function focusMainWindow() {
if (!mainWindow) return;
if (mainWindow.isMinimized()) mainWindow.restore();
if (!mainWindow.isVisible()) mainWindow.show();
mainWindow.focus();
}
// macOS delivers llink:// URLs via this event, both when the app is already
// running and on cold start (after `ready`). We prevent the default to silence
// Electron's warning and focus the window — OS-level focus alone won't restore
// a hidden or minimized window. Cold start is handled by createWindow().
app.on('open-url', (event) => {
event.preventDefault();
focusMainWindow();
});
// Windows/Linux: the OS launches a second process with the URL in argv; the
// single-instance lock diverts it here on the primary instance.
app.on('second-instance', () => {
focusMainWindow();
});
// In this file you can include the rest of your app's specific main process
// code. You can also put them in separate files and import them here.