iPhone Safari Web App ouvre des liens dans une nouvelle fenêtre

155

J'ai un problème avec le Web après avoir ajouté une icône à l'écran d'accueil. Si le Web est lancé à partir de l'écran d'accueil, tous les liens s'ouvriront dans une nouvelle fenêtre dans Safari (et perdront la fonctionnalité plein écran). Comment puis-je l'empêcher? Je n'ai trouvé aucune aide, seulement la même question sans réponse.

Pavel Linkesch
la source
3
Vous pouvez maintenant utiliser le scopeparamètre dans manifest.json. Voir ma réponse pour plus de détails. Je l'ai testé dans iOS 11.3 et cela fonctionne.
Amir Raminfar
3
Pour réitérer, pour quiconque a du mal avec iOS 11.3 ouvrant Safari, veuillez consulter la réponse de @ AmirRaminfar ici: stackoverflow.com/a/49604315/32055
Chris Haines

Réponses:

110

J'ai trouvé une solution JavaScript dans le framework iWebKit :

var a=document.getElementsByTagName("a");
for(var i=0;i<a.length;i++)
{
    a[i].onclick=function()
    {
        window.location=this.getAttribute("href");
        return false
    }
}
Pavel Linkesch
la source
25
Pour indiquer l'évidence et rendre cela explicite: iOS traite les liens dans Web Apps comme quelque chose qui devrait être ouvert dans Safari, et les changements d'emplacement javascript comme une action dans l'application qui est autorisée à saty dans l'application Web. Le code ci-dessus fonctionne car il empêche le comportement de lien par défaut, en le remplaçant par un appel js nav.
Oskar Austegard
6
Y a-t-il un exemple du contraire? Forcer une application Web iPhone à ouvrir une page dans Safari même s'il s'agit d'un changement d'emplacement javascript?
tkahn le
1
@Pavel merci d'avoir mentionné iwebkit :). Aide à obtenir du trafic: D
cmplieger
3
[].forEach.call(document.links, function(link) { link.addEventListener("click", function(event) { event.preventDefault(); window.location = this.href; }) });
alex
1
Cela a-t-il des effets secondaires?
pingu
94

Les autres solutions ici ne tiennent pas compte des liens externes (que vous souhaitez probablement ouvrir en externe dans Safari) ou ne tiennent pas compte des liens relatifs (sans le domaine en eux).

Le projet html5 mobile-passe-partout est lié à cet essentiel qui a une bonne discussion sur le sujet: https://gist.github.com/1042026

Voici le code final qu'ils ont trouvé:

<script>(function(a,b,c){if(c in b&&b[c]){var d,e=a.location,f=/^(a|html)$/i;a.addEventListener("click",function(a){d=a.target;while(!f.test(d.nodeName))d=d.parentNode;"href"in d&&(d.href.indexOf("http")||~d.href.indexOf(e.host))&&(a.preventDefault(),e.href=d.href)},!1)}})(document,window.navigator,"standalone")</script>
rmarscher
la source
Cela fonctionne très bien sauf pour une page, la page "Contactez-nous" pour notre entreprise. Au lieu d'afficher la page, il ouvre l'application «Cartes» et repère notre bureau. Qu'est-ce qui pourrait en être la cause et comment pouvons-nous y remédier?
Jonathan
@Jonathan Je ne suis pas sûr. Cela n'arrive-t-il pas si vous supprimez ce script? Peut-être publier un lien vers votre site? Ou ouvrez une nouvelle question, cela pourrait être mieux.
rmarscher
@rmarscher Cela ne se produit que lors de l'exécution du code que vous avez fourni et non sans lui. Je suis moi-même développeur Web et je ne comprends pas pourquoi il gérerait le lien de cette façon. Je n'ai pas d'URL de page car elle n'exécute actuellement pas le code, vous ne le remarquerez donc pas. En outre, cela affecte également le Safari régulier, et pas seulement autonome. Merci pour votre réponse!
Jonathan
Cela devrait être la réponse acceptée et a fonctionné un charme sur mon client plein écran iPad1 fait avec PHPRunner en plaçant le code dans l'en-tête. Je ne sais pas pourquoi il est si obscurci car il semble assez concis de code qui pourrait être écrit de manière lisible sans trop de surcharge BW ... c'est juste d'être difficile et je veux généralement dire merci.
sradforth
4
Cela brise les choses Bootstrappy telles que les liens href = "#" qui sont utilisés par les fonctions js
Sean
47

