Die iPhone Safari Web App öffnet Links in einem neuen Fenster


155

Ich habe ein Problem mit dem Web, nachdem ich dem Startbildschirm ein Symbol hinzugefügt habe. Wenn das Web über den Startbildschirm gestartet wird, werden alle Links in Safari in einem neuen Fenster geöffnet (und verlieren die Vollbildfunktionalität). Wie kann ich das verhindern? Ich konnte keine Hilfe finden, nur die gleiche unbeantwortete Frage.


3
Sie können jetzt den scopeParameter in verwenden manifest.json. Siehe meine Antwort für weitere Details. Ich habe es in iOS 11.3 getestet und es funktioniert.
Amir Raminfar

3
Um es noch einmal zu wiederholen, für alle, die Probleme mit der Eröffnung von Safari mit iOS 11.3 haben, lesen Sie bitte die Antwort von @ AmirRaminfar hier: stackoverflow.com/a/49604315/32055
Chris Haines

Antworten:


110

Ich habe eine JavaScript-Lösung im iWebKit- Framework gefunden:

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
Um das Offensichtliche zu sagen und dies explizit zu machen: iOS behandelt Links in Web-Apps als etwas, das in Safari geöffnet werden sollte, und der Javascript-Speicherort ändert sich als In-App-Aktion, die in der Web-App ausgeführt werden darf. Der obige Code funktioniert, weil er das Standardverhalten der Verbindung verhindert und durch einen js nav-Aufruf ersetzt.
Oskar Austegard

6
Gibt es ein Beispiel für das Gegenteil? Erzwingen, dass eine iPhone-Web-App eine Seite in Safari öffnet, obwohl es sich um eine Änderung des Javascript-Speicherorts handelt?
Tkahn

1
@ Pavel danke für die Erwähnung von iwebkit :). Hilft, etwas Verkehr zu bekommen: D
cmplieger

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

1
Hat dies irgendwelche Nebenwirkungen?
Pingu

94

Die anderen Lösungen hier berücksichtigen entweder keine externen Links (die Sie wahrscheinlich extern in Safari öffnen möchten) oder keine relativen Links (ohne die darin enthaltene Domain).

Das html5 Mobile-Boilerplate-Projekt verweist auf diesen Kern, der eine gute Diskussion zum Thema enthält: https://gist.github.com/1042026

Hier ist der endgültige Code, den sie sich ausgedacht haben:

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

Dies funktioniert hervorragend, bis auf eine Seite, die Seite "Kontakt" für unser Unternehmen. Anstatt die Seite anzuzeigen, wird die Anwendung "Karten" geöffnet und unser Büro lokalisiert. Was könnte dies verursachen und wie können wir es beheben?
Jonathan

@ Jonathan Ich bin nicht sicher. Kommt es nicht vor, wenn Sie dieses Skript entfernen? Vielleicht einen Link zu deiner Seite posten? Oder öffnen Sie eine neue Frage, die vielleicht besser ist.
Rmarscher

@rmarscher Dies geschieht nur, wenn der von Ihnen angegebene Code ausgeführt wird und nicht ohne. Ich bin selbst Webentwickler und verstehe nicht, warum der Link so gehandhabt wird. Ich habe keine Seiten-URL, da der Code derzeit nicht ausgeführt wird und Sie ihn nicht bemerken. Dies betrifft auch die reguläre Safari und nicht nur Standalone. Danke für deine Antwort!
Jonathan

Dies sollte die akzeptierte Antwort sein und auf meinem iPad1-Vollbild-Client, der mit PHPRunner erstellt wurde, einen Reiz haben, indem der Code in die Kopfzeile eingefügt wurde. Ich bin mir nicht sicher, warum es so verschleiert ist, da es ein ziemlich prägnantes Stück Code zu sein scheint, das ohne viel BW-Aufwand leserlich geschrieben werden könnte ... das ist allerdings nur wählerisch und möchte im Allgemeinen wirklich Danke sagen.
Sradforth

4
Dies bricht Bootstrappy Dinge wie href = "#" Links, die von js Funktionen verwendet werden
Sean

