iPhone Safari Web App otwiera łącza w nowym oknie


155

Mam problem z siecią po dodaniu ikony do ekranu głównego. Jeśli Internet jest uruchamiany z ekranu głównego, wszystkie łącza otworzą się w nowym oknie w Safari (i utracą funkcjonalność pełnego ekranu). Jak mogę temu zapobiec? Nie mogłem znaleźć żadnej pomocy, tylko to samo pytanie bez odpowiedzi.


3
Możesz teraz użyć scopeparametru w manifest.json. Zobacz moją odpowiedź, aby uzyskać więcej informacji. Przetestowałem to w iOS 11.3 i działa.
— Amir Raminfar

3
Aby powtórzyć, dla każdego, kto zmaga się z otwieraniem Safari w systemie iOS 11.3, zapoznaj się z odpowiedzią @ AmirRaminfar tutaj: stackoverflow.com/a/49604315/32055
— Chris Haines

Odpowiedzi:


110

Znalazłem rozwiązanie JavaScript w ramach 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
Mówiąc wprost i wyraźnie: iOS traktuje linki w aplikacjach internetowych jako coś, co powinno być otwierane w przeglądarce Safari, a zmiana lokalizacji javascript jako czynność w aplikacji, która może działać w aplikacji internetowej. Powyższy kod działa, ponieważ zapobiega domyślnemu zachowaniu linków, zastępując je wywołaniem js nav.
— Oskar Austegard

6
Czy jest przykład odwrotny? Zmuszanie aplikacji internetowej na iPhone'a do otwierania strony w Safari, mimo że jest to zmiana lokalizacji javascript?
— tkahn

1
@Pavel dziękuję za wspomnienie o iwebkit :). Pomaga uzyskać trochę ruchu: D
— cmplieger

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

1
Czy ma to jakieś skutki uboczne?
— pingu

94

Inne rozwiązania tutaj albo nie uwzględniają linków zewnętrznych (które prawdopodobnie chcesz otworzyć zewnętrznie w Safari) lub nie uwzględniają linków względnych (bez domeny w nich).

Projekt html5 mobile-boilerplate zawiera linki do tego streszczenia, które ma dobrą dyskusję na ten temat: https://gist.github.com/1042026

Oto ostateczny kod, który wymyślili:

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

To działa świetnie, z wyjątkiem jednej strony, strony „Kontakt” dla naszej firmy. Zamiast wyświetlać stronę, otwiera aplikację „Mapy” i wskazuje nasze biuro. Co może być tego przyczyną i jak możemy to naprawić?
— Jonathan,

@Jonathan Nie jestem pewien. Czy to się nie dzieje, jeśli usuniesz ten skrypt? Może zamieść link do swojej strony? Albo otwórz nowe pytanie, może być lepiej.
— rmarscher

@rmarscher Dzieje się tak tylko wtedy, gdy uruchamiasz kod, który podałeś, a nie bez niego. Sam jestem programistą stron internetowych i nie rozumiem, dlaczego miałby obsługiwać łącze w ten sposób. Nie mam adresu URL strony, ponieważ obecnie nie uruchamia ona kodu, więc go nie zauważysz. Dotyczy to również zwykłego Safari, a nie tylko samodzielnego. Dziękuję za odpowiedź!
— Jonathan,

Powinna to być akceptowana odpowiedź i zadziałała urokiem na moim pełnoekranowym kliencie iPad1 wykonanym za pomocą PHPRunner, umieszczając kod w nagłówku. Nie jestem pewien, dlaczego jest tak zaciemniony, ponieważ wydaje się dość zwięzły fragment kodu, który można napisać czytelnie bez dużego narzutu BW ... to tylko wybredne i ogólnie naprawdę chcę podziękować.
— sradforth,

4
To psuje rzeczy Bootstrappy, takie jak linki href = "#" używane przez funkcje js
— Sean,

47

Jeśli używasz jQuery, możesz:

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

1
Proszę wyjaśnić, dlaczego .live () może być lepsze?
— ajcw

8
live spowoduje powiązanie wydarzenia ze wszystkimi linkami, w tym z tymi, które jeszcze nie istnieją, kliknięcie spowoduje powiązanie tylko z tymi, które obecnie istnieją
— msaspence

dzięki! ratownik. Właśnie spędziłem godziny, próbując dowiedzieć się, dlaczego safari cały czas się ładuje.
— Steve,

1
+1 ode mnie - używane this.hrefzamiast rzutowania do obiektu jQuery, ale dzięki za tę odpowiedź. Działa na iOS6.
— Fenton,

17
.live () jest przestarzała od jQuery 1.7 i usunięta od 1.9 . Zamiast tego użyj $ (document) .on ('click', 'a', function () {...}).
— Tom Davies

21

To działa dla mnie na iOS 6.1 i z linkami Bootstrap JS (tj. Menu rozwijane itp.)

