iPhone Safari Web App apre i collegamenti in una nuova finestra


155

Ho un problema con il web dopo aver aggiunto l'icona alla schermata principale. Se il web viene avviato dalla schermata principale, tutti i collegamenti si apriranno in una nuova finestra in Safari (e perderanno la funzionalità a schermo intero). Come posso prevenirlo? Non sono riuscito a trovare alcun aiuto, solo la stessa domanda senza risposta.


3
Ora puoi usare il scopeparametro in manifest.json. Vedi la mia risposta per maggiori dettagli. L'ho provato su iOS 11.3 e funziona.
Amir Raminfar,

3
Per ribadire, per chiunque abbia difficoltà con iOS 11.3 ad aprire Safari, vedere la risposta di @ AmirRaminfar qui: stackoverflow.com/a/49604315/32055
Chris Haines,

Risposte:


110

Ho trovato la soluzione JavaScript nel 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
    }
}

25
Per affermare l'ovvio e renderlo esplicito: iOS tratta i collegamenti nelle app Web come qualcosa che dovrebbe essere aperto in Safari e la posizione javascript cambia come un'azione in-app che può essere sfruttata nell'applicazione web. Il codice sopra funziona perché impedisce il comportamento di collegamento predefinito, sostituendolo con una chiamata js nav.
Oskar Austegard,

6
C'è un esempio del contrario? Costringere un'app Web per iPhone ad aprire una pagina in Safari anche se si tratta di un cambio di posizione javascript?
tkahn

1
@Pavel grazie per aver menzionato iwebkit :). Aiuta a ottenere un po 'di traffico: D
cmplieger

3
[].forEach.call(document.links, function(link) { link.addEventListener("click", function(event) { event.preventDefault(); window.location = this.href; }) });
alex,

1
Questo ha effetti collaterali?
pingu,

94

Le altre soluzioni qui non tengono conto dei collegamenti esterni (che probabilmente si desidera aprire esternamente in Safari) o non tengono conto dei collegamenti relativi (senza il dominio in essi).

Il progetto html5 mobile-boilerplate si collega a questa sintesi che ha una buona discussione sull'argomento: https://gist.github.com/1042026

Ecco il codice finale che hanno inventato:

<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>

Funziona alla grande, tranne per una pagina, la pagina "Contattaci" per la nostra azienda. Invece di mostrare la pagina, apre l'applicazione "Maps" e individua il nostro ufficio. Cosa potrebbe causare questo e come possiamo risolverlo?
Jonathan,

@Jonathan non ne sono sicuro. Non succede se rimuovi questo script? Forse pubblicare un link al tuo sito? O aprire una nuova domanda, potrebbe essere migliore.
rmarscher,

@rmarscher Questo succede solo quando si esegue il codice fornito e non senza di esso. Sono uno sviluppatore web e non capisco perché gestisca il collegamento in questo modo. Non ho un URL di pagina perché al momento non sta eseguendo il codice, quindi non lo noterai. Inoltre, influisce anche sul normale Safari e non solo autonomo. Grazie per la tua risposta!
Jonathan,

Questa dovrebbe essere la risposta accettata e ha incantato il mio client a schermo intero iPad1 realizzato con PHPRunner inserendo il codice nell'intestazione. Non sono sicuro del motivo per cui è così offuscato in quanto sembra un po 'di codice abbastanza conciso che potrebbe essere scritto in modo leggibile senza molto sovraccarico di BW ... ma è solo schizzinoso e in genere voglio davvero ringraziare.
Sradforth,

4
Ciò interrompe cose Bootstrappy come i collegamenti href = "#" utilizzati dalle funzioni js
Sean

47

Se stai usando jQuery, puoi fare:

$("a").click(function (event) {
    event.preventDefault();
    window.location = $(this).attr("href");
});

1
Spiega perché .live () potrebbe essere migliore?
ajcw,

8
live vincolerà l'evento a tutti i link inclusi quelli che non esistono ancora, click si legherà solo a quelli che esistono attualmente
msaspence,

Grazie! salvavita. Ho appena trascorso ore a cercare di capire perché Safari si caricasse continuamente.
Steve,

1
+1 da me - usato this.hrefpiuttosto che lanciare un oggetto jQuery, ma grazie per questa risposta. Funziona su iOS6.
Fenton,

17
.live () è obsoleto a partire da jQuery 1.7 e rimosso a partire da 1.9 . Utilizzare invece $ (document) .on ('click', 'a', function () {...}).
Tom Davies,

21

Questo funziona per me su iOS 6.1 e con collegamenti Bootstrap JS (ad esempio menu a discesa, ecc.)

$(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;
        }
      });
    }
  });

1
+1. Questo in realtà controlla se stai usando una webapp prima di correggere i collegamenti.
Carrello

1
Funziona su iOS 8.0.2! Grazie
Joel Murphy,