Si vous utilisez jQuery, vous pouvez faire:

$("a").click(function (event) {
    event.preventDefault();
    window.location = $(this).attr("href");
});
David H.
la source
1
Veuillez expliquer pourquoi .live () pourrait être meilleur?
ajcw
8
live liera l'événement à tous les liens, y compris ceux qui n'existent pas encore, cliquez sur ne liera que ceux qui existent actuellement
msaspence
Merci! bouée de sauvetage. Je viens de passer des heures à essayer de comprendre pourquoi le safari se chargeait tout le temps.
Steve
1
+1 de moi - utilisé this.hrefplutôt que de lancer vers un objet jQuery, mais merci pour cette réponse. Fonctionne sur iOS6.
Fenton
17
.live () est obsolète à partir de jQuery 1.7 et supprimé à partir de 1.9 . Utilisez plutôt $ (document) .on ('click', 'a', function () {...}).
Tom Davies
21

Cela fonctionne pour moi sur iOS 6.1 et avec les liens Bootstrap JS (c'est-à-dire les menus déroulants, etc.)

$(document).ready(function(){
    if (("standalone" in window.navigator) && window.navigator.standalone) {
      // For iOS Apps
      $('a').on('click', function(e){
        e.preventDefault();
        var new_location = $(this).attr('href');
        if (new_location != undefined && new_location.substr(0, 1) != '#' && $(this).attr('data-method') == undefined){
          window.location = new_location;
        }
      });
    }
  });
Sean
la source
1
+1. Cela vérifie en fait si vous utilisez une application Web avant de corriger les liens.
Trolley
1
Fonctionne sous iOS 8.0.2! Merci
Joel Murphy
1
@sean J'ai une autre application Web en cours d'exécution dans un iPad qui utilise une image map comme href et ce code ne fonctionne pas .. Cela fonctionne bien pour tous les autres liens. Des idées pour faire fonctionner ce code avec des images cartographiques? J'ai essayé de copier le morceau entier et de remplacer $('a').on('click', function (e) {`par $('area').on('click', function (e) {` mais cela ne semble pas fonctionner non plus. Des idées?
nematoth
Si vous avez déjà défini des fonctions de clic aavec, href="#"vous pouvez être plus précis sur le sélecteur jquery, par exemple$('a[href!="#"]')
cjk
13

C'est une vieille question et de nombreuses solutions ici utilisent javascript. Depuis lors, iOS 11.3 a été publié et vous pouvez désormais utiliser le membre de l' étendue . Le membre de l'étendue est une URL comme "/"où tous les chemins sous cette étendue n'ouvriront pas une nouvelle page.

Le membre de la portée est une chaîne qui représente la portée de navigation du contexte d'application de cette application Web.

Voici mon exemple:

{
  "name": "Test",
  "short_name": "Test",
  "lang": "en-US",
  "start_url": "/",
  "scope": "/",
  ...
}

Vous pouvez également en savoir plus ici . Je recommande également d'utiliser le générateur qui fournira cette fonctionnalité.

Si vous spécifiez la portée, tout fonctionne comme prévu, similaire à Android, les destinations hors de la portée s'ouvriront dans Safari - avec un bouton de retour (le petit dans la barre d'état) sur votre PWA.

