web-dev-qa-db-fra.com

Comment vérifier si une application est installée à partir d'une page Web sur un iPhone?

Je souhaite créer une page Web, une page qui redirigera un iPhone vers l'App-Store si l'application n'est pas installée sur l'iPhone, mais si l'application est installée sur l'iPhone, je souhaite qu'elle ouvre l'application.

J'ai déjà implémenté une URL personnalisée dans l'application iPhone. J'ai donc une URL pour l'application qui ressemble à quelque chose comme:

myapp://

Et si cette URL n'est pas valide, je souhaite que la page soit redirigée vers l'App Store. Est-ce possible?

Si l'application n'est pas installée sur le téléphone et que j'écris l'url myapp: // dans safari, tout ce que je reçois est un message d'erreur.

Même s'il existe un hack laid avec javascript, j'aimerais vraiment savoir?

131
Joakim Engstrom

Autant que je sache, vous ne pouvez pas, depuis un navigateur, vérifier si une application est installée ou non.

Mais vous pouvez essayer de rediriger le téléphone vers l'application, et si rien ne se passe, redirigez le téléphone vers une page spécifiée, comme ceci:

setTimeout(function () { window.location = "https://iTunes.Apple.com/appdir"; }, 25);
window.location = "appname://";

Si la deuxième ligne de code donne un résultat, la première ligne n'est jamais exécutée.

J'espère que cela t'aides!

Question similaire:

180
missemisa

Pour approfondir la réponse acceptée, vous devez parfois ajouter du code supplémentaire pour gérer les personnes qui retournent le navigateur après le lancement de l'application: la fonction setTimeout s'exécutera à chaque fois. Alors, je fais quelque chose comme ça:

var now = new Date().valueOf();
setTimeout(function () {
    if (new Date().valueOf() - now > 100) return;
    window.location = "https://iTunes.Apple.com/appdir";
}, 25);
window.location = "appname://";

De cette façon, s’il ya eu un gel de l’exécution du code (c’est-à-dire du changement d’application), il ne fonctionnera pas.

148
Alastair

iOS Safari dispose d'une fonctionnalité qui vous permet d'ajouter une bannière "intelligente" à votre page Web, qui sera liée à votre application, si elle est installée, ou à l'App Store.

Pour ce faire, vous ajoutez une balise meta à la page. Vous pouvez même spécifier une URL d'application détaillée si vous souhaitez que l'application fasse quelque chose de spécial lors du chargement.

Les détails se trouvent sur la page Promotion des applications avec les bannières Smart App .

Le mécanisme présente l'avantage d'être simple et de présenter une bannière standardisée. L'inconvénient est que vous n'avez pas beaucoup de contrôle sur l'apparence ou l'emplacement. En outre, tous les paris sont désactivés si la page est affichée dans un navigateur autre que Safari.

27
brainjam

@Alistair a souligné dans cette réponse que parfois les utilisateurs reviennent au navigateur après avoir ouvert l'application. Un commentateur à cette réponse a indiqué que les valeurs de temps utilisées devaient être modifiées en fonction de la version iOS. Lorsque notre équipe a dû gérer cela, nous avons constaté que les valeurs de temps du délai initial et de l'indication de notre retour au navigateur devaient être ajustées et ne fonctionnaient souvent pas pour tous les utilisateurs et appareils.

Plutôt que d'utiliser un seuil de décalage horaire arbitraire pour déterminer si nous sommes revenus au navigateur, il était logique de détecter les événements "pagehide" et "pageshow".

J'ai développé la page Web suivante pour aider à diagnostiquer ce qui se passait. Il ajoute des diagnostics HTML au fur et à mesure que les événements se déroulent, principalement parce que l'utilisation de techniques telles que la journalisation sur console, les alertes, Web Inspector, jsfiddle.net, etc. avait tous des inconvénients dans ce flux de travail. Plutôt que d'utiliser un seuil temporel, le code Javascript compte le nombre d'événements "pagehide" et "pageshow" pour voir s'ils se sont produits. Et j’ai trouvé que la stratégie la plus robuste consistait à utiliser un délai d’attente initial de 1 000 (au lieu des 25, 50 ou 100 signalés/suggérés par d’autres).

Cela peut être servi sur un serveur local, par exemple. python -m SimpleHTTPServer et visualisé sur iOS Safari.

