On every repo, GitHub has a button that is labelled "Clone in Desktop" (example: https://github.com/github/developer.github.com). If you have GitHub for Mac installed, the href
is something like:
github-mac://openRepo/https://github.com/github/developer.github.com
This opens GitHub for Mac and offers to clone the repo. If you don't, the href
is:
http://mac.github.io`
This is a download page for GitHub for Mac. I would like to do something similar on my website: open my app if installed and redirect to download if not. How can this be best accomplished?
The GitHub for Mac client includes a local service called GitHub Conduit that runs in the background. The GitHub page communicates with this service through the the URL https://ghconduit.com:25035/status
.
For example, Conduit is behind the
Clone in Desktop
button on repository pages and theOpen
button on file pages. Conduit listens for queries from the browser about GitHub for Mac actions. To see this in action, visit https://ghconduit.com:25035/status. It should look something like this:
{"capabilities":["status","unique_id","url-parameter-filepath"],"running":true,"server_version":"5"}
If you have the GitHub Conduit service running, JavaScript on the page fetches data from this URL and give the Clone in Desktop button a github-mac://
URL. Otherwise, the URL returns a 404 response and it assumes you do not have GitHub for Mac installed, and gives you the link to download it.
Unfortunately, there is no JavaScript API to do this in the browser. Protocols the browser does not recognize are handled by the OS itself. I tried my best, but I was only able to hack-up a decent JavaScript-only solution for Firefox on Mac, and an ugly half-baked solution for Safari. Both hacks hinge on undefined behavior, and neither work for Chrome. You can see my research code below.
If you want to do it the GitHub way, you will have to create a local HTTP server that runs as a service over a known port on your user's machines. Then you can use JavaScript to connect to it and retrieve information about the installed application. Doing this would not be trivial, and unless it provides some amazing functionality, I would advise against doing this.
The JavaScript code to do this would be fairly simple though. Assuming you return the appropriate CORS headers, you could just make a simple AJAX request. Here's a jQuery-based example.
$.ajax({
url: 'http://127.0.0.1:1337',
dataType: 'json',
success: function(jqXHR) {
//Replace links to app protocol URLs.
}
});
The following code is my super-hacky and rather fragile code for Firefox and Safari. While it is working on my end, I make absolutely no guarantee that it will work as expected, or will continue to work in the future. It relies on browser-specific undefined behavior, and should be considered unstable. I also have no idea what this code will do on non-OS X systems.
This code relies on opening the link in an iframe that will trigger an error when a protocol is unrecognized (on success it will open the URL as normal).
function openAppFirefox(url, failure) {
var iframe = document.createElement('iframe');
//Firefox will fire an error if protocol fails to open.
iframe.onerror = function() {
failure();
};
//Hide the iframe.
iframe.style.width = 0;
iframe.style.height = 0;
iframe.style.visibility = "hidden";
iframe.style.position = "fixed";
//Load the URL.
iframe.src = url;
document.body.appendChild(iframe);
//Clean up the iframe.
setTimeout(function() {
document.body.removeChild(iframe);
}, 1000);
}
//Will work.
//var url = 'itmss://itunes.apple.com/us/app/stack-exchange/id871299723';
//Will fail.
var url = 'wat://bummer';
someElment.addEventListener('click', function() {
openAppFirefox(url, function() {
alert('Download my app!');
});
});
This code relies on opening the URL in a new tab, whose win.location.href
will before undefined
within a second (but probably less time) if the URL was not recognized. The "There is no application set to open the URL" dialog will still open if it fails to open the protocol unfortunately.
function openAppSafari(url, failure) {
var win = window.open(url);
var done = function(failed) {
win.close();
clearInterval(checkFail);
clearTimeout(giveup);
if (failed) {
failure();
}
};
//Chck for failure.
var checkFail = setInterval(function() {
//In Safari, location.href becomes undefined on failure.
if (!win.location.href) {
done(true);
}
});
//After a second, assume success.
var giveup = setTimeout(function() {
done(false);
}, 1000);
}
//Will work.
//var url = 'itmss://itunes.apple.com/us/app/stack-exchange/id871299723';
//Will fail.
var url = 'wat://bummer';
someElment.addEventListener('click', function() {
openAppSafari(url, function() {
alert('Download my app!');
});
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With