47

Wenn Sie jQuery verwenden, können Sie Folgendes tun:

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

1
Bitte erklären Sie, warum .live () besser sein könnte.
Ajcw

8
Live bindet das Ereignis an alle Links, einschließlich derer, die noch nicht existieren. Klicken Sie nur an diejenigen, die derzeit existieren
msaspence

Vielen Dank! Lebensretter. Ich habe nur Stunden damit verbracht herauszufinden, warum die Safari die ganze Zeit geladen wurde.
Steve

1
+1 von mir - wird verwendet, this.hrefanstatt in ein jQuery-Objekt umzuwandeln, aber danke für diese Antwort. Funktioniert unter iOS6.
Fenton

17
.live () ist ab jQuery 1.7 veraltet und ab 1.9 entfernt . Verwenden Sie stattdessen $ (document) .on ('click', 'a', function () {...}).
Tom Davies

21

Dies funktioniert für mich unter iOS 6.1 und mit Bootstrap JS-Links (dh Dropdown-Menüs usw.)

$(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. Dadurch wird tatsächlich überprüft, ob Sie eine Webanwendung verwenden, bevor die Links repariert werden.
Trolley

1
Funktioniert in iOS 8.0.2! Vielen Dank
Joel Murphy

1
@sean Ich habe eine andere Webanwendung auf einem iPad, die eine Imagemap als href verwendet, und dieser Code funktioniert nicht. Es funktioniert gut für alle anderen Links. Irgendwelche Ideen, wie dieser Code mit Imagemaps funktioniert? Ich habe versucht, den gesamten Block zu kopieren und $('a').on('click'Funktion (e) {`durch $('area').on('click'Funktion (e) {` zu ersetzen , aber das scheint auch nicht zu funktionieren. Irgendwelche Ideen?
Nematoth

Falls Sie bereits Funktionen Klick definiert auf amit , href="#"dann können Sie spezifischere auf dem jQuery - Selektor, zB$('a[href!="#"]')
cjk

13

Dies ist eine alte Frage, und viele der hier verwendeten Lösungen verwenden Javascript. Seitdem wurde iOS 11.3 veröffentlicht und Sie können jetzt das Scope-Mitglied verwenden . Das Bereichsmitglied ist eine URL, "/"bei der nicht alle Pfade unter diesem Bereich eine neue Seite öffnen.

Das Bereichsmitglied ist eine Zeichenfolge, die den Navigationsbereich des Anwendungskontexts dieser Webanwendung darstellt.

Hier ist mein Beispiel:

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

Sie können auch weitere Informationen lesen Sie hier . Ich empfehle auch die Verwendung des Generators, der diese Funktionalität bietet.

Wenn Sie den Bereich angeben, funktioniert alles wie erwartet, ähnlich wie bei Android. Ziele außerhalb des Bereichs werden in Safari geöffnet - mit einer Zurück-Schaltfläche (die kleine in der Statusleiste) für Ihre PWA.


7
Leider glaube ich nicht, dass Sie andere Websites (wie OAuth-Anmeldungen auf einer anderen Domain) in den Geltungsbereich aufnehmen können.
Bhollis

Hey @Amir, ich habe ein Pwa mit Angular erstellt und unter Android erhalte ich die Eingabeaufforderung "Zum Startbildschirm hinzufügen", da es so aussieht, als würde es meine manfest.json richtig lesen. Auf IOs Chrome / Safari jedoch keine Eingabeaufforderung ... irgendwelche Ideen?
Am

5

Basierend auf Davids Antwort und Richards Kommentar sollten Sie eine Domainprüfung durchführen. Andernfalls werden auch Links zu anderen Websites in Ihrer Web-App geöffnet.

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

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

Gute Ergänzung zu den oben genannten Lösungen. Benötigte eine Domain-Überprüfung, um zu verhindern, dass Personen externe Websites in der App öffnen. Funktioniert auch unter iOS 5.
Ian

funktioniert auch unter iOS 5 für mich. Das Problem kann manchmal mit dem Cache sein. Beim Testen verschiedener Ansätze konnte ich iOS nicht zwingen, den Cache ungültig zu machen und eine neue Version von JS-Dateien abzurufen (Safari hat die Änderungen übernommen, jedoch nicht mehr, nachdem die App zum Startbildschirm hinzugefügt wurde). Das Ändern des Ports meines Entwicklungsservers hat geholfen. Wenn Sie das Höchstalter = 0 festgelegt haben (oder ein gleichwertiges Alter), hat dies wahrscheinlich keine Auswirkungen auf Sie.
Lukasz Korzybski

5

Wenn Sie jQuery Mobile verwenden, wird das neue Fenster angezeigt, wenn Sie das Attribut data-ajax = 'false' verwenden. Tatsächlich geschieht dies immer dann, wenn ajaxEnabled durch einen externen Link, durch eine Einstellung von $ .mobile.ajaxEnabled oder durch ein Attribut target = '' deaktiviert wird.

Sie können dies folgendermaßen beheben:

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

(Danke an Richard Poole für die live () Methode - funktionierte nicht mit bind ())

Wenn Sie ajaxEnabled global deaktiviert haben, müssen Sie [data-ajax = 'false'] löschen.

Es dauerte ziemlich lange, bis ich herausgefunden hatte, dass es sich um ein jQuery Mobile-spezifisches Problem handelte, bei dem es tatsächlich die Ajax-Verknüpfung war, die das neue Fenster tatsächlich verbot.


Perfekt, du hast mich gerettet :)
Saulob

3

Dieser Code funktioniert für iOS 5 (er hat bei mir funktioniert):

In der Kopfmarke:

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

In dem Link, den Sie im selben Fenster öffnen möchten:

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

Ich habe diesen Code aus diesem Kommentar erhalten: iPhone Web App Meta-Tags


Aus irgendeinem Grund denke ich, dass dies am einfachsten zu verstehen ist.
Jerrybibo

3

Vielleicht sollten Sie zulassen, dass Links in einem neuen Fenster geöffnet werden, wenn das Ziel explizit auf "_blank" gesetzt ist:

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

});