Pour jouer avec, appuyez sur le lien "Ouvrir une application installée" ou "Application non installée". Ces liens doivent entraîner l’ouverture de l’application Cartes ou de l’App Store. Vous pouvez ensuite revenir à Safari pour voir la séquence et la chronologie des événements.

(Remarque: cela ne fonctionne que pour Safari. Pour les autres navigateurs (comme Chrome), vous devez installer des gestionnaires pour les événements pagehide/show-equivalent).

Mise à jour: Comme l'a souligné @Mikko dans les commentaires, les événements pageshow/pagehide que nous utilisons ne sont apparemment plus pris en charge par iOS8.

<html>
<head>
</head>
<body>
<a href="maps://" onclick="clickHandler()">Open an installed app</a>
<br/><br/>
<a href="xmapsx://" onclick="clickHandler()">App not installed</a>
<br/>

<script>

var hideShowCount = 0 ;
window.addEventListener("pagehide", function() {
    hideShowCount++ ;
    showEventTime('pagehide') ;
});

window.addEventListener("pageshow", function() {
    hideShowCount++ ;
    showEventTime('pageshow') ;
});

function clickHandler(){
    var hideShowCountAtClick = hideShowCount ;
    showEventTime('click') ;
    setTimeout(function () {
               showEventTime('timeout function '+(hideShowCount-hideShowCountAtClick)+' hide/show events') ;
               if (hideShowCount == hideShowCountAtClick){
                    // app is not installed, go to App Store
                    window.location = 'http://iTunes.Apple.com/app' ;
               }
            }, 1000);
}

function currentTime()
{
    return Date.now()/1000 ;
}

function showEventTime(event){
    var time = currentTime() ;
    document.body.appendChild(document.createElement('br'));
    document.body.appendChild(document.createTextNode(time+' '+event));
}
</script>
</body>
</html>
9
brainjam

À compter de 2017, il semble qu'il n'y ait aucun moyen fiable de détecter une application installée, et l'astuce de redirection ne fonctionnera pas partout.

Pour ceux comme moi qui ont besoin de créer des liens profonds directement à partir de courriels (assez courants), il convient de noter les points suivants:

  • L'envoi d'e-mails avec appScheme: // ne fonctionnera pas correctement car les liens seront filtrés dans Gmail.

  • La redirection automatique vers appScheme: // est bloquée par Chrome: je soupçonne que Chrome nécessite que la redirection soit synchrone par rapport à une interaction utilisateur (comme un clic).

  • Vous pouvez maintenant créer des liens profonds sans appScheme: // et c'est mieux, mais cela nécessite une plate-forme moderne et une configuration supplémentaire. AndroidiOS


Il est à noter que d'autres personnes ont déjà réfléchi à cette question en profondeur. Si vous regardez comment Slack implémente sa fonctionnalité "lien magique", vous remarquerez que:

  • Il envoie un email avec un lien http habituel (ok avec Gmail)
  • La page Web comporte un gros bouton qui renvoie à appScheme: // (ok avec Chrome).
9
Sebastien Lorber

Vous pouvez consulter ce plugin qui tente de résoudre le problème. Il est basé sur la même approche que celle décrite par missemisa et Alastair, etc., mais utilise plutôt un iframe caché.

https://github.com/hampusohlsson/browser-deeplink

9
hampusohlsson

Je dois faire quelque chose comme ça, je me suis retrouvé avec la solution suivante.

J'ai une URL de site Web spécifique qui ouvrira une page avec deux boutons

1) Button One aller sur le site web

2) Bouton Deux aller à l'application (iPhone/Android téléphone/tablette), vous pouvez revenir à un emplacement par défaut à partir d'ici si l'application n'est pas installée (comme une autre URL ou un magasin d'applications).

3) cookie pour rappeler le choix des utilisateurs

<head>
<title>Mobile Router Example </title>


<script type="text/javascript">
    function set_cookie(name,value)
    {
       // js code to write cookie
    }
    function read_cookie(name) {
       // jsCode to read cookie
    }

    function goToApp(appLocation) {
        setTimeout(function() {
            window.location = appLocation;
              //this is a fallback if the app is not installed. Could direct to an app store or a website telling user how to get app


        }, 25);
        window.location = "custom-uri://AppShouldListenForThis";
    }

    function goToWeb(webLocation) {
        window.location = webLocation;
    }

    if (readCookie('appLinkIgnoreWeb') == 'true' ) {
        goToWeb('http://somewebsite');

    }
    else if (readCookie('appLinkIgnoreApp') == 'true') {
        goToApp('http://fallbackLocation');
    }



