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

Launch app if installed or redirect to download

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

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

这会为 Mac 打开 GitHub 并提供克隆存储库。如果不这样做,href 是:

http://mac.github.io`

这是 GitHub Mac 的下载页面。我想在我的网站上做类似的事情:如果已安装则打开我的应用程序,如果没有则重定向以下载。如何才能最好地实现这一点?

这可以通过 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() return and/or getBrowser 函数,您可以向用户呈现不同的内容...这是一个简单的 if else 块代码:)

尽情享受吧!

GitHub是怎么做到的?

后台运行的GitHub for Mac client includes a local service called GitHub Conduit。 GitHub 页面通过 URL https://ghconduit.com:25035/status.

与此服务通信

摘自GitHub Conduit help page

For example, Conduit is behind the Clone in Desktop button on repository pages and the Open 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"}

如果您有 GitHub 管道服务 运行,页面上的 JavaScript 会从此 URL 获取数据并为“在桌面中克隆”按钮提供 github-mac:// URL。否则,URL return 是一个 404 响应,它假定您没有安装 Mac 的 GitHub,并为您提供 link 下载它。


如何实现这样的功能?

不幸的是,浏览器中没有 JavaScript API 可以执行此操作。浏览器无法识别的协议由 OS 本身处理。我尽了最大努力,但我只能 hack-up 在 Mac 上为 Firefox 提供一个不错的 JavaScript-only 解决方案,为 Safari 提供一个丑陋的 half-baked 解决方案。这两个 hack 都依赖于未定义的行为,并且都不适用于 Chrome。你可以在下面看到我的研究代码。

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

执行此操作的 JavaScript 代码相当简单。假设您 return 合适的 CORS headers,您可以只发出一个简单的 AJAX 请求。这是一个 jQuery-based 示例。

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


研究代码:

以下代码是我的 super-hacky 并且是相当脆弱的 Firefox 和 Safari 代码。虽然它正在为我工​​作,但我绝对不保证它会按预期工作,或者将来会继续工作。它依赖于 browser-specific 未定义的行为,应该被认为是不稳定的。我也不知道这段代码在 non-OS X 系统上会做什么。

火狐:

此代码依赖于在 iframe 中打开 link,当无法识别协议时会触发错误(成功后它将正常打开 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!');
    });
});

野生动物园:

这段代码依赖于在新选项卡中打开 URL,如果 URL没有被认出。如果不幸无法打开协议,"There is no application set to open the 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!');
    });
});