41

When user clicks link with custom protocol (like myapp://superlink)

I need either launch an app or allow user to download and run configuration app

I am looking for cross-browser way to check if custom protocol is registered

I've tried to determine this by checking user agent server-side (for IE)

[HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Internet Settings\5.0\User Agent\Post Platform] "myapp"=""

sends

`....NET CLR 3.0.30729; .NET4.0C; .NET4.0E; InfoPath.3; **myapp**`

as user-agent

This is good, clean way, easy configuration:

just download .reg file and run it or propagiate via ms windows policy

I can't fix this for Chrome and Firefox

Are there any client-side solution (in js)?

My enviroment: IE8+, Chrome (latest), Firefox(latest)

jonny
  • 1,326
  • 9
  • 44
  • 62
  • 1
    What happens if you send an AJAX request using the sample protocol and then test the response? – Lee Taylor Aug 22 '14 at 17:59
  • 1
    @LeeTaylor - that won't work. CORS issues will kick in. Maybe this might help http://stackoverflow.com/questions/836777/how-to-detect-browsers-protocol-handlers – Jibi Abraham Aug 23 '14 at 09:01
  • if (!navigator.isProtocolHandlerRegistered("myapp", url)) { navigator.registerProtocolHandler("myapp", url, "Fake Protocol"); } – dandavis Aug 25 '14 at 01:04
  • Hi! This super link actually starts our binary application (.exe) on client side or downloads installer, therefore no ajax can be used – jonny Aug 29 '14 at 17:16
  • I initially used habsq's code but it fails on some IE version then I tried https://gist.github.com/aaronk6/d801d750f14ac31845e8 and it works! – Qiulang Jul 02 '20 at 09:39

6 Answers6

29

There is this old tricks that it always never fails me.

The core functionality that you need is setTimeout. I will tell you in detail:

setTimeout(function() {
  window.location = "http://itunes.com/app/yourapplocation";
}, 200);

// once you do the custom-uri, it should properly execute the handler, otherwise, the settimeout that you set before will kick in
window.location = "myapp://superlink";

Now you mentioned that it maybe a link or links so I made this nice function just for your convenience:

HTML code

<a href="myapp://superlink" data-href-alt="http://itunes.com/app/yourapplocation">Click here</a>

JS code

$("a[href*='myapp://']").click(function(e)
{
  var el = $(this);
  setTimeout(function() {
    window.location = el.data("data-href-alt");
  }, 200);

  // once you do the custom-uri, it should properly execute the handler, otherwise, the settimeout that you set before will kick in
  window.location = el.data("href");

  e.preventDefault();
});

Hope this will help you :)

kororo
  • 1,972
  • 15
  • 26
  • I really like your jQuery code thats a nice and simple fix it might be worth bundling that into a plugin for jQuery sure loads of people would like to use that. – Barkermn01 Aug 29 '14 at 14:47
  • 1
    Hi! This super link actually starts our binary application (.exe) on client side or downloads installer, therefore no ajax can be used – jonny Aug 29 '14 at 17:17
  • 3
    This solution doesn't work for me. It opens the href and the alt-href. I would show you with a jsFiddle, but it doesn't like it when you set `window.location` –  Sep 02 '15 at 16:23
  • Seems to fail now on windows 10 build 1903 – Jeff Mar 06 '20 at 00:53
  • Firefox now shows a popup asking for permission to open the custom protocol. So this redirects to the fallback URL anyway. – Gaurang Tandon Jan 25 '23 at 09:26
20

I had a similar problem where I needed to check whether a custom protocol is already registered (which will open an executable file), or otherwise open a download page or do something else. Unfortunately there is no easy way to deal with this since every browser behaves differently. I tried to collect all information and come up with a rather generic library for this matter, you can take a look at:

https://github.com/ismailhabib/custom-protocol-detection

ps: the solution for non Windows 8 IE is rather ugly, but I couldn't find a better solution.

habsq
  • 1,827
  • 16
  • 17
  • 2
    So far on the browsers I have tested, this seems to work really well. Great work! – rolledback Nov 08 '16 at 18:23
  • Loved It Thank You So Much. Excellent Solution! – Ali Jamal Jun 21 '19 at 05:49
  • I am trying same library but it is not working for me. `onBlur` never triggers in any scenario whatever URI load successfully or failed. `var timeout = setTimeout` this function always triggers. Any idea if you faced? – Ambuj Khanna Oct 29 '20 at 09:17
10

kororo's solution wouldn't work for me for some reason, so I managed with this slightly modified solution instead.

<html>
<a id="link">Click Me</a>
<script>
var link = document.getElementById('link');
var timeout;
window.addEventListener('blur',function(e){
    window.clearTimeout(timeout);
})

link.addEventListener('click', function(e) { 

    timeout = window.setTimeout(function() {
      console.log('timeout');
      window.location = "https://myapp.net";
    }, 1000);

    window.location = "myapp://";
    e.preventDefault();
});
</script>
</html>
8

Note that as at February 2020, there doesn't seem to be a working way to do this. Only considering Chrome, neither the solution from @kororo or @habsq work at the moment. The reason is that what we're trying to achieve by checking if a URL protocol handler exists is actually considered as being a security risk by some people.

So my advice is to not persevere in trying to get this to work.

The best case scenario if you try to get this work is that you succeed until some browser removes the mechanism which let you "hack" your way into checking the url protocol, and then you're back to square one again.

An easier way here is to do what even very large sites do, and have javascript on your page saying something like:

window.location = "myprotocol://asdf";

which will either work or not, and then displaying a message on the page saying something along the lines of "if this didn't work, then please download our software at such and such a link"

Jack
  • 871
  • 1
  • 9
  • 17
  • 1
    another thing to add on: have a callback system with a unique browser id on the application to tell the server that the protocol got triggered so it doesn't need to show the download prompt – Yakov .P Jun 03 '22 at 01:49
  • @Yakov.P yeah, I thought this way too, but there are a couple of difficulties here, which prevent this from being a really good idea in my opinion. 1. If someone misses the download prompt the first time, then they won't have a way to install the program next time. 2. If someone uses a different browser, then this check will fail anyway. 3. If someone downloads the tool and uninstalls it, they won't have a way to reinstall again – Jack Jun 03 '22 at 04:54
  • 1
    It can check each time, it doesn't need to be one-time then never prompt again. (if the program is uninstalled, it won't run and it won't give the server a greenlight and thus, yielding another prompt) – Yakov .P Jun 10 '22 at 18:22
2

Update to Korono's answer, this worked for me:

$(function() {
    var timeIndex;
    $("a[href*='myapp://']").blur(function(e)
    {
        clearTimeout(timeIndex);
    });

    $("a[href*='myapp://']").click(function(e)
    {
      var el = $(this);
      timeIndex = setTimeout(function() {
        window.location = el.attr("data-href-alt");
      }, 200);

      // once you do the custom-uri, it should properly execute the handler, otherwise, the settimeout that you set before will kick in
      window.location = el.attr("href");
      e.preventDefault();
    });
});
-1

Salaam

Install ismailhabib/custom-protocol-detection

By including this JS file protocolcheck.js

Then write code something like this

<div id="protocol" href="myprotocol:johndoe@somewhere.com">Check Protocol</div>

<script>
        $("#protocol").click(function (event) {
            protocolCheck($(this).attr("href"), function () {
                    alert("protocol not recognized");
                });
            event.preventDefault ? event.preventDefault() : event.returnValue = false;
        });
</script>
Ali Jamal
  • 1,383
  • 1
  • 13
  • 20