-
-
Save diachedelic/0d60233dab3dcae3215da8a4dfdcd434 to your computer and use it in GitHub Desktop.
function DeepLinker(options) { | |
if (!options) { | |
throw new Error('no options') | |
} | |
var hasFocus = true; | |
var didHide = false; | |
// window is blurred when dialogs are shown | |
function onBlur() { | |
hasFocus = false; | |
}; | |
// document is hidden when native app is shown or browser is backgrounded | |
function onVisibilityChange(e) { | |
if (e.target.visibilityState === 'hidden') { | |
didHide = true; | |
} | |
}; | |
// window is focused when dialogs are hidden, or browser comes into view | |
function onFocus() { | |
if (didHide) { | |
if (options.onReturn) { | |
options.onReturn(); | |
} | |
didHide = false; // reset | |
} else { | |
// ignore duplicate focus event when returning from native app on | |
// iOS Safari 13.3+ | |
if (!hasFocus && options.onFallback) { | |
// wait for app switch transition to fully complete - only then is | |
// 'visibilitychange' fired | |
setTimeout(function() { | |
// if browser was not hidden, the deep link failed | |
if (!didHide) { | |
options.onFallback(); | |
} | |
}, 1000); | |
} | |
} | |
hasFocus = true; | |
}; | |
// add/remove event listeners | |
// `mode` can be "add" or "remove" | |
function bindEvents(mode) { | |
[ | |
[window, 'blur', onBlur], | |
[document, 'visibilitychange', onVisibilityChange], | |
[window, 'focus', onFocus], | |
].forEach(function(conf) { | |
conf[0][mode + 'EventListener'](conf[1], conf[2]); | |
}); | |
} | |
// add event listeners | |
bindEvents('add'); | |
// expose public API | |
this.destroy = bindEvents.bind(null, 'remove'); | |
this.openURL = function(url) { | |
// it can take a while for the dialog to appear | |
var dialogTimeout = 500; | |
setTimeout(function() { | |
if (hasFocus && options.onIgnored) { | |
options.onIgnored(); | |
} | |
}, dialogTimeout); | |
window.location = url; | |
}; | |
} | |
/* usage */ | |
var url = 'fb://profile/240995729348595'; | |
var badURL = 'lksadjgajsdhfaskd://slkdfs'; | |
var linker = new DeepLinker({ | |
onIgnored: function() { | |
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); |
@vatsal-gadhiya-searce Ahh that's a shame. I'm afraid I can't help you if that's the case :(
So Universal links only :) No solution.
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
It is not possible "check" whether the browser can handle a certain type of deep link for security reasons, sorry @biandtlp.
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.
Hey @luizcieslak, I didn't know you could do that with Chrome! Sorry but I don't know about Safari.
I'm not the type to leave comments. Thank you so much. God bless you
Thank you king
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
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});
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.
Can it be fixed?
@diachedelic, increased
dialogTimeout
to5000
.onBlur
is called but it is still inconsistent. sometimes called sometimes it doesn't.