Vielen Dank! Dies ist der einzige Code, der für iOS5 mit Twitter Bootstrap funktioniert hat. Bei der Produktion funktioniert das allerdings nicht.
Chim Kan

Mmm nicht so sicher, warum es in der Produktion nicht funktionieren würde, aber ich denke, es ist etwas anderes. Lass es mich wissen!
Daformat


2

Sie können auch fast normal verknüpfen:

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

Und Sie können das Hash-Tag und href entfernen, alles, was es tut, wirkt sich auf das Erscheinungsbild aus.


2

Dies hat bei iOS 6 für mich funktioniert (sehr geringfügige Anpassung der Antwort von 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

Dies ist eine leicht angepasste Version von Sean, die den Zurück-Button verhinderte

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

Für diejenigen mit Twitter Bootstrap und Rails 3

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

Löschlinks funktionieren immer noch so.


1

Ich ziehe es vor, alle Links im eigenständigen Web-App-Modus zu öffnen, mit Ausnahme derjenigen, deren Ziel = "_ leer" ist. Natürlich mit jQuery.

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

1

Eine Problemumgehung, die ich für eine iOS-Web-App verwendet habe, war, dass ich alle Links (die Schaltflächen per CSS waren) über Submit-Schaltflächen erstellt habe. Also öffnete ich ein Formular, das auf dem Ziellink gepostet wurde, und gab dann type = "submit" ein. Nicht der beste Weg, aber es ist das, was ich herausgefunden habe, bevor ich diese Seite gefunden habe.



1

Für diejenigen JQuery Mobile, die diese verwenden , unterbrechen die oben genannten Lösungen den Popup-Dialog. Dadurch bleiben Links in der Webanwendung erhalten und Popups sind möglich.

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

Könnte es auch tun durch:

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

0

Folgendes würde ich für alle Links auf einer Seite verwenden ...

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

Wenn Sie jQuery oder Zepto verwenden ...

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

-3

Sie können dieses Meta-Tag einfach entfernen.

<meta name="apple-mobile-web-app-capable" content="yes">
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.