65

Is there any way to check if a URL scheme is currently registered on the phone... with javascript?

Cezar
  • 55,636
  • 19
  • 86
  • 87
  • 3
    I found the solution posted here to work much better: http://stackoverflow.com/questions/6964515/launching-app-or-app-store-from-safari – benathon Jul 12 '12 at 07:05

10 Answers10

64

Not seamlessly. But there is a way similar to checking if a pop-up was blocked or not.

When you try a URL scheme which is not supported, Safari will warn the user that it doesn't know what to do with it and stay on the same page.

So if you gave your app-call some time to activate, say 300 ms, and then do something else to respond to the non-existence of the scheme.

It's not the prettiest but it works:

function startIThrown(){
  document.location = 'ithrown://restart';
  setTimeout(function(){
    if(confirm('You do not seem to have iThrown installed, do you want to go download it now?')){
      document.location = 'http://itunes.apple.com/WebObjects/MZStore.woa/wa/viewSoftware?id=293049283&mt=8&uo=6';
    }
  }, 300);
}

<a href="#" onclick="startIThrown()">Restart iThrown</a>
Maarten
  • 649
  • 5
  • 3
  • 2
    It was worth a try, but indeed this is kinda a nasty solution. That function gets called even if the URL scheme goes through when you come back to the page. So the user gets an alert popup no matter what. Either 1 or 2, depending on whether his device support the scheme. – samvermette Feb 21 '11 at 13:44
  • 9
    @samvermette There is a semi-complicated workaround. If the url scheme works, then have your app send a confirmation to your server. Then when you come back to the app, have it ping the server to see if the app was opened successfully. Complicated, but feasible. – Amir Jun 01 '11 at 21:54
  • 7
    Is there any way to not show that horribly unfriendly error if the app is not installed? – devios1 Jul 14 '13 at 01:02
  • iOS 13.3 solution which plays nice with the "horribly unfriendly error": https://gist.github.com/diachedelic/0d60233dab3dcae3215da8a4dfdcd434 – diachedelic Feb 20 '20 at 05:44
  • is it working on iOS 15 and above? – RohitK Dec 28 '22 at 09:25
39

Here is a solution that does not show the popup when you come back from the app, it assumes you've been gone longer than 400 ms:

function startiThrown() {
    document.location = appurl;
    var time = (new Date()).getTime();
    setTimeout(function(){
        var now = (new Date()).getTime();

        if((now - time)<400) {
            if(confirm('You do not seem to have iThrown installed, do you want to go download it now?')){
            document.location = 'http://itunes.apple.com/WebObjects/MZStore.woa/wa/viewSoftware?id=293049283&mt=8&uo=6';
            }
         }
    }, 300);
}
Ismael Abreu
  • 16,443
  • 6
  • 61
  • 75
mrahman
  • 391
  • 3
  • 2
  • We've run into a problem where the "now" variable in this solution is flat out wrong. We can wait minutes in the app, go back to the browser, and get the confirmation. It seems the hibernation wakeup process is buggy. – JoshNaro Apr 29 '14 at 21:17
14

I found pagehide event to be more robust than depending on system time. For those of us who prefers a non-jQuery favor, here is the snippet.

  var appurl = 'custom://url';
  var appstore = 'https://itunes.apple.com/us/app/your-app';

  var timeout;
  function preventPopup() {
    clearTimeout(timeout);
    timeout = null;
    window.removeEventListener('pagehide', preventPopup);
  }
  function startApp() {
    window.location = appurl;
    timeout = setTimeout(function(){
      if(confirm('You do not seem to have the App installed, do you want to go download it now?')){
        document.location = appstore;
      }
    }, 1000);
    window.addEventListener('pagehide', preventPopup);
  }
Timo Tijhof
  • 10,032
  • 6
  • 34
  • 48
Thomas - BeeDesk
  • 1,008
  • 1
  • 11
  • 12
  • That code does not work. When the schema exists and it is associated with an executable, browser asks if one wants to run that app. That delay causes the timeout to arrive and obviously, the `confirm` function to be executed. – jstuardo Oct 26 '20 at 22:29
9

Another great (at least working in latest browser versions) workaround is to check if the browser window has focus after a short timeout, this way you can show a dialog box to the user only if the URI scheme didn't work

HTML:

<a class="uri-link" data-uri="qobuzapp://" href="#">URI</a>​

Javascript (using jQuery here):

var windowHasFocus;

$(window).focus(function() {
  windowHasFocus = true;
}).blur(function() {
  windowHasFocus = false;
});

function goToUri(uri) {
  window.location = uri;
  setTimeout(function(){
    if (windowHasFocus) {
      if (confirm('You do not seem to have Qobuz installed, do you want to go download it now?')){
        window.location = 'http://www.qobuz.com';
      }
    }
  }, 100);
}

$('a').on('click', function(){ 
  goToUri($(this).data('uri')); 
});​
izilotti
  • 4,757
  • 1
  • 48
  • 55
Loris Guignard
  • 131
  • 2
  • 5
  • That code does not work. When the schema exists and it is associated with an executable, browser asks if one wants to run that app. That delay causes the timeout to arrive and obviously, the `confirm` function to be executed. – jstuardo Oct 26 '20 at 22:28