Amir Raminfar
la source
7
Malheureusement, je ne pense pas que vous puissiez inclure d'autres sites Web (tels que les connexions OAuth sur un autre domaine) dans la portée.
bhollis
Hey @Amir, j'ai créé un pwa en utilisant Angular et sur Android, j'obtiens l'invite `` Ajouter à l'écran d'accueil '' car il semble lire correctement mon manfest.json. Cependant, sur IOs Chrome / Safari, aucune invite ... des idées?
ustad
5

Sur la base de la réponse de Davids et du commentaire de Richards, vous devez effectuer une vérification de domaine. Sinon, des liens vers d'autres sites Web s'ouvriront également dans votre application Web.

$('a').live('click', function (event)
{      
    var href = $(this).attr("href");

    if (href.indexOf(location.hostname) > -1)
    {
        event.preventDefault();
        window.location = href;
    }
});
Thomas Kekeisen
la source
Bon ajout aux solutions ci-dessus. Il fallait une vérification de domaine pour empêcher les gens d'ouvrir des sites extérieurs dans l'application. Fonctionne également sur iOS 5.
Ian
fonctionne aussi sur iOS 5 pour moi. Le problème peut parfois être lié au cache. En testant différentes approches, je n'ai pas pu forcer iOS à invalider son cache et à récupérer la nouvelle version des fichiers JS (Safari a pris les modifications mais pas plus après l'ajout de l'application à l'écran d'accueil). Le changement de port de mon serveur de développement a aidé. Si vous avez défini max-age = 0 (ou équivalent), cela ne vous affectera probablement pas.
Lukasz Korzybski
5

Si vous utilisez jQuery Mobile, vous rencontrerez la nouvelle fenêtre lors de l'utilisation de l'attribut data-ajax = 'false'. En fait, cela se produira chaque fois que ajaxEnabled est désactivé, par un lien externe, par un paramètre $ .mobile.ajaxEnabled ou en ayant un attribut target = ''.

Vous pouvez le réparer en utilisant ceci:

$("a[data-ajax='false']").live("click", function(event){
  if (this.href) {
    event.preventDefault();
    location.href=this.href;
    return false;
  }
});

(Merci à Richard Poole pour la méthode live () - ne fonctionnait pas avec bind ())

Si vous avez désactivé ajaxEnabled globalement, vous devrez supprimer [data-ajax = 'false'].

Cela m'a pris assez de temps à comprendre car je m'attendais à ce que ce soit un problème spécifique à jQuery Mobile où en fait c'était la liaison Ajax qui interdisait la nouvelle fenêtre.

Jason Prawn
la source
Parfait, tu m'as sauvé :)
saulob
3

Ce code fonctionne pour iOS 5 (cela a fonctionné pour moi):

Dans la balise head:

<script type="text/javascript">
    function OpenLink(theLink){
        window.location.href = theLink.href;
    }
</script>

Dans le lien que vous souhaitez ouvrir dans la même fenêtre:

<a href="(your website here)" onclick="OpenLink(this); return false"> Link </a>

J'ai obtenu ce code de ce commentaire: balises meta pour iphone web

SerinEleven
la source
Pour une raison quelconque, je pense que c'est la plus facile à comprendre.
Jerrybibo
3

Peut-être devriez-vous autoriser l'ouverture de liens dans une nouvelle fenêtre lorsque la cible est également définie explicitement sur "_blank":

$('a').live('click', function (event)
{      
    var href = $(this).attr("href");

    // prevent internal links (href.indexOf...) to open in safari if target
    // is not explicitly set_blank, doesn't break href="#" links
    if (href.indexOf(location.hostname) > -1 && href != "#" && $(this).attr("target") != "_blank")
    {
        event.preventDefault();
        window.location = href;
    }

});
daformat
la source
Merci beaucoup! C'est le seul code qui a fonctionné pour iOS5 avec Twitter Bootstrap. Cela ne fonctionne pas sur la production cependant.
Chim Kan
Mmm je ne sais pas trop pourquoi cela ne fonctionnerait pas en production mais je pense que c'est autre chose. Faites le moi savoir!
daformat
2

Vous pouvez également créer des liens presque normalement:

