27

I have protocol (like http) with scheme managed with 3rd party App registered in Mac OS X. I.e, x-someapp://someaction or something like that.

How can I open this URL with Google Chrome? By default, Chrome starts searching in Google engine instead launching App and passing URL handling to it...

Safari launches some registered App. And it is right thing.

Firefox and Opera asks what to do... and I can launch App also.

But Chrome... Doesn't ask.

I even tried to write some HTML page with JavaScript inside to send XHttpRequest:

function _httpExecuteCallback()
{
 if (httpRequestCallbackFunction != null) {
  if (httpRequest.readyState == 4) {
   if (httpRequest.status == 200) {
    httpRequestCallbackFunction();
    httpRequestCallbackFunction = null;
   }   
  }
 }
}

function _httpGet(url, callbackFunction)
{
 httpRequest = false;
 httpRequestCallbackFunction = callbackFunction;
 httpRequest = new XMLHttpRequest();
 httpRequest.onreadystatechange = _httpExecuteCallback;
 httpRequest.open('GET', url, true);
 httpRequest.send(null);
}


_httpGet('x-someapp://test',function(){})

No results also...

UncleMiF
  • 1,051
  • 2
  • 11
  • 20

6 Answers6

30

The current accepted solution has a problem with Chrome for SSL https. Watching the console log, Chrome blocks the request because it thinks the custom url protocol is not secure:

[blocked] The page at reports blah blah ran insecure content from customproto//blah blah

Here is a solution (this took me a few days to research):

    <input type='button' value='Test Custom Url' onclick='exec()'>

    <script>
    function submitRequest(buttonId) {
        var d = (window.parent)?window.parent.document:window.document
        if (d.getElementById(buttonId) == null || d.getElementById(buttonId) == undefined) return;
        if (d.getElementById(buttonId).dispatchEvent) {
                var e = d.createEvent("MouseEvents");
                e.initEvent("click", true, true);
                d.getElementById(buttonId).dispatchEvent(e);
        } 
        else {
                d.getElementById(buttonId).click();
        }
    }

    function exec(){
        var d = (window.parent)?window.parent.document:window.document
        var f = d.getElementById('customUrlLink')
        if (f ) {f.parentNode.removeChild(f);}
        var a = d.createElement('a');
        a.href =  'mycustomproto://arg1';    
        a.innerHTML = "Link"                                    
        a.setAttribute('id',        'customUrlLink');
        a.setAttribute("style", "display:none; "); 
        d.body.appendChild(a); 
        submitRequest("customUrlLink");
    }
    </script>

This code will not work for IE. I've found using this technique IE limits the argument of the custom protocol to less than 1000 where as using the iFrame technique IE will allow 2083 chars.

The only way to overcome the url limit in javascript is chuck the data and call multiple times. If anyone wants to take a stab at that, please let me know how it goes. I would like to use it.

To handle long urls in the executing app, pass a token into the app and have it go get the data from a url GET.

So for right now I am using one function for Chrome/FF and another function for IE.

These links helped me develop this solution:

https://superuser.com/questions/655405/custom-protocol-handler-not-working-in-chrome-on-ssl-page

Simulating a click in jQuery/JavaScript on a link

(wish I had known this a few days ago....hope this helps someone)

==================================================

Update: (8hr later)

==================================================

Jake posted a great solution for chrome: https://superuser.com/questions/655405/custom-protocol-handler-not-working-in-chrome-on-ssl-page

This works in chrome only:

 window.location.assign("customprotocol://");

It will fail in an iframe so this is working:

var w = (window.parent)?window.parent:window
w.location.assign(service + '://' +  data)

==================================================

Update: (weeks later)

==================================================

All of the examples of opening the custom protocol, including my own, have a "://" in the url. And this is what is causing the SSL warnings.

Turns out the solution is to change "://" to ":"

so do this:

src="x-myproto:query"  .....

and the SSL warnings will go away.

==================================================

Follow: (after months of production use)

==================================================

This has been working well for chorme. Detect the browser and if chrome do this:

var w = (window.parent)?window.parent:window
w.location.assign('myproto://xyzabcdefetc')

For IE and other browsers I do something slightly different.

Note that browsers do impose a limit on how much data you can put in custom url protocol. As long as your string is under 800 chars this seems to be the magic number for which works in all browsers.

Community
  • 1
  • 1
Brian McGinity
  • 5,777
  • 5
  • 36
  • 46
  • 1
    Brian, thanks for the post, but I fail to see how this solves the issue in Chrome. Our application uses an iframe for other browsers to avoid navigation away from the application while still launching the URL handler (SSH in our case). This used to work on Chrome but is now broken. When I employ your solution (without an iframe) it causes a navigation away from our application when the URL handler is launched. So I'm not sure how the answer above is a "solution" to the problem. Am I missing something? – brettw Jul 02 '14 at 02:52
  • @brettw, I've added an update to the answer. Really it's saying pretty much the same stuff. What I've posted is working in chrome for me. This has been in production for sometime now. If this solution is navigating away, try using an href to call a js function such as test and then put the code in the solution in the test() function. – Brian McGinity Jul 02 '14 at 21:49
  • @BrianMcGinity - in chrome doing window.location.assign is changing the tab content to go back to the previous page (which is the no longer valid authorization/login page). Is there anyway to make it stay on that page? – Noitidart Jun 18 '17 at 01:07
  • I was able to keep on the page with a beforeunload prompt on 2nd unload (because first unload goes to custom protocol to launch) with this code - https://gist.github.com/Noitidart/e898a84a4f72e1b4c11ff7ca11a46bf7 - however when the 2nd unload happens and it shows the prompt, it brings focus back to the browser :( – Noitidart Jun 18 '17 at 01:18
  • For iOS, `window.location.assign` is the ONLY solution that seems to work anymore in 2021, thank you. – Albert Renshaw Jul 24 '21 at 01:12