$(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. To faktycznie sprawdza, czy używasz aplikacji internetowej przed naprawieniem linków.
— Trolley

1
Działa w iOS 8.0.2! Dzięki
— Joel Murphy

1
@sean Mam inną aplikację internetową uruchomioną na iPadzie, która używa mapy obrazu jako href i ten kod nie działa. Działa dobrze dla wszystkich innych linków. Jakieś pomysły, jak sprawić, by ten kod działał z mapami obrazu? Próbowałem skopiować cały fragment i zamienić $('a').on('click'funkcję (e) {`na $('area').on('click'funkcję (e) {`, ale to też nie działa. Jakieś pomysły?
— nicienie

Jeśli masz już zdefiniowane funkcje klikania za apomocą href="#", możesz być bardziej szczegółowy w selektorze jquery, np.$('a[href!="#"]')
— cjk

13

To jest stare pytanie i wiele rozwiązań tutaj wykorzystuje JavaScript. Od tego czasu wydano iOS 11.3 i możesz teraz używać elementu członkowskiego zakresu . Element członkowski zakresu to adres URL podobny do tego, w "/"którym wszystkie ścieżki w tym zakresie nie otwierają nowej strony.

Element członkowski zakresu to ciąg, który reprezentuje zakres nawigacji w kontekście aplikacji tej aplikacji sieci Web.

Oto mój przykład:

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

Możesz również przeczytać więcej na ten temat tutaj . Polecam również użycie generatora, który zapewni taką funkcjonalność.

Jeśli określisz zakres, wszystko będzie działać zgodnie z oczekiwaniami, podobnie jak w Androidzie, miejsca docelowe poza zakresem zostaną otwarte w Safari - z przyciskiem Wstecz (małym na pasku stanu) do twojego PWA.


7
Niestety nie sądzę, aby można było objąć zakresem inne witryny (np. Loginy OAuth w innej domenie).
— bhollis

Hej @Amir, utworzyłem pwa za pomocą Angulara, a na Androidzie pojawia się komunikat „Dodaj do ekranu głównego”, ponieważ wygląda na to, że poprawnie odczytuje mój plik manfest.json. Jednak na IOs Chrome / Safari nie ma zachęty ... jakieś pomysły?
— ustad

5

Na podstawie odpowiedzi Davidsa i komentarza Richardsa należy przeprowadzić kontrolę domeny. W przeciwnym razie w Twojej aplikacji internetowej zostaną otwarte również linki do innych witryn internetowych.

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

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

Dobry dodatek do powyższych rozwiązań. Potrzebne było sprawdzenie domeny, aby uniemożliwić ludziom otwieranie zewnętrznych witryn w aplikacji. Działa również na iOS 5.
— Ian

dla mnie działa również na iOS 5. Czasami problem może dotyczyć pamięci podręcznej. Podczas testowania różnych podejść nie mogłem zmusić iOS do unieważnienia pamięci podręcznej i pobrania nowej wersji plików JS (Safari odebrało zmiany, ale nie więcej po dodaniu aplikacji do ekranu głównego). Pomogła zmiana portu mojego serwera deweloperskiego. Jeśli masz ustawioną wartość max-age = 0 (lub równoważną), prawdopodobnie nie będzie to miało na Ciebie wpływu.
— Łukasz Korzybski

5

Jeśli używasz jQuery Mobile, zobaczysz nowe okno, używając atrybutu data-ajax = 'false'. W rzeczywistości stanie się to za każdym razem, gdy ajaxEnabled zostanie wyłączony, będąc przez i zewnętrznym łączem, przez ustawienie $ .mobile.ajaxEnabled lub przez posiadanie atrybutu target = ''.

Możesz to naprawić, używając tego:

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

(Podziękowania dla Richarda Poole'a za metodę live () - nie działało z bind ())

Jeśli globalnie wyłączyłeś ajaxEnabled, musisz porzucić [data-ajax = 'false'].

Zajęło mi to dość dużo czasu, aby się zorientować, ponieważ spodziewałem się, że będzie to problem specyficzny dla jQuery Mobile, podczas gdy w rzeczywistości to linkowanie Ajax faktycznie blokowało nowe okno.


Doskonale, uratowałeś mnie :)
— saulob

3

Ten kod działa na iOS 5 (działał dla mnie):

W tagu head:

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

W linku, który chcesz otworzyć w tym samym oknie:

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

Mam ten kod z tego komentarza: metatagi aplikacji internetowej na iPhone'a


Z jakiegoś powodu myślę, że jest to najłatwiejsze do zrozumienia.
— Jerrybibo

3

Może powinieneś zezwolić na otwieranie linków w nowym oknie, gdy cel jest jawnie ustawiony na „_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;
    }

});

Wielkie dzięki! To jedyny kod, który działał dla iOS5 z Twitter Bootstrap. To jednak nie działa na produkcji.
— Chim Kan

Mmm nie jestem taki pewien, dlaczego nie miałby działać w produkcji, ale myślę, że to coś innego. Daj mi znać!
— daformat


2

Możesz też prawie normalnie tworzyć linki:

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

Możesz też usunąć hash tag i href, wszystko, co robi, wpływa na wygląd.


2

Oto, co zadziałało na mnie na iOS 6 (bardzo nieznaczna adaptacja odpowiedzi rmarschera):

<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

Jest to nieco zaadaptowana wersja Seana, która blokowała przycisk Wstecz

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

Dla tych z Twitter Bootstrap i Rails 3

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

Usuwanie linków nadal działa w ten sposób.


1

Wolę otwierać wszystkie linki w trybie samodzielnej aplikacji internetowej z wyjątkiem tych, które mają target = "_ blank". Oczywiście przy użyciu jQuery.

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

1

Jednym z obejść, które zastosowałem w aplikacji internetowej na iOS, było to, że wszystkie linki (które były przyciskami w CSS) tworzyłem przyciski przesyłania. Więc otworzyłem formularz, który wysłał do linku docelowego, a następnie input type = "submit" Nie jest to najlepszy sposób, ale to jest to, co odkryłem, zanim znalazłem tę stronę.



1

W przypadku użytkowników JQuery Mobilepowyższe rozwiązania powodują przerwanie wyskakującego okna dialogowego. Zachowa to linki w aplikacji internetowej i pozwoli na wyświetlanie wyskakujących okienek.

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

Można to również zrobić poprzez:

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

0

Oto, czego użyłbym dla wszystkich linków na stronie ...

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

Jeśli używasz jQuery lub Zepto ...

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

-3

Możesz po prostu usunąć ten metatag.

<meta name="apple-mobile-web-app-capable" content="yes">
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.