Skip to content

Instantly share code, notes, and snippets.

@diachedelic
Last active June 25, 2024 18:17
Show Gist options
  • Save diachedelic/0d60233dab3dcae3215da8a4dfdcd434 to your computer and use it in GitHub Desktop.
Save diachedelic/0d60233dab3dcae3215da8a4dfdcd434 to your computer and use it in GitHub Desktop.
Deep link to a native app from a browser, with a fallback
@diachedelic
Copy link
Author

Test in Safari on iOS 13.3 and Google Chrome v80 on MacOS

@mesutucar
Copy link

Worked like a charm. You saved my day. Thank you.

@AC-devon
Copy link

onIgnored not triggered when browser failed to respond to the deep link in IOS safari 13.4.1

@diachedelic
Copy link
Author

@amir0900 do you get an alert like "Safari cannot open the page because the address is invalid"? In that situation, onFallback is called rather than onIgnored (tested on iOS simulator 13.4.1)

@AC-devon
Copy link

yea, but in case i have the app i end up with 2 application open (appstore & my app) in case of onfallback, maybe because of the safari alert delay...

@diachedelic
Copy link
Author

@amir0900 I believe I've fixed your issue, can you please test it out? cheers

@abeltolu
Copy link

abeltolu commented Jun 8, 2020

Life saver! Thanks a lot

Copy link

ghost commented Aug 7, 2020

I've got the same behavior on iOS 13.5.1 (real device) as @diachedelic had it on iOS 13.3. But i think there is no difference between "can not open url, tapped on ok" and "can open url, but tapped on canel". They will trigger the same events.
But for me it's ok to handle both cases, onIgnore & onFallback, as the same.

For a better soultion i think we have to use UniversalLinks.

@diachedelic
Copy link
Author

@spaschold yes, universal links are a much better solution - I wrote this library to support a legacy app, in our newer app we use universal links exclusively.

@vatsal-gadhiya-searce
Copy link

In my case using IOS in safari, when app is already installed. It redirects to the native app (which is good) but then again redirect it to appstore as well (onIgnored called). I am frustrated on how to get rid of this. This is really a good solution but again there is no difference if we use simple redirect line of app link and setTimeOut and redirect to store only instead of this fancy onFocus and visibility events etc things.

If anyone has solution for this? @diachedelic

@diachedelic
Copy link
Author

Are you able to discover why onVisibilityChange is not being called after the native app opens, @vatsal-gadhiya-searce? Perhaps dialogTimeout needs to be increased? What version of iOS are you using?

@vatsal-gadhiya-searce
Copy link

vatsal-gadhiya-searce commented Apr 14, 2021

@diachedelic Thanks for your response, I am using IOS 14.4.2(iPhone XR) and safari 14.4.2. But i am sure, it is not related to IOS version. As i have already tested in many versions. It's the same behaviour. It's not consistence actually. sometimes it works sometimes it doesn't.

Also as you said about onVisibilityChange is not being called right, but i guess it's about onBlur as you are changing hasFocus to false onBlur and checking it in onIgnored. correct me if i am wrong.

Just FYI: I have not written any code of redirection inside onFallback and onReturn. it's onIgnored only where i have appstore redirection.

Code usage:

 var url = 'noq://home';
  var appURL = 'https://apps.apple.com/gb/app/noq/id1515913853'
  var linker = new DeepLinker({
    onIgnored: function() {
      window.location = appURL;
      console.log('browser failed to respond to the deep link');
    },
    onFallback: function() {
       console.log('dialog hidden or user returned to tab');
    },
    onReturn: function() {
      console.log('user returned to the page from the native app');
    },
  });
  linker.openURL(url);

Steps to reproduce:
If the app is not installed it calls onIgnored and redirect to Appstore (which is fine). Install the app from Appstore, Again open the same or other link, it redirects to the native app(which is fine) but again take me back to Appstore (which is weird) and I debug and found that onIgnored has been called even it redirects me to native app.