</script>
</head>
<body>


<div class="iphone_table_padding">
<table border="0" cellspacing="0" cellpadding="0" style="width:100%;">
    <tr>
        <td class="iphone_table_leftRight">&nbsp;</td>
        <td>
            <!-- INTRO -->
            <span class="iphone_copy_intro">Check out our new app or go to website</span>
        </td>
        <td class="iphone_table_leftRight">&nbsp;</td>
    </tr>
    <tr>
        <td class="iphone_table_leftRight">&nbsp;</td>
        <td>
            <div class="iphone_btn_padding">

                <!-- GET IPHONE APP BTN -->
                <table border="0" cellspacing="0" cellpadding="0" class="iphone_btn" onclick="set_cookie('appLinkIgnoreApp',document.getElementById('chkDontShow').checked);goToApp('http://getappfallback')">
                    <tr>
                        <td class="iphone_btn_on_left">&nbsp;</td>
                        <td class="iphone_btn_on_mid">
                            <span class="iphone_copy_btn">
                                Get The Mobile Applications
                            </span>
                        </td>
                        <td class="iphone_btn_on_right">&nbsp;</td>
                    </tr>
                </table>

            </div>
        </td>
        <td class="iphone_table_leftRight">&nbsp;</td>
    </tr>
    <tr>
        <td class="iphone_table_leftRight">&nbsp;</td>
        <td>
            <div class="iphone_btn_padding">

                <table border="0" cellspacing="0" cellpadding="0" class="iphone_btn"  onclick="set_cookie('appLinkIgnoreWeb',document.getElementById('chkDontShow').checked);goToWeb('http://www.website.com')">
                    <tr>
                        <td class="iphone_btn_left">&nbsp;</td>
                        <td class="iphone_btn_mid">
                            <span class="iphone_copy_btn">
                                Visit Website.com
                            </span>
                        </td>
                        <td class="iphone_btn_right">&nbsp;</td>
                    </tr>
                </table>

            </div>
        </td>
        <td class="iphone_table_leftRight">&nbsp;</td>
    </tr>
    <tr>
        <td class="iphone_table_leftRight">&nbsp;</td>
        <td>
            <div class="iphone_chk_padding">

                <!-- CHECK BOX -->
                <table border="0" cellspacing="0" cellpadding="0">
                    <tr>
                        <td><input type="checkbox" id="chkDontShow" /></td>
                        <td>
                            <span class="iphone_copy_chk">
                                <label for="chkDontShow">&nbsp;Don&rsquo;t show this screen again.</label>
                            </span>
                        </td>
                    </tr>
                </table>

            </div>
        </td>
        <td class="iphone_table_leftRight">&nbsp;</td>
    </tr>
</table>

</div>

</body>
</html>
2
nate_weldon

Après avoir compilé quelques réponses, je viens avec le code suivant. Ce qui m'a surpris, c'est que le minuteur ne soit pas bloqué sur un PC (Chrome, FF) ou Android Chrome - le déclencheur fonctionnait en arrière-plan et le contrôle de visibilité était la seule information fiable.

var timestamp             = new Date().getTime();
var timerDelay              = 5000;
var processingBuffer  = 2000;

var redirect = function(url) {
  //window.location = url;
  log('ts: ' + timestamp + '; redirecting to: ' + url);
}
var isPageHidden = function() {
    var browserSpecificProps = {hidden:1, mozHidden:1, msHidden:1, webkitHidden:1};
    for (var p in browserSpecificProps) {
        if(typeof document[p] !== "undefined"){
        return document[p];
      }
    }
    return false; // actually inconclusive, assuming not
}
var elapsedMoreTimeThanTimerSet = function(){
    var elapsed = new Date().getTime() - timestamp;
  log('elapsed: ' + elapsed);
  return timerDelay + processingBuffer < elapsed;
}
var redirectToFallbackIfBrowserStillActive = function() {
  var elapsedMore = elapsedMoreTimeThanTimerSet();
  log('hidden:' + isPageHidden() +'; time: '+ elapsedMore);
  if (isPageHidden() || elapsedMore) {
    log('not redirecting');
  }else{
    redirect('appStoreUrl');
  }
}
var log = function(msg){
    document.getElementById('log').innerHTML += msg + "<br>";
}

setTimeout(redirectToFallbackIfBrowserStillActive, timerDelay);
redirect('nativeApp://');

JS Fiddle

1
ptrk