Skip to content

Commit

Permalink
fix: deeplink can be flakey (#1831)
Browse files Browse the repository at this point in the history
  • Loading branch information
aeharding authored Jan 30, 2025
1 parent b66b6fd commit 2720882
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 15 deletions.
8 changes: 7 additions & 1 deletion android/app/src/main/java/app/vger/voyager/MainActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,13 @@ protected void onNewIntent(Intent intent) {
return;
}

newIntent.setData(Uri.parse(potentialUrl));
Uri uri = Uri.parse(potentialUrl);

// Add a timestamp to the URL to let app know it is not stale
Uri.Builder uriBuilder = uri.buildUpon();
long currentTime = System.currentTimeMillis() / 1000L;
uriBuilder.appendQueryParameter("t", String.valueOf(currentTime));
newIntent.setData(uriBuilder.build());

bridge.onNewIntent(newIntent);
}
Expand Down
4 changes: 4 additions & 0 deletions ios/App/VoyagerActionExtension/ActionRequestHandler.swift
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,10 @@ extension URL {
var iceCubesAppDeepLink: URL {
var components = URLComponents(url: self, resolvingAgainstBaseURL: false)!
components.scheme = "vger"

// Add a timestamp so the app can check if the deep link is stale or not
components.queryItems = (components.queryItems ?? []) + [URLQueryItem(name: "t", value: String(Int(Date().timeIntervalSince1970)))]

return components.url!
}
}
Expand Down
54 changes: 40 additions & 14 deletions src/core/listeners/AppUrlListener.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,17 @@ import { deepLinkFailed } from "#/helpers/toastMessages";
import useAppToast from "#/helpers/useAppToast";
import { useAppSelector } from "#/store";

const PREVIOUS_APP_URL_STORAGE_KEY = "previous-app-url";

(async () => {
const response = await App.getLaunchUrl();

// If normal startup, remove previous app url
if (!response?.url) localStorage.removeItem(PREVIOUS_APP_URL_STORAGE_KEY);
})();

export default function AppUrlListener() {
const presentToast = useAppToast();
const { redirectToLemmyObjectIfNeeded } = useLemmyUrlHandler();
const knownInstances = useAppSelector(
(state) => state.instances.knownInstances,
Expand All @@ -21,33 +31,51 @@ export default function AppUrlListener() {
);
const deepLinkReady = useAppSelector((state) => state.deepLinkReady.ready);

const appUrlToOpen = useRef<string | undefined>();
const presentToast = useAppToast();
const appUrlFromEventRef = useRef<string>();

const notReady =
!knownInstances ||
knownInstances === "pending" ||
!connectedInstance ||
!deepLinkReady;

const onAppUrl = async (url: string) => {
if (notReady) {
appUrlToOpen.current = url;
const onAppUrlIfNeeded = async () => {
// wait for router to get into a good state before pushing
// (needed for pushing user profiles from app startup)
if (notReady) return;

// If appUrl received from explicit event, redirect to it
if (appUrlFromEventRef.current) {
redirectTo(appUrlFromEventRef.current);
appUrlFromEventRef.current = undefined;
return;
}

// wait for router to get into a good state before pushing
// (needed for pushing user profiles from app startup)
const result = await redirectToLemmyObjectIfNeeded(url);
const url = (await App.getLaunchUrl())?.url;

if (result === "not-found") presentToast(deepLinkFailed);
if (!url) return;

// If appUrl received from launch, redirect to it if it's not stale
// (the appUrl could be stale if web process was killed, but native wrapper wasn't)
if (url === localStorage.getItem(PREVIOUS_APP_URL_STORAGE_KEY)) return;

redirectTo(url);
};

const onAppUrlEvent = useEffectEvent(onAppUrl);
async function redirectTo(url: string) {
const result = await redirectToLemmyObjectIfNeeded(normalizeObjectUrl(url));

if (result === "not-found") presentToast(deepLinkFailed);

localStorage.setItem(PREVIOUS_APP_URL_STORAGE_KEY, url);
}

const onAppUrlIfNeededEvent = useEffectEvent(onAppUrlIfNeeded);

useEffect(() => {
const listener = App.addListener("appUrlOpen", (event) => {
onAppUrlEvent(normalizeObjectUrl(event.url));
appUrlFromEventRef.current = event.url;
onAppUrlIfNeededEvent();
});

return () => {
Expand All @@ -57,10 +85,8 @@ export default function AppUrlListener() {

useEffect(() => {
if (notReady) return;
if (!appUrlToOpen.current) return;

onAppUrlEvent(appUrlToOpen.current);
appUrlToOpen.current = undefined;
onAppUrlIfNeededEvent();
}, [notReady]);

return null;
Expand Down

0 comments on commit 2720882

Please sign in to comment.