BookNest's book page now opens from both kinds of link, booknest://book/3 and https://booknest.example.com/book/3. expo-linking supplies useLinkingURL(), a hook that returns the URL the app was opened with and then each new one, parse(), which splits a URL into scheme, hostname, path and query, and createURL(), which builds a link for the current environment (logged as booknest://book/3 here).
// booknest://book/3 and https://booknest.example.com/book/3 both open book 3
export function bookIdFrom(url: string | null): number | null {
if (!url) return null;
const { scheme, hostname, path, queryParams } = Linking.parse(url);
// booknest://book/3 parses "book" as the hostname; https://host/book/3 keeps it in path
const route = scheme === 'booknest' ? `${hostname}/${path}` : path;
console.log('parsed', JSON.stringify({ hostname, path, route, queryParams }));
const m = /^book\/(\d+)$/.exec(route ?? '');
return m ? Number(m[1]) : null;
}
// ...inside BookLinks:
const url = Linking.useLinkingURL(); // initial URL, then every new one
const [book, setBook] = useState<Book | undefined>();
useEffect(() => {
const id = bookIdFrom(url);
if (id != null) setBook(books.find((b) => b.id === id));
}, [url]);The route line exists because the first version failed: booknest://book/5 parsed as hostname book and path 5, so a regular expression on the path matched nothing. With the fix, a cold start from adb shell am start -a android.intent.action.VIEW -d booknest://book/5 com.anonymous.booknest, followed by an App Link while the app was open, logged:
ReactNativeJS: 'parsed', '{"hostname":"book","path":"5","route":"book/5","queryParams":{}}'
ReactNativeJS: 'parsed', '{"hostname":"booknest.example.com","path":"book/3","route":"bo...The App Link first opened Chrome 1 , since the domain failed verification, until pm set-app-links-user-selection approved the domain for BookNest, as a user can under Open by default (Sharing a Book from BookNest's figure). Validate every incoming id, and never let a link buy or delete anything unconfirmed.