9

It looks like it's Google's locationbar parsing which is getting in the way.

The browser, however, does seem to handle custom URL schemes properly. Try this in your locationbar:

javascript:document.location = 'myscheme://whatever'

Any link on your page that uses the custom scheme should also do the right thing.

Mark Judd
  • 149
  • 1
  • 5
4

I found the solution that works with Chrome. I use the IFRAME-way.

Example (with JQuery):

$("body").append('<span id="__protoProxy"></span>');

function queryWord(aWord)
{
 var protoProxy = document.getElementById('__protoProxy');
 if (protoProxy)
 {   
  var word = aWord.replace('"','\"');
  protoProxy.innerHTML = '<div style="display:none;"><iframe src="x-myproto://query?' + word + '"></iframe></div>';
 }
}

queryWord('hello');
UncleMiF
  • 1,051
  • 2
  • 11
  • 20
  • 1
    Oh, so instead of typing `x-myproto://query?furries` into the location bar, you open an iframe with it, and then Chrome uses the existing registered application to fetch the thing to display inside the iframe? – Kragen Javier Sitaker Nov 09 '11 at 23:54
  • This is necessary for our Chrome plugin, nobody enter address directly to user's location bar, so hidden iframe is the best solution indeed. – UncleMiF Dec 13 '11 at 21:18
4

Here's a solution that also includes a redirect to the App Store / Play Store if the user doesn't have the app. It uses a setTimeout for this. It also makes use of an iframe to support more browsers. So this works on Chrome, and any other mobile browser. We use this as my company, Branch. Just modify the two links below to correspond to your URI and App Store link.

<!DOCTYPE html>
<html>
    <body>
        <script type="text/javascript">
            window.onload = function() {
                // Deep link to your app goes here
                document.getElementById("l").src = "my_app://somepath";

                setTimeout(function() {
                    // Link to the App Store should go here -- only fires if deep link fails                
                    window.location = "https://itunes.apple.com/us/app/myapp/id123456789?ls=1&mt=8";
                }, 500);
            };
        </script>
        <iframe id="l" width="1" height="1" style="visibility:hidden"></iframe>
    </body>
</html>

Again, this should work on any browser, thanks to the iframe.

st.derrick
  • 4,769
  • 2
  • 24
  • 25
3

If Chrome does not recognize the URL scheme, it defaults to a search.

This is what I see in Safari: alt text http://img62.imageshack.us/img62/6792/clipboard02oh.jpg

and in Firefox:

alt text http://img138.imageshack.us/img138/9986/clipboard04xk.jpg

I believe the reason why Chrome defaults to search is that there are special google searches that use the colon.

E.g:

  • define: dictionary
  • filetype:pdf google chromium

This is one of the annoyances I have with Firefox, I have to jump to the "search box" rather than the address bar to execute these types of searches. Since Chrome does not have a separate search box like Firefox, IE and Safari have, this functionality is required.

Ajax requests won't get you around this.

Community
  • 1
  • 1
Pierre-Antoine LaFayette
  • 24,222
  • 8
  • 54
  • 58
  • I dunno how it works on Windows, I tagged this question as Mac OS X. So, in the Mac OS X World, any App can register its own internet scheme right inside Info.plist file (which contains in the App Bundle). So, Safari will always know about 3rd party protocols, as only new App was installed, even Firefox and Opera will know, but Chrome seems doesn't read this information from the System. For example, if I have SpamSieve installed, I can open x-spamsieve protocol right from the Safari and register the software... Safari may just redirect this URL-scheme query to the NSWorkspace... – UncleMiF Feb 25 '10 at 16:26
  • Additionally, I successfully used AJAX from Firefox (see the code example inside my question) on Mac OS X to request 3rd party protocols (not http/ftp). – UncleMiF Feb 25 '10 at 16:28
  • 1
    Here is additional examples http://mac.gettranslateit.com/integrationFireFox.shtml and http://mac.gettranslateit.com/integrationOpera.shtml I just wanna write Chrome extension, and generally I did it except sandbox restrictions - now I need to call 3rd party protocol (my own), but I can't. – UncleMiF Feb 25 '10 at 16:31
  • Chrome should recognize the protocol if it is registered with the OS. I believe this may be a Mac specific bug. Please file this as a Mac OS X bug at http://crbug.com. Thanks. – Pierre-Antoine LaFayette Feb 25 '10 at 18:30
  • we don't have a subscription to image shack.. – CrazyVideoGamer May 01 '22 at 21:15
  • @UncleMiF Also, those links don't work. – CrazyVideoGamer May 01 '22 at 21:16
0

Some weeks later ....

Looks like window.location.replace('myscheme://whatever') has full cross-browser support , works with chrome,firefox,safari,edge,opera see https://developer.mozilla.org/en-US/docs/Web/API/Location/replace

Jimmy Obonyo Abor
  • 7,335
  • 10
  • 43
  • 71