25

我们有一个处理自定义 URL 方案 (vstream://) 的应用程序。当有人访问包含一些 vstream:// 内容的网页时,如果他们没有安装我们的应用程序,我们需要将他们重定向到商店。

在 iOS 中,我们这样做:

setTimeout(function() {
  window.location =
    "itms://itunes.apple.com/us/app/kaon-v-stream/id378890806?mt=8&uo=4";
}, 25);

window.location = "vstream:view?code=...stuff...";

如果window.location分配失败,超时会在对话框出现之前跳过 App Store。(我在这里找到了这种技术:Is it possible to register a http+domain-based URL Scheme for iPhone apps, like YouTube and Maps?.

不幸的是,这个技巧在 Android 中不起作用。我们检测到设备服务器端并写了这个而不是 itms: 行:

"market://details?id=com.kaon.android.vstream";

问题是,当您转到未处理的 url 方案时,iOS 会引发错误,而 Android 会转到生成的页面。因此,超时永远没有机会运行。

网页上是否有某种方法可以明确测试是否处理了自定义 URL 方案,或者有人可以建议像这样在 Android 中工作的黑客吗?(当然,我想我需要一个无论他们使用什么浏览器都能正常工作的 hack,这可能是一项艰巨的任务......)

更新:以下方法在 Nexus 7 上的 Jelly Bean 中不起作用。新的 Chrome 浏览器不会转到生成的页面(因此不需要 iFrame),但似乎没有任何方法可以知道 URL 是否方案得到处理。如果是,则无论如何都会触发超时。如果未处理超时触发。如果我使用 onload 处理程序和 iframe,onload 处理程序永远不会触发(无论是否安装了应用程序)。如果我知道如何知道该计划是否得到处理,我会更新......

我已经删除了我之前的解决方案中的“已解决”,因为它不再起作用了。

更新 2:我现在有一个很好的跨平台解决方案,适用于 iOS、带有 Chrome 的 Android 4.1 和 Android pre-Chrome。见下文...

更新 3:谷歌再次故意破坏一切。看看我在某处的 amit_saxena 接受的非常好的解决方案/

4

7 回答 7

18

更新:谷歌打破了这一点。请参阅新接受的答案。

事实证明,关键是 document.webkitHidden 属性。当您将 window.location 设置为自定义 URL 方案并打开时,浏览器会继续运行,但该属性会变为 false。因此,您可以对其进行测试以确定是否处理了自定义 URL 方案。

这是一个示例,您可以实时查看

<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <title>Starting App...</title>
<script>

var URL = "kaonkaon://product.html#malvern;6";
var MARKET = "market://details?id=com.kaon.android.lepton.kaon3d";
var ITUNES = "itms://itunes.apple.com/us/app/kaon-interactive-3d-product/id525051513?mt=8&uo=4";
var QR = "http://goo.gl/gz07g"; // this should be a shortened link back to this page

function onLoad() {

    if (navigator.userAgent.match(/Android/)) {

        if (navigator.userAgent.match(/Chrome/)) {

            // Jelly Bean with Chrome browser
            setTimeout(function() {
                if (!document.webkitHidden)
                    window.location = MARKET;
            }, 1000);

            window.location = URL;

        } else {

            // Older Android browser
            var iframe = document.createElement("iframe");
            iframe.style.border = "none";
            iframe.style.width = "1px";
            iframe.style.height = "1px";
            var t = setTimeout(function() {
                window.location = MARKET;
            }, 1000);
            iframe.onload = function () { clearTimeout(t) };
            iframe.src = URL;
            document.body.appendChild(iframe);

        }

     } else if (navigator.userAgent.match(/iPhone|iPad|iPod/)) {

         // IOS
         setTimeout(function() {
             if (!document.webkitHidden)
                 window.location = ITUNES;
         }, 25);

         window.location = URL;

     } else {

         // Not mobile
         var img = document.createElement("img");
         img.src = "https://chart.googleapis.com/chart?chs=300x300&cht=qr&chl="+encodeURIComponent(QR);
         document.body.appendChild(img);
     }
}
</script>
  </head>
  <body onload="onLoad()">
  </body>
</html>
于 2012-09-24T20:21:32.177 回答
15

以下是大多数安卓浏览器的工作代码片段:

<script type="text/javascript">
    var custom = "myapp://custom_url";
    var alt = "http://mywebsite.com/alternate/content";
    var g_intent = "intent://scan/#Intent;scheme=zxing;package=com.google.zxing.client.android;end";
    var timer;
    var heartbeat;
    var iframe_timer;

    function clearTimers() {
        clearTimeout(timer);
        clearTimeout(heartbeat);
        clearTimeout(iframe_timer);
    }

    function intervalHeartbeat() {
        if (document.webkitHidden || document.hidden) {
            clearTimers();
        }
    }

    function tryIframeApproach() {
        var iframe = document.createElement("iframe");
        iframe.style.border = "none";
        iframe.style.width = "1px";
        iframe.style.height = "1px";
        iframe.onload = function () {
            document.location = alt;
        };
        iframe.src = custom;
        document.body.appendChild(iframe);
    }

    function tryWebkitApproach() {
        document.location = custom;
        timer = setTimeout(function () {
            document.location = alt;
        }, 2500);
    }

    function useIntent() {
        document.location = g_intent;
    }

    function launch_app_or_alt_url(el) {
        heartbeat = setInterval(intervalHeartbeat, 200);
        if (navigator.userAgent.match(/Chrome/)) {
            useIntent();
        } else if (navigator.userAgent.match(/Firefox/)) {
            tryWebkitApproach();
            iframe_timer = setTimeout(function () {
                tryIframeApproach();
            }, 1500);
        } else {
            tryIframeApproach();
        }
    }

    $(".source_url").click(function (event) {
        launch_app_or_alt_url($(this));
        event.preventDefault();
    });
</script>

您需要将source_url类添加到锚标记。

我在这里写了更多关于它的博客:

http://aawaara.com/post/88310470252/smallest-piece-of-code-thats-going-to-change-the

于 2014-06-09T22:10:24.997 回答
14

这就是谁来拯救你们的答案!

https://developers.google.com/chrome/mobile/docs/intents

<a href="intent://scan/#Intent;scheme=zxing;package=com.google.zxing.client.android;end"> Take a QR code </a>

如果安装了应用程序,它将您的 url schestart 我,否则它将在指定的包中启动市场

于 2013-09-25T13:09:12.723 回答
6

@jesmith,这是一个干净的版本,可以修复 Android 上的双重操作。

if (navigator.appVersion.indexOf('iPhone') > -1) {
  setTimeout(function noapp() { window.location="http://itunes.apple.com/app/id378890806?mt=8"; }, 25);
  window.location = 'vstream:';
}
else if (navigator.userAgent.indexOf('Android') > -1) {
  var iframe = document.createElement('iframe');
  iframe.style.visibility = 'hidden';
  iframe.src = 'vstream:';
  iframe.onload = function noapp() { window.location="market://details?id=com.kaon.android.vstream"; };
  document.body.appendChild(iframe);
}
于 2012-03-21T10:52:53.753 回答
4

解决了!诀窍是在 IFRAME 中打开我的应用程序,而不是设置位置:

setTimeout(function() {
  window.location =
    "market://details?id=com.kaon.android.vstream";
}, 1000);

document.write('<iframe style="border:none; width:1px; height:1px;" src="vstream:view?code='+code+'"></iframe>');

请注意,我将超时时间增加到 1000,因为 Android 实际上在每种情况下都会执行这两种操作(不理想,但并不可怕),并且需要更大的超时时间来确保 Market 最终不会成为用户看到的东西我已经安装好了。

(是的,当然使用 document.write 是上个世纪的事了,但我是那种老派 :)

于 2011-08-29T23:19:58.107 回答
2

由于某些原因,最终的解决方案在 android 上对我不起作用(仅仅是我吗?!!)。关键是 iframe.onload 函数在您的应用安装时不执行,它在您的应用未安装时执行。

解决方案实际上变得更简单一些。这是“旧版 Android 浏览器”部分的部分:

    } else {

        // Older Android browser
        var iframe = document.createElement("iframe");
        iframe.style.border = "none";
        iframe.style.width = "1px";
        iframe.style.height = "1px";
        iframe.onload = function () { window.location = MARKET; };
        iframe.src = URL;
        document.body.appendChild(iframe);

    }
于 2012-10-05T22:11:19.940 回答
1

在您的应用程序中嵌入一个 http 服务器作为服务,侦听本地端口(高于 1024,例如:8080),从浏览器向 127.0.0.1:8080 发送请求。如果您的应用已安装(并且服务正在运行),请启动它,如果请求失败,请转到 google play。

于 2015-01-06T02:08:50.357 回答