-
-
Save davidwkeith/2662899 to your computer and use it in GitHub Desktop.
<!doctype html> | |
<html> | |
<head> | |
<meta charset="utf-8"> | |
<title>App Redirection</title> | |
</head> | |
<body> | |
<!-- | |
NOTE: This was a great hack in days gone by, but now both Apple and Google have improved their support for custom | |
protocol handlers. | |
# References | |
* Handle Open URL: http://handleopenurl.com/ | |
* iOS Smart App Banners: https://developer.apple.com/library/content/documentation/AppleApplications/Reference/SafariWebContent/PromotingAppswithAppBanners/PromotingAppswithAppBanners.html | |
* Android Intents: https://developer.android.com/reference/android/content/Intent.html | |
* On the desktop you still need to make a custom plugin to do the right thing, or save some sort of user prefernce. | |
--> | |
<!-- iframe used for attempting to load a custom protocol --> | |
<iframe style="display:none" height="0" width="0" id="loader"></iframe> | |
<script>(function(){ | |
// For desktop browser, remember to pass though any metadata on the link for deep linking | |
var fallbackLink = 'http://example.com/my-web-app/'+window.location.search+window.location.hash; | |
// Simple device detection | |
var isiOS = navigator.userAgent.match('iPad') || navigator.userAgent.match('iPhone') || navigator.userAgent.match('iPod'), | |
isAndroid = navigator.userAgent.match('Android'); | |
// Mobile | |
if (isiOS || isAndroid) { | |
// Load our custom protocol in the iframe, for Chrome and Opera this burys the error dialog (which is actually HTML) | |
// for iOS we will get a popup error if this protocol is not supported, but it won't block javascript | |
document.getElementById('loader').src = 'custom-protocol://my-app'+window.location.search+window.location.hash; | |
// The fallback link for Android needs to be https:// rather than market:// or the device will try to | |
// load both URLs and only the last one will win. (Especially FireFox, where an "Are You Sure" dialog will appear) | |
// on iOS we can link directly to the App Store as our app switch will fire prior to the switch | |
// If you have a mobile web app, your fallback could be that instead. | |
fallbackLink = isAndroid ? 'https://play.google.com/store/apps/details?id=com.mycompany.myapp' : | |
'itms-apps://itunes.apple.com/app/my-app/idxxxxxxxx?mt=8' ; | |
} | |
// Now we just wait for everything to execute, if the user is redirected to your custom app | |
// the timeout below will never fire, if a custom app is not present (or the user is on the Desktop) | |
// we will replace the current URL with the fallbackLink (store URL or desktop URL as appropriate) | |
window.setTimeout(function (){ window.location.replace(fallbackLink); }, 1); | |
/* | |
Q&A | |
I have a native desktop app as well, how do I link to a custom protocol handler on the desktop? | |
IE Only: http://msdn.microsoft.com/en-us/library/ms537512.aspx#Version_Vectors | |
All Other Browsers: Use a custom plugin like iTunes does: http://ax.itunes.apple.com/detection/itmsCheck.js | |
*/ | |
})();</script> | |
</body> | |
</html> |
This looks great, any chance you could add some license information to the gist?
This method is similar to others I have seen but it has a major flaw in that the timer will still run when you come back to the page later. Thus you always end up on your fallback page which is, in the example, the app store. Not quite the best user experience. It would be better if we could figure out how to kill the timer totally once it complete's once.
This answer on SO describes one way to avoid the problem @jimadamsss describes
Did anyone find a fix for the =Chrome issue? thanks
@bsurtz - Check out the Chrome page. You have to use something different for Chrome 25 and later.
thanks for your comment @aaronschneiderbelkin. I'm now using two separated links:
- procotol://host/ (for iOS)
- intent://host/#Intent;scheme=protocol;package=com.domain.apppackage;end (for Android browsers)
On the end, I have something like this:
function openApp() {
var isiOS = navigator.userAgent.match('iPhone') || navigator.userAgent.match('iPod');
var isAndroid = navigator.userAgent.match('Android');
if (isiOS) {
document.getElementById('loader').src = "{{ mobileURI }}";
}
else if (isAndroid) {
window.location = "{{ androidIntentURI }}";
}
}
(function(){
openApp();
})();
Hello colaboradores,
Iphone is working fine, but in android i want to check only the application is installed or not, in your code if not installed then redirect to play store. Is there any way to stay there if application is not installed
I wonder same solution as rahuljodhani!!
any possibility to use intent and not redirect to google play if application is not installed???
As our friends rahuljodhani and fengyuanyang asked, can we checked if the app is instaled on Android and iOS?
For Chrome I have only found the following 2 ways to open the app
window.location = "customprotocol://"
window.location.assign('customprotocol://')
If the app is not installed it will land you on a About:Blank or a page that says the protocol isn't registered / does not exist.
What I found to work is setting the window.location to my protocol and then doing a settimeout for a very short time 5ms or less that will attempt the fallback url such as the apps Google Play listing. The issue I still encounter with this is the app will launch and the Default App launcher is started 50% of the time behind the app that just opened and the other 50% in front of the app asking what I want to do with the google play URL as in Open in the Google Play app or use the webbrowser.
While that works it disrupts UX which isn't good.
@andresmafra You can via native code but via javascript I have not found a way.
I am getting the same issue @delconis in android (till KitKat) but in Andoird Lollipop version its not working any more. Its not opening our application first, its was asking to open the play store url and there is no way to skip this step. Please give me some solution for this.
FYI: I have tested it in Moto G 2nd generation(Lollipop)
Hi, I have an issue with safari, when my app is not installed, i got an alert saying can't open page before redirecting to store url
Hi Cedriclombardot,
I have modified the above code, which works fine in all mobile and desktop browsers including chrome & it won't give you any alert msg, kindly use the below piece of code 😄
<!doctype html>
<title>App Redirection</title> <script src="//ajax.googleapis.com/ajax/libs/jquery/1.8/jquery.min.js"></script> <script> function openApp() { //see if our window is active window.isActive = true; $(window).focus(function() { this.isActive = true; }); $(window).blur(function() { this.isActive = false; }); // For desktop browser, remember to pass though any metadata on the link for deep linking
var fallbackLink = 'your website url';
// Simple device detection
var isiOS = navigator.userAgent.match('iPad') || navigator.userAgent.match('iPhone') || navigator.userAgent.match('iPod'),
isAndroid = navigator.userAgent.match('Android'), isWindow = navigator.userAgent.match('Windows Phone');
// Mobile
if (isiOS || isAndroid || isWindow) {
// Load our custom protocol in the iframe, for Chrome and Opera this burys the error dialog (which is actually HTML)
// for iOS we will get a popup error if this protocol is not supported, but it won't block javascript
var isMobile = /iPhone|iPad|iPod|Android/i.test(navigator.userAgent);
if (isMobile) {
var isChrome = /Chrome/.test(navigator.userAgent) && /Google Inc/.test(navigator.vendor);
var isSafari = /Safari/.test(navigator.userAgent) && /Apple Computer/.test(navigator.vendor);
if (isChrome){
window.location = 'custom-protocol://my-app';
}else
{
document.getElementById('loader').src = 'custom-protocol://my-app';
}
}
// The fallback link for Android needs to be https:// rather than market:// or the device will try to
// load both URLs and only the last one will win. (Especially FireFox, where an "Are You Sure" dialog will appear)
// on iOS we can link directly to the App Store as our app switch will fire prior to the switch
// If you have a mobile web app, your fallback could be that instead.
fallbackLink = isAndroid ? 'https://play.google.com/store/apps/details?id=com.mycompany.myapp' :
'itms-apps://itunes.apple.com/app/my-app/idxxxxxxxx?mt=8' ;
}
// Now we just wait for everything to execute, if the user is redirected to your custom app
// the timeout below will never fire, if a custom app is not present (or the user is on the Desktop)
// we will replace the current URL with the fallbackLink (store URL or desktop URL as appropriate)
window.setTimeout(function (){
if (window.isActive) {
window.location.replace(fallbackLink);
}
}, 1000);
/*
Q&A
I have a native desktop app as well, how do I link to a custom protocol handler on the desktop?
IE Only: http://msdn.microsoft.com/en-us/library/ms537512.aspx#Version_Vectors
All Other Browsers: Use a custom plugin like iTunes does: http://ax.itunes.apple.com/detection/itmsCheck.js
*/
};
window.onload = function()
{
var button = document.getElementById("button");
button.onclick = function()
{
openApp();
};
};
</script>
<style type="text/css">
#button
{
border:1px solid #7c5b2b; -webkit-border-radius: 3px; -moz-border-radius: 3px;border-radius: 3px;font-size:12px;font-family:arial, helvetica, sans-serif; padding: 10px 10px 10px 10px; text-decoration:none; display:inline-block;text-shadow: -1px -1px 0 rgba(0,0,0,0.3);font-weight:bold; color: #FFFFFF;
background-color: #a67939; background-image: -webkit-gradient(linear, left top, left bottom, from(#a67939), to(#845108));
background-image: -webkit-linear-gradient(top, #a67939, #845108);
background-image: -moz-linear-gradient(top, #a67939, #845108);
background-image: -ms-linear-gradient(top, #a67939, #845108);
background-image: -o-linear-gradient(top, #a67939, #845108);
background-image: linear-gradient(to bottom, #a67939, #845108);filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0,startColorstr=#a67939, endColorstr=#845108);
}
</style>
<iframe style="display:none" height="0" width="0" id="loader"></iframe>
doesn't work with iOS9
iOS 9 fail 👎
doesn't work with iOS9
document.getElementById('loader').src = '{{ url }}';
this does not work in iOS 9
This mostly worked for me...major gotcha for iOS is that you cannot start your custom protocol with a number. Evidently that get's url encoded and the redirect will fail since it would find that registered with an app. Specifically, I noticed that 9 gets reencoded as %39
Safair has already not support call up app by iframe after iOS9.
Safair has already not support call up app by iframe after iOS9.
@maquannene did you find any solution for this ??
document.getElementById('loader').src = '{{ url }}';
this does not work in iOS 9
Hi, Did you find any solution for this ??
How do you pass data to the appstore - to the itms link?
@quantumpotato You really shouldn't be using this hack anymore. Use Smart App Banners on iOS and Intents on Android.
@davidwkeith can you pass data to be loaded by the app when it boots up with smart banners?
yes, just provided an app-argument
in the content
parameters of the Smart App Banner meta tag.
See the official documentation here https://developer.apple.com/documentation/webkit/promoting_apps_with_smart_app_banners
Thank you
Thank you
So far I can only get this to work in the non-Chrome default Android browser (pre Jelly Bean). In Chrome, the custom protocol is not picked up by the app when I set it as the source of the iframe. Any thoughts?