It would be life saver! if we get the solution for this @diachedelic

I am happy to debug as per your suggestion.

@diachedelic
Copy link
Author

Install the app from Appstore, Again open the same or other link, it redirects to the native app

@vatsal-gadhiya-searce, does a dialog appear at this point, asking if you would like to open the native app? That is the expected behaviour.

@vatsal-gadhiya-searce
Copy link

vatsal-gadhiya-searce commented Apr 14, 2021

@diachedelic Yup, The dialog appears like "Open this in NOQ"? click ok redirects to the native app and then again redirect back to browser opening Appstore.

One thing i observed, if i close all the tabs of safari and open the link it works. it doesn't redirect back to the browser after native redirection when the app already installed.

@diachedelic
Copy link
Author

@vatsal-gadhiya-searce, can you please increase dialogTimeout to 5000 and check if onBlur is called when that dialog is shown?

@vatsal-gadhiya-searce
Copy link

@diachedelic, increased dialogTimeout to 5000. onBlur is called but it is still inconsistent. sometimes called sometimes it doesn't.

@diachedelic
Copy link
Author

@vatsal-gadhiya-searce Ahh that's a shame. I'm afraid I can't help you if that's the case :(

@vatsal-gadhiya-searce
Copy link

So Universal links only :) No solution.

@biandtlp
Copy link

Hello, is it possible to hide the alert "Safari cannot open the page because the address is invalid"?
Or we have to use Universal links for this?
Thank you

@diachedelic
Copy link
Author

It is not possible "check" whether the browser can handle a certain type of deep link for security reasons, sorry @biandtlp.

@luizcieslak
Copy link

Hey @diachedelic, very nice writeup. Do you happen to know if there's a way to open to Safari via deeplink? I tested using this URL for google chrome: googlechrome://www.google.com and it works nicely but I wonder if there's the same thing for Safari.

@diachedelic
Copy link
Author

Hey @luizcieslak, I didn't know you could do that with Chrome! Sorry but I don't know about Safari.

@david-baul
Copy link

I'm not the type to leave comments. Thank you so much. God bless you

@MarcoYolanga
Copy link

Thank you king

@johnny-mnemonica
Copy link

working on iOS 17.0.3, had to tweak the timeout values a bit but otherwise works beautifully, ty.
behaviour in safari is if user does not have the app installed, onFallback is triggered.
in chrome, onIgnored is triggered. onReturn fires as expected in both browsers

@cody-dashka
Copy link

cody-dashka commented Oct 27, 2023

try this.

function openDeepLink(url: string, options?: Partial<{ onOpen?: () => void; onFail?: () => void; waitTime?: number }>) {
  let timeout: NodeJS.Timeout;
  let interval: NodeJS.Timer;
  let visible: DocumentVisibilityState = 'visible';

   const handleOpen = () => {
      window.removeEventListener('visibilitychange', () => true);
      options?.onOpen?.();
  };
  const handleResponse = () => {
    if (visible === 'visible') return options?.onFail?.();
    clearInterval(interval);
    handleOpen();
  };

  try {
    window.addEventListener('visibilitychange', (e) => (visible = (e.target as Document)?.visibilityState));
    timeout = setTimeout(handleResponse, options?.waitTime || 5000);

    interval = setInterval(() => {
      if (visible === 'hidden') {
        clearTimeout(timeout);
        handleResponse();
      }
    }, options?.waitTime || 5000);

    window.location.href = url;
  } catch (error) {
    options?.onFail?.();
  }
}

openDeepLink("fb://profile/100004452732850", {onOpen: console.log, onFail: console.error});

@MTPGI
Copy link

MTPGI commented Mar 25, 2024

Tested on last version of Firefox 124, Android 13. Not working because even if a dialog appears to redirect to the app, the pages doesn't loose focus.

@diachedelic
Copy link
Author

Can it be fixed?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment