启动应用程序(如果已安装)或重定向下载

时间:2015-02-08 01:47:28

标签: javascript macos github href url-scheme

在每个repo上,GitHub都有一个标记为“Clone in Desktop”的按钮(例如:https://github.com/github/developer.github.com)。如果您安装了GitHub for Mac,则href类似于:

github-mac://openRepo/https://github.com/github/developer.github.com

这将打开GitHub for Mac并提供克隆回购。如果不这样做,href是:

http://mac.github.io`

这是GitHub for Mac的下载页面。我想在我的网站上做类似的事情:如果已安装,请打开我的应用程序,如果没有则重定向下载。如何最好地完成这项工作?

2 个答案:

答案 0 :(得分:7)

GitHub是如何做到的?

GitHub for Mac客户端包含一个在后台运行的名为GitHub Conduit的本地服务。 GitHub页面通过URL https://ghconduit.com:25035/status与此服务进行通信。

摘自GitHub Conduit help page

  

例如,Conduit位于存储库页面上的Clone in Desktop按钮和文件页面上的Open按钮之后。 Conduit从浏览器中侦听有关GitHub for Mac操作的查询。要查看此操作,请访问https://ghconduit.com:25035/status。看起来应该是这样的:

{"capabilities":["status","unique_id","url-parameter-filepath"],"running":true,"server_version":"5"}

如果您正在运行GitHub Conduit服务,则页面上的JavaScript将从此URL获取数据,并为“在桌面克隆”按钮提供github-mac:// URL。否则,URL会返回404响应,并假定您没有安装GitHub for Mac,并为您提供下载它的链接。


如何实现这样的功能?

不幸的是,在浏览器中没有JavaScript API可以执行此操作。浏览器无法识别的协议由操作系统本身处理。我尽了最大努力,但我只能在Mac上为Firefox提供一个体面的JavaScript解决方案,并为Safari提供了一个丑陋的半生不熟的解决方案。两种黑客都依赖于未定义的行为,并且都不适用于Chrome。您可以在下面看到我的研究代码。

如果您想以GitHub方式进行,则必须创建一个本地HTTP服务器,该服务器作为服务在用户计算机上的已知端口上运行。然后,您可以使用JavaScript连接到它并检索有关已安装应用程序的信息。这样做不是微不足道的,除非它提供了一些惊人的功能,否则我建议不要这样做。

执行此操作的JavaScript代码相当简单。假设您返回相应的CORS标头,您可以只生成一个简单的AJAX请求。这是一个基于jQuery的例子。

$.ajax({
    url: 'http://127.0.0.1:1337',
    dataType: 'json',
    success: function(jqXHR) {
        //Replace links to app protocol URLs.
    }
});


研究代码:

以下代码是我的超级hacky和相当脆弱的Firefox和Safari代码。虽然它正在我的工作,我绝对不能保证它将按预期工作,或将继续在未来工作。它依赖于特定于浏览器的未定义行为,应该被视为不稳定。我也不知道这个代码在非OS X系统上会做什么。

火狐:

此代码依赖于在iframe中打开链接,当协议无法识别时将触发错误(成功时它将正常打开URL)。

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!');
    });
});

Safari浏览器:

此代码依赖于在新标签页中打开网址,如果无法识别网址,则win.location.href将在undefined之前的一秒钟内(但可能更短的时间内)。 "没有应用程序设置来打开URL"如果无法打开协议,对话框仍然会打开。

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!');
    });
});

答案 1 :(得分:0)

这可以通过Javascript或PHP实现......

对于Javascript,您有一个很酷的库is.js,可用于环境检查。见这里:http://arasatasaygin.github.io/is.js/#environment-checks

您只需在HTML中创建一个div,然后使用javascript根据功能结果填充内容,例如:is_windows()或!is_windows()

您也可以使用PHP。为此,您可以使用此问题的第一个答案中的代码:Get users OS and version number

<?php

$user_agent     =   $_SERVER['HTTP_USER_AGENT'];

function getOS() { 

global $user_agent;

$os_platform    =   "Unknown OS Platform";

$os_array       =   array(
                        '/windows nt 6.2/i'     =>  'Windows 8',
                        '/windows nt 6.1/i'     =>  'Windows 7',
                        '/windows nt 6.0/i'     =>  'Windows Vista',
                        '/windows nt 5.2/i'     =>  'Windows Server 2003/XP x64',
                        '/windows nt 5.1/i'     =>  'Windows XP',
                        '/windows xp/i'         =>  'Windows XP',
                        '/windows nt 5.0/i'     =>  'Windows 2000',
                        '/windows me/i'         =>  'Windows ME',
                        '/win98/i'              =>  'Windows 98',
                        '/win95/i'              =>  'Windows 95',
                        '/win16/i'              =>  'Windows 3.11',
                        '/macintosh|mac os x/i' =>  'Mac OS X',
                        '/mac_powerpc/i'        =>  'Mac OS 9',
                        '/linux/i'              =>  'Linux',
                        '/ubuntu/i'             =>  'Ubuntu',
                        '/iphone/i'             =>  'iPhone',
                        '/ipod/i'               =>  'iPod',
                        '/ipad/i'               =>  'iPad',
                        '/android/i'            =>  'Android',
                        '/blackberry/i'         =>  'BlackBerry',
                        '/webos/i'              =>  'Mobile'
                    );

    foreach ($os_array as $regex => $value) { 

    if (preg_match($regex, $user_agent)) {
        $os_platform    =   $value;
    }

}   

return $os_platform;

}

function getBrowser() {

global $user_agent;

$browser        =   "Unknown Browser";

$browser_array  =   array(
                        '/msie/i'       =>  'Internet Explorer',
                        '/firefox/i'    =>  'Firefox',
                        '/safari/i'     =>  'Safari',
                        '/chrome/i'     =>  'Chrome',
                        '/opera/i'      =>  'Opera',
                        '/netscape/i'   =>  'Netscape',
                        '/maxthon/i'    =>  'Maxthon',
                        '/konqueror/i'  =>  'Konqueror',
                        '/mobile/i'     =>  'Handheld Browser'
                    );

foreach ($browser_array as $regex => $value) { 

    if (preg_match($regex, $user_agent)) {
        $browser    =   $value;
    }

}

return $browser;

}


$user_os        =   getOS();
$user_browser   =   getBrowser();

$device_details =   "<strong>Browser: </strong>".$user_browser."<br /><strong>Operating System: </strong>".$user_os."";

print_r($device_details);

echo("<br /><br /><br />".$_SERVER['HTTP_USER_AGENT']."");

?>

现在基于getOS()和/或getBrowser函数的返回,您可以向用户呈现不同的内容......这是一个简单的if else块代码:)

享受!