8

Starting from iOS 6.0 Apple presented the Smart App Banners which do what most of us are looking for:

  • Send to App Store if the app isn't installed.
  • Open the App with a specific deep link, using the app-argument param.

Include the following meta tag:

<meta name="apple-itunes-app" content="app-id=myAppStoreID, affiliate-data=myAffiliateData, app-argument=myURL">

taken from here: Safari Web Content Guide

eladleb
  • 2,616
  • 26
  • 21
3

No, not from a webpage.

Andrew Grant
  • 58,260
  • 22
  • 130
  • 143
  • I thought I recalled a way that apps could check this but I'm probably wrong. – Andrew Grant Mar 09 '09 at 21:32
  • 2
    Thanks for the quick answer. As far as from native code, it is possible via openUrl: to check, so I've read... not tested –  Mar 10 '09 at 17:34
  • 12
    @Brent Royal-Gordon: Nope. A native iPhone app can check by calling **canOpenURL:**. – Di Wu Mar 17 '11 at 05:52
  • 4
    There's a way from a web page: http://stackoverflow.com/questions/1108693/is-it-possible-to-register-a-httpdomain-based-url-scheme-for-iphone-apps-like-y/1109200#1109200 – amok May 23 '11 at 21:06
  • this could help... http://stackoverflow.com/questions/6964515/launching-app-or-app-store-from-safari – Underdog May 31 '12 at 05:23
  • 1
    This is one of those "factually correct, but not actually that useful" answers. [This answer](https://stackoverflow.com/questions/627916/check-if-url-scheme-is-supported-in-javascript/1404662#1404662) addresses the question the OP probably ought to have asked in the first place! – funkybro Mar 09 '15 at 14:47
2

Here is a variation on the previous 2 solutions. It will create a link that can be opened in Google Chrome. If it fails it opens the link using http

<script>
 function checkChrome(h){
  document.location=h;
  var time = (new Date()).getTime();
  setTimeout(function(){
   var now = (new Date()).getTime();
   if((now-time)<400) {
    if(confirm('Missing Chrome. Download it now?')){
     document.location = 'http://itunes.apple.com/us/app/chrome/id535886823?mt=8';
    } else {
     document.location=h.replace('googlechrome','http');
    }
   }
  }, 300);
 }
</script>

<a href="googlechrome://www.google.com" onclick="checkChrome(this.href);return false;">Open Google with Chrome</a>
Terry Riegel
  • 159
  • 10
1

This is based on the answer of mrahman. As noted, by JoshNaro new Date() gives back a wrong date when called inside the timeout. Tests suggest that the date is not updated in threads that are started before the app is deactivated.

A further ugly setTimeout called after activation will create a new thread with the current date.

This was tested on iOS 8.

function startiThrown() {
    document.location = appurl;
    var time = (new Date()).getTime();
    setTimeout(function(){
        setTimeout(function(){ // <-- start new thread after activation
            var now = (new Date()).getTime();
            if((now - time)<400) {
                if(confirm('You do not seem to have iThrown installed, do you want to go download it now?')){
                    document.location = 'http://itunes.apple.com/WebObjects/MZStore.woa/wa/viewSoftware?id=293049283&mt=8&uo=6';
                }
            }
        }, 10); // <-- start new thread after activation
    }, 300);
}
TheEye
  • 9,280
  • 2
  • 42
  • 58
k3erg
  • 46
  • 2
0

I have this comment https://stackoverflow.com/a/18715513/49114 with a jQuery plugin to add alternative app link to regular links.

Community
  • 1
  • 1
Lito
  • 1,262
  • 2
  • 17
  • 25
0

I try to use just the 'pagehide' event, but then it not work into Firefox. I created this version here http://jsfiddle.net/thiagomata/6tvoc4f1/2/ what works in Firefox, Google Chrome and Safari. I have not tested in Internet Explorer yet.

One thing what was necessary to make it work into Firefox, was use Iframe to set the src. This allows me to call the app without leaving my page.

<a class="uri-link" href="#" 
  data-uri-app="myapp://" 
  data-url-app-not-found="http://www.google.com?q=not-found-link"
  >
  Example 1
</a>​
<a class="uri-link" href="#" 
  data-uri-app="myapp://" 
  data-url-app-not-found="http://www.google.com?q=not-found-link"
  data-url-app-found="http://www.google.com?q=found-link"
  >
  Example 2
</a>​
<a class="uri-link"  href="#"
  data-uri-app="notexists://" 
  data-url-app-not-found="http://www.google.com?q=not-exists"
>
  Example 3
</a>​
<iframe id="callapp" style="display:none"></iframe>
Thiago Mata
  • 2,825
  • 33
  • 32
  • nice concept. although the app-found doesn't happen ever. Even when the app is installed (i tried instagram://app) it triggers the notfound one. – Tom Roggero Apr 13 '15 at 19:16
  • Do you tried to make the timeout bigger? Change the value in line 95 from 1000 to 9000 ( just for fun ) and tell me what happens. – Thiago Mata Apr 15 '15 at 21:43