1
@sean Ho un'altra webapp in esecuzione su un iPad che sta usando una mappa immagine come href e questo codice non funziona .. Funziona bene per tutti gli altri collegamenti. Qualche idea su come far funzionare questo codice con le mappe immagine? Ho provato a copiare l'intero pezzo e a sostituire $('a').on('click', function (e) {`con $('area').on('click', function (e) {` ma non sembra funzionare neanche. Qualche idea?
nematoth,

Nel caso in cui tu abbia già definito le funzioni click acon href="#"allora puoi essere più specifico sul selettore jquery, ad es.$('a[href!="#"]')
cjk

13

Questa è una vecchia domanda e molte delle soluzioni qui stanno usando JavaScript. Da allora, iOS 11.3 è stato rilasciato e ora è possibile utilizzare il membro ambito . Il membro dell'ambito è un URL come quello in "/"cui tutti i percorsi nell'ambito non apriranno una nuova pagina.

Il membro scope è una stringa che rappresenta l'ambito di navigazione del contesto dell'applicazione di questa applicazione Web.

Ecco il mio esempio:

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

Puoi anche leggere di più qui . Consiglio anche di utilizzare il generatore che fornirà questa funzionalità.

Se specifichi l'ambito, tutto funziona come previsto simile ad Android, le destinazioni al di fuori dell'ambito si apriranno in Safari - con un pulsante indietro (quello piccolo nella barra di stato) sul tuo PWA.


7
Sfortunatamente, non credo che tu possa includere altri siti Web (come accessi OAuth su un altro dominio) nell'ambito.
bhollis,

Ehi @Amir, ho creato un pwa usando Angular e su Android, ricevo il 'Aggiungi alla schermata iniziale' come sembra che stia leggendo correttamente il mio manfest.json. Tuttavia, su IO Chrome / Safari, nessun prompt ... qualche idea?
ustad

5

Sulla base della risposta di Davids e del commento di Richards, è necessario eseguire un controllo del dominio. In caso contrario, verranno aperti anche collegamenti ad altri siti Web nell'app Web.

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

    if (href.indexOf(location.hostname) > -1)
    {
        event.preventDefault();
        window.location = href;
    }
});

Buona aggiunta alle soluzioni di cui sopra. Era necessario un controllo del dominio per impedire alle persone di aprire siti esterni all'app. Funziona anche su iOS 5.
Ian,

funziona su iOS 5 anche per me. A volte il problema potrebbe riguardare la cache. Durante il test di approcci diversi non sono stato in grado di forzare iOS a invalidare la sua cache e recuperare la nuova versione dei file JS (Safari ha raccolto le modifiche ma non più dopo aver aggiunto l'app alla schermata principale). La modifica della porta del mio server di sviluppo ha aiutato. Se hai max-age = 0 impostato (o equivalente), probabilmente questo non ti influenzerà.
Lukasz Korzybski,

5

Se si utilizza jQuery Mobile, verrà visualizzata la nuova finestra quando si utilizza l'attributo data-ajax = 'false'. In effetti, ciò accadrà ogni volta che ajaxEnabled è disattivato, essendo by e collegamento esterno, tramite un'impostazione $ .mobile.ajaxEnabled o avendo un attributo target = ''.

Puoi risolverlo usando questo:

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

(Grazie a Richard Poole per il metodo live () - non funzionava con bind ())

Se hai disattivato ajaxEnabled a livello globale, dovrai eliminare [data-ajax = 'false'].

Mi ci è voluto un po 'di tempo per capire, poiché mi aspettavo che fosse un problema specifico di jQuery Mobile, dove in realtà era il collegamento Ajax a proibire effettivamente la nuova finestra.


Perfetto, mi hai salvato :)
Saulob,

3

Questo codice funziona per iOS 5 (ha funzionato per me):

Nel tag head:

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

Nel collegamento che si desidera aprire nella stessa finestra:

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

Ho ottenuto questo codice da questo commento: meta tag per l'app web per iPhone


Per qualche ragione penso che questo sia il più facile da comprendere.
Jerrybibo,

3

Forse dovresti consentire di aprire i collegamenti in una nuova finestra quando target è esplicitamente impostato anche su "_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;
    }

});

Molte grazie! Questo è l'unico codice che ha funzionato per iOS5 con Twitter Bootstrap. Non funziona sulla produzione però.
Chim Kan,

Mmm non sono così sicuro del perché non funzionerebbe in produzione ma penso che sia qualcos'altro. Fammelo sapere!
daformat,


2

Puoi anche fare il collegamento quasi normalmente:

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

E puoi rimuovere il tag hash e href, tutto ciò che fa influenza l'aspetto.


2

Questo è ciò che ha funzionato per me su iOS 6 (lievissimo adattamento della risposta di 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>

2

Questa è una versione leggermente adattata di Sean che stava impedendo il pulsante Indietro

// 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;
    }
  });
}

});


1

Per quelli con Twitter Bootstrap e Rails 3

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

I collegamenti di eliminazione funzionano ancora in questo modo.


1

Preferisco aprire tutti i collegamenti all'interno della modalità app Web autonoma tranne quelli con target = "_ blank". Usando jQuery, ovviamente.

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

1

Una soluzione alternativa che ho usato per un'app Web iOS è stata quella di creare tutti i collegamenti (che erano pulsanti tramite CSS) dai pulsanti di invio. Quindi ho aperto un modulo che ha pubblicato sul link di destinazione, quindi input type = "submit" Non è il modo migliore, ma è quello che ho capito prima di trovare questa pagina.



1

Per coloro che utilizzano JQuery Mobile, le soluzioni precedenti interrompono la finestra di dialogo popup. Ciò manterrà i collegamenti all'interno di webapp e consentirà i popup.

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

Potrebbe anche farlo:

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

0

Ecco cosa userei per tutti i link in una pagina ...

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

Se stai usando jQuery o Zepto ...

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

-3

Puoi semplicemente rimuovere questo meta tag.

<meta name="apple-mobile-web-app-capable" content="yes">
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.