Skip to content

Instantly share code, notes, and snippets.

@davidwkeith
Last active April 10, 2024 12:01
Show Gist options
  • Save davidwkeith/2662899 to your computer and use it in GitHub Desktop.
Save davidwkeith/2662899 to your computer and use it in GitHub Desktop.
NOTE: This was a great hack in days gone by, but now both Apple and Google have improved their support for custom protocol handlers. Licensed under the WFTPL http://www.wtfpl.net/txt/copying/
<!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>
@anil1712
Copy link

anil1712 commented May 5, 2015

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)

@cedriclombardot
Copy link

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

@YogendraChauhan
Copy link

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>
Open App

@mdeora
Copy link

mdeora commented Sep 19, 2015

doesn't work with iOS9

@luigisaggese
Copy link

iOS 9 fail 👎

@curbsaleem
Copy link

doesn't work with iOS9

@ebsaral
Copy link

ebsaral commented Oct 27, 2015

document.getElementById('loader').src = '{{ url }}';

this does not work in iOS 9

@jonesmac
Copy link

jonesmac commented Jun 9, 2017

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

@maquannene
Copy link

Safair has already not support call up app by iframe after iOS9.

@yashwanthkumar1796
Copy link

Safair has already not support call up app by iframe after iOS9.

@maquannene did you find any solution for this ??

@yashwanthkumar1796
Copy link

document.getElementById('loader').src = '{{ url }}';

this does not work in iOS 9

Hi, Did you find any solution for this ??

@quantumpotato
Copy link

How do you pass data to the appstore - to the itms link?

@davidwkeith
Copy link
Author

@quantumpotato You really shouldn't be using this hack anymore. Use Smart App Banners on iOS and Intents on Android.

@quantumpotato
Copy link

@davidwkeith can you pass data to be loaded by the app when it boots up with smart banners?

@davidwkeith
Copy link
Author

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

@quantumpotato
Copy link

Thank you

@jjj201200
Copy link

Thank you

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