<a href="#" onclick="window.location='URL_TO_GO';">TEXT OF THE LINK</a>

Et vous pouvez supprimer la balise de hachage et href, tout ce qu'elle fait affecte l'apparence.

JuR
la source
2

C'est ce qui a fonctionné pour moi sur iOS 6 (très légère adaptation de la réponse de rmarscher):

<script>                                                                
    (function(document,navigator,standalone) {                          
        if (standalone in navigator && navigator[standalone]) {         
            var curnode,location=document.location,stop=/^(a|html)$/i;  
            document.addEventListener("click", function(e) {            
                curnode=e.target;                                       
                while (!stop.test(curnode.nodeName)) {                  
                    curnode=curnode.parentNode;                         
                }                                                       
                if ("href" in curnode && (curnode.href.indexOf("http") || ~curnode.href.indexOf(location.host)) && curnode.target == false) {
                    e.preventDefault();                                 
                    location.href=curnode.href                          
                }                                                       
            },false);                                                   
        }                                                               
    })(document,window.navigator,"standalone")                          
</script>
bjh
la source
2

Ceci est une version légèrement adaptée de Sean qui empêchait le bouton de retour

// this function makes anchor tags work properly on an iphone

$(document).ready(function(){
if (("standalone" in window.navigator) && window.navigator.standalone) {
  // For iOS Apps
  $("a").on("click", function(e){

    var new_location = $(this).attr("href");
    if (new_location != undefined && new_location.substr(0, 1) != "#" && new_location!='' && $(this).attr("data-method") == undefined){
      e.preventDefault();
      window.location = new_location;
    }
  });
}

});

Richard Turner
la source
1

Pour ceux qui ont Twitter Bootstrap et Rails 3

$('a').live('click', function (event) {
  if(!($(this).attr('data-method')=='delete')){
    var href = $(this).attr("href");
    event.preventDefault();
    window.location = href; 
  }   
});

Les liens de suppression fonctionnent toujours de cette façon.

wouf
la source
1

Je préfère ouvrir tous les liens à l'intérieur du mode d'application Web autonome, sauf ceux qui ont target = "_ blank". En utilisant jQuery, bien sûr.

$(document).on('click', 'a', function(e) {
    if ($(this).attr('target') !== '_blank') {
        e.preventDefault();
        window.location = $(this).attr('href');
    }
});
Alex Haas
la source
1

Une solution de contournement que j'ai utilisée pour une application Web iOS était que j'ai créé tous les boutons de soumission de formulaires (qui étaient des boutons par CSS). J'ai donc ouvert un formulaire qui a posté sur le lien de destination, puis input type = "submit" Ce n'est pas la meilleure façon, mais c'est ce que j'ai compris avant de trouver cette page.

dster77
la source
1

Pour ceux qui utilisent JQuery Mobile, les solutions ci-dessus cassent la boîte de dialogue contextuelle. Cela conservera les liens dans l'application Web et autorisera les fenêtres contextuelles.

$(document).on('click','a', function (event) {
    if($(this).attr('href').indexOf('#') == 0) {
        return true;
    }
    event.preventDefault();
    window.location = $(this).attr('href');     
});

Pourrait également le faire en:

$(document).on('click','a', function (event){
    if($(this).attr('data-rel') == 'popup'){
        return true;
    }
    event.preventDefault();
    window.location = $(this).attr('href');     
});
Hexchaimen
la source
0

Voici ce que j'utiliserais pour tous les liens sur une page ...

document.body.addEventListener(function(event) {
    if (event.target.href && event.target.target != "_blank") {
        event.preventDefault();
        window.location = this.href;                
    }
});

Si vous utilisez jQuery ou Zepto ...

$("body").on("click", "a", function(event) {
   event.target.target != "_blank" && (window.location = event.target.href);
});
Alex
la source
-3

Vous pouvez simplement supprimer cette balise meta.

<meta name="apple-mobile-web-app-capable" content="yes">
Parc Soohwan
la source