Браузер iPhone: проверка наличия приложения iPhone из браузера

У меня есть веб-страница, на которой у меня есть Button, которая либо открывает приложение (если оно установлено), либо направляет в App Store, если приложение не установлено. Все работает, если приложение установлено (я звоню в "MYAPP://" ). Однако, если приложение не установлено, Safari показывает сообщение об ошибке "Не удается открыть URL" и что он. Есть ли способ отключить это сообщение от JScript или есть другой способ узнать из JScript, если приложение установлено (вместо того, чтобы удалять URL-адрес приложения)?

К MODERATOR: Я видел, что кто-то спросил аналогичный вопрос, а Модератор ошибочно отметил его как дубликат. Пожалуйста, поймите, что речь идет конкретно о том, чтобы делать это из браузера.

Нашел несколько подходящее решение здесь

Кстати, если кто-то заинтересован в том, как сделать то же самое для Android, вот код. Мы используем библиотеку Dojo:

  dojo.io.iframe.send({
    url: "yourApp://foo/bar",
    load: function(resp) {
      // nothing to do since it will automagically open App
    },
    error: function () {
      window.location = "go to Android market";
    }
  });

Ответ 1

В Branch мы используем форму кода ниже - обратите внимание, что iframe работает с большим количеством браузеров. Просто замените в своем URI приложения и в своем приложении в App Store. Кстати, использование iframe замалчивает ошибку, если у них нет установленного приложения. Это здорово!

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

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

Если у других есть лучшие решения, чтобы определить, действительно ли вызов схемы URI не удалось, отправьте сообщение! Я его не видел, и я потратил немало времени. Все существующие решения просто полагаются на пользователя, все еще находящегося на странице, и на запуск setTimeout.

Ответ 2

Вот код, который работает на iOs, даже если "Не удается открыть URL" все еще отображается.

    window.location = "yourApp://foo/bar";      
    clickedAt = +new Date;
    setTimeout(function() {
        if (+new Date - clickedAt < 2000) {
            window.location = "go to Android market";
        }
    }, 500);

Спасибо за решение для Android.

Ответ 3

Я думаю, что вы все равно можете использовать URL-адрес приложения в качестве теста. Попробуйте обернуть его в блок try...catch,

try {
  //run code that normally breaks the script or throws error
}
catch(e) {
  //do nothing
}

Ответ 4

Я объединил несколько вещей и использовал следующий код, чтобы проверить, не является ли это iOS-устройством перед использованием метода try/catch из chazbot. К сожалению, устройство по-прежнему выбрасывает всплывающее окно для пользователя, указав, что адрес недопустим... кто-нибудь знает, если это ожидаемое поведение для попытки открыть недопустимый URL-адрес в блоке "try"?

    var i = 0,
    iOS = false,
    iDevice = ['iPad', 'iPhone', 'iPod'];

    for ( ; i < iDevice.length ; i++ ) {
        if( navigator.platform === iDevice[i] ){ iOS = true; break; }
    }

    try {
        //run code that normally breaks the script or throws error
        if (iOS) { window.location = "myApp://open";}
    }
    catch(e) {
        //do nothing
    }

Ответ 5

Есть несколько вещей, которые вы можете сделать, чтобы улучшить другие ответы. Начиная с iOS 9, ссылку можно открыть в UIWebView или в SFSafariViewController. Возможно, вы захотите обработать их по-другому.

SFSafariViewController использует файлы cookie в приложениях и со встроенным Safari. Таким образом, в вашем приложении вы можете сделать запрос через SFSafariViewController, который установит файл cookie, в котором говорится, что "мое приложение установлено". Например, вы открываете свой веб-сайт, предлагая своему серверу установить такой файл cookie. Затем в любое время, когда вы получаете запрос от SFSafariViewController, вы можете проверить этот файл cookie и перенаправить на MYAPP://, если вы его найдете, или в магазин приложений, если вы этого не сделаете. Не нужно открывать веб-страницу и выполнять перенаправление javascript, вы можете сделать 301 с вашего сервера. Приложения, такие как Messages или Safari, совместно используют эти файлы cookie.

UIWebView очень сложный, поскольку он полностью изолирован и не содержит файлов cookie ни с чем другим. Поэтому вам придется отказаться от того, что было описано в других ответах:

window.onload = function() {
  var iframe = document.createElement("iframe");
  var uri = 'MYAPP://';
  var interval = setInterval(function() {
      // Link to the App Store should go here -- only fires if deep link fails                
      window.location = "https://itunes.apple.com/us/app/my.app/id123456789?ls=1&mt=8";
  }, 500);
  iframe.onload = function() {
      clearInterval(interval);
      iframe.parentNode.removeChild(iframe);
      window.location.href = uri;
  };
  iframe.src = uri;
  iframe.setAttribute("style", "display:none;");
  document.body.appendChild(iframe);  
};

Я нашел, что это раздражает, что это заставит пользователя, если они захотят покинуть текущее приложение (перейти в ваше приложение), даже если ваше приложение не установлено. (эмпирически это кажется только верным с UIWebView, если вы делаете это из обычного Safari, например, это не произойдет), но все, что у нас получилось!

Вы можете отличить UIWebView от SFSafariViewController от вашего сервера, поскольку у них есть другой заголовок агента пользователя: SFSafariViewController содержит Safari, а UIWebView - нет. Например:

Mozilla/5.0 (iPhone; CPU iPhone OS 10_3 like Mac OS X) AppleWebKit/603.1.30 (KHTML, like Gecko) Mobile/14E269
-> UIWebView

Mozilla/5.0 (iPhone; CPU iPhone OS 10_3 like Mac OS X) AppleWebKit/603.1.30 (KHTML, like Gecko) Version/10.0 Mobile/14E269 Safari/602.1
-> SFSafariViewController

Другие соображения:

  • в первом подходе вам может понадобиться обработать uninstalls: если пользователь удаляет ваше приложение, у вас все еще есть куки файл, в котором говорится, что приложение есть, но оно отсутствует, поэтому вы можете вступить в сообщение "Can not open URL". Я обработал его, удалив куки файл после нескольких попыток, которые не закончили открывать приложение (что я знаю, потому что при каждом открытии приложения я сбрасываю этот файл с ошибками.)
  • Во втором случае неясно, лучше ли вам использовать setInterval или setTimeout. Проблема с таймаутом заключается в том, что если он запускается во время включения приглашения, он будет проигнорирован. Например, если вы откроете ссылку из Messenger, os спросит вас: "Оставьте Messenger? Вы собираетесь открыть другое приложение", когда iframe пытается загрузить ваше приложение. Если вы не ответите ни разу в течение 500 мс таймаута, перенаправление в таймаут будет проигнорировано.
  • Наконец, несмотря на то, что UIWebView изолирован песочницей, вы можете дать ему куки файл, чтобы идентифицировать его, передать его в свой deeplink и сохранить этот идентификатор как соответствующий устройству с вашим приложением на вашем сервере при открытии вашего приложения. В следующий раз, если вы увидите такой файл cookie в запросе, исходящем от UIWebView, вы можете проверить, совпадает ли он с известным устройством с приложением и перенаправить напрямую с 301.