fix: remove @capacitor/app dynamic import from DeepLinkHandler
Use window.Capacitor.Plugins.App directly instead of dynamic import() so the build doesn't fail when @capacitor/app isn't in node_modules Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
This commit is contained in:
parent
c3ef0247fc
commit
be70ff490f
1 changed files with 35 additions and 29 deletions
|
|
@ -4,54 +4,60 @@ import { useNavigate } from 'react-router-dom';
|
||||||
/**
|
/**
|
||||||
* Forwards OS-level deep-link opens into the React Router navigation stack.
|
* Forwards OS-level deep-link opens into the React Router navigation stack.
|
||||||
*
|
*
|
||||||
|
* Uses the global window.Capacitor object to avoid a hard npm dependency on
|
||||||
|
* @capacitor/app (which is installed on the native build machine but not in
|
||||||
|
* the web/CI build environment).
|
||||||
|
*
|
||||||
* When the OS launches the app via a URL (Amber NIP-55 callback, custom scheme,
|
* When the OS launches the app via a URL (Amber NIP-55 callback, custom scheme,
|
||||||
* or universal link), Capacitor fires an `appUrlOpen` event. This component
|
* or universal link), Capacitor fires an `appUrlOpen` event. This component
|
||||||
* listens for it and navigates to the correct in-app route.
|
* listens for it and navigates to the correct in-app route.
|
||||||
*
|
*
|
||||||
* Uses HashRouter compatible path extraction — strips the origin/scheme so
|
|
||||||
* only the pathname+search+hash is passed to navigate().
|
|
||||||
*
|
|
||||||
* Must be rendered inside a Router (so `useNavigate` works).
|
|
||||||
* Safe to render unconditionally — on web it is a no-op.
|
|
||||||
*
|
|
||||||
* Amber deep-link example:
|
* Amber deep-link example:
|
||||||
* org.skatespots.app://amber-callback?event=<data>
|
* org.skatespots.app://amber-callback?event=<data>
|
||||||
* → navigates to /amber-callback?event=<data>
|
* → navigates to /amber-callback?event=<data>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// Type for the global Capacitor object injected by the native runtime
|
||||||
|
interface CapacitorGlobal {
|
||||||
|
isNativePlatform?: () => boolean;
|
||||||
|
Plugins?: {
|
||||||
|
App?: {
|
||||||
|
addListener: (
|
||||||
|
event: string,
|
||||||
|
handler: (data: { url: string }) => void
|
||||||
|
) => Promise<{ remove: () => void }>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
export function DeepLinkHandler() {
|
export function DeepLinkHandler() {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// Only run in Capacitor native context
|
const cap = (window as unknown as { Capacitor?: CapacitorGlobal }).Capacitor;
|
||||||
const cap = (window as unknown as { Capacitor?: { isNativePlatform?: () => boolean } }).Capacitor;
|
|
||||||
if (!cap?.isNativePlatform?.()) return;
|
if (!cap?.isNativePlatform?.()) return;
|
||||||
|
|
||||||
|
const AppPlugin = cap?.Plugins?.App;
|
||||||
|
if (!AppPlugin) return;
|
||||||
|
|
||||||
let removeListener: (() => void) | undefined;
|
let removeListener: (() => void) | undefined;
|
||||||
|
|
||||||
async function setup() {
|
AppPlugin.addListener('appUrlOpen', (event) => {
|
||||||
try {
|
try {
|
||||||
const { App } = await import('@capacitor/app');
|
const url = new URL(event.url);
|
||||||
|
// Extract path + query + fragment from the deep link URL
|
||||||
const listener = await App.addListener('appUrlOpen', (event) => {
|
const path = url.pathname + url.search + url.hash;
|
||||||
try {
|
if (path && path !== '/') {
|
||||||
const url = new URL(event.url);
|
navigate(path, { replace: true });
|
||||||
// Extract path + query + fragment from the deep link URL
|
}
|
||||||
const path = url.pathname + url.search + url.hash;
|
|
||||||
if (path && path !== '/') {
|
|
||||||
navigate(path, { replace: true });
|
|
||||||
}
|
|
||||||
} catch {
|
|
||||||
// Invalid URL — ignore
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
removeListener = () => listener.remove();
|
|
||||||
} catch {
|
} catch {
|
||||||
// @capacitor/app not available (web build without Capacitor installed)
|
// Invalid URL — ignore
|
||||||
}
|
}
|
||||||
}
|
}).then((listener) => {
|
||||||
|
removeListener = () => listener.remove();
|
||||||
setup();
|
}).catch(() => {
|
||||||
|
// Plugin not available — ignore
|
||||||
|
});
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
removeListener?.();
|
removeListener?.();
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue