iPhone Safari Web App abre links em uma nova janela

155

Tenho um problema com a web depois de adicionar o ícone à tela inicial. Se a web for iniciada na Tela inicial, todos os links abrirão em uma nova janela no Safari (e perderão a funcionalidade de tela cheia). Como posso evitar isso? Não consegui encontrar ajuda, apenas a mesma pergunta sem resposta.

Pavel Linkesch
fonte
3
Agora você pode usar o scopeparâmetro manifest.json. Veja minha resposta para mais detalhes. Eu testei no iOS 11.3 e funciona.
Amir Raminfar
3
Para reiterar, para qualquer pessoa lutando com iOS 11,3 abertura Safari, consulte resposta da @ AmirRaminfar aqui: stackoverflow.com/a/49604315/32055
Chris Haines

Respostas:

110

Encontrei a solução JavaScript no quadro do 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
fonte
25
Para declarar o óbvio e tornar isso explícito: o iOS trata os links nos aplicativos da Web como algo que deve ser aberto no Safari, e a localização do javascript muda como uma ação no aplicativo que pode ficar saturada no aplicativo da web. O código acima funciona porque impede o comportamento padrão do link, substituindo-o por uma chamada js nav.
Oskar Austegard 15/09
6
Existe um exemplo do oposto? Forçar um aplicativo da Web para iPhone a abrir uma página no Safari, mesmo que seja uma alteração de local em javascript?
tkahn
1
@Pavel obrigado por mencionar o iwebkit :). Ajuda a obter algum tráfego: D
cmplieger 23/03
3
[].forEach.call(document.links, function(link) { link.addEventListener("click", function(event) { event.preventDefault(); window.location = this.href; }) });
alex
1
Isso tem algum efeito colateral?
pingu
94

As outras soluções aqui não são responsáveis ​​por links externos (que você provavelmente deseja abrir externamente no Safari) ou por links relativos (sem o domínio neles).

O projeto html5 mobile-boilerplate está vinculado a essa essência, que tem uma boa discussão sobre o tópico: https://gist.github.com/1042026

Aqui está o código final que eles criaram:

<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
fonte
Isso funciona muito bem, exceto em uma página, a página "Entre em contato" da nossa empresa. Em vez de mostrar a página, ele abre o aplicativo "Mapas" e localiza nosso escritório. O que poderia estar causando isso e como podemos corrigi-lo?
Jonathan
@ Jonathan Eu não tenho certeza. Isso não acontece se você remover esse script? Talvez postar um link para o seu site? Ou abra uma nova pergunta, que pode ser melhor.
precisa saber é o seguinte
@rmarscher Isso acontece apenas ao executar o código que você forneceu e não sem ele. Sou desenvolvedor web e não entendo por que ele manipularia o link dessa maneira. Não tenho um URL de página, porque ele não está atualmente executando o código, portanto você não notará. Além disso, afeta também o Safari comum, e não apenas autônomo. Obrigado pela sua resposta!
31712 Jonathan
Essa deve ser a resposta aceita e funcionou muito bem no meu cliente de tela cheia do iPad1, feito com o PHPRunner, colocando o código no cabeçalho. Não sei por que ele é tão ofuscado, pois parece um pouco conciso de código que poderia ser escrito de maneira legível, sem muita sobrecarga de BW ... isso é apenas exigente e geralmente quer agradecer.
precisa saber é o seguinte
4
Este coisas breaks Bootstrappy tais como href = ligações "#" que são utilizados por funções js
Sean
47

Se você estiver usando o jQuery, poderá:

$("a").click(function (event) {
    event.preventDefault();
    window.location = $(this).attr("href");
});
David H.
fonte
1
Por favor, explique por que .live () pode ser melhor?
ajcw
8
ao vivo vai ligar o evento para todas as ligações, incluindo aqueles que não existe ainda, clique só irá ligar-se a aqueles que existem atualmente
msaspence
obrigado! salva-vidas. Passei horas tentando descobrir por que o safari estava carregando o tempo todo.
Steve
1
+1 de mim - usado em this.hrefvez de transmitir para um objeto jQuery, mas obrigado por esta resposta. Funciona no iOS6.
Fenton
17
.live () foi descontinuado a partir do jQuery 1.7 e removido a partir do 1.9 . Use $ (document) .on ('clique', 'a', function () {...}).
Tom Davies
21

Isso está funcionando para mim no iOS 6.1 e com links JS do Bootstrap (ou seja, menus suspensos 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
fonte
1
+1. Na verdade, isso verifica se você está usando um aplicativo da web antes de corrigir os links.
Trolley
1
Funciona no iOS 8.0.2! Obrigado
Joel Murphy
1
@sean Eu tenho outro webapp rodando em um iPad que está usando um mapa de imagem como href e esse código não funciona .. Funciona bem para todos os outros links. Alguma idéia de como fazer esse código funcionar com mapas de imagem? Eu tentei copiar todo o bloco e substituir $('a').on('click', function (e) {`por $('area').on('click', function (e) {` mas isso também não parece funcionar. Alguma ideia?
Nematoth
No caso de você já tem funções de clique definidos no acom href="#", então você pode ser mais específico sobre o seletor jQuery, por exemplo$('a[href!="#"]')
cjk
13

Esta é uma pergunta antiga e muitas das soluções aqui estão usando javascript. Desde então, o iOS 11.3 foi lançado e agora você pode usar o membro do escopo . O membro do escopo é uma URL como "/"onde todos os caminhos desse escopo não abrirão uma nova página.

O membro do escopo é uma sequência que representa o escopo de navegação do contexto de aplicativo desse aplicativo Web.

Aqui está o meu exemplo:

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

Você também pode ler mais sobre isso aqui . Eu também recomendo usar o gerador que fornecerá essa funcionalidade.

Se você especificar o escopo, tudo funcionará como esperado, semelhante ao Android, os destinos fora do escopo serão abertos no Safari - com um botão voltar (o pequeno na barra de status) no seu PWA.

Amir Raminfar
fonte
7
Infelizmente, não acredito que você possa incluir outros sites (como logons do OAuth em outro domínio) no escopo.
precisa saber é
Hey @Amir, eu criei um pwa usando Angular e no Android, recebo o 'Adicionar ao prompt da tela inicial', pois parece que ele está lendo meu manfest.json corretamente. No entanto, no IOs Chrome / Safari, nenhum prompt ... alguma idéia?
ustad
5

Com base na resposta de Davids e no comentário de Richards, você deve executar uma verificação de domínio. Caso contrário, os links para outros sites também serão abertos no seu aplicativo da web.

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

    if (href.indexOf(location.hostname) > -1)
    {
        event.preventDefault();
        window.location = href;
    }
});
Thomas Kekeisen
fonte
Boa adição às soluções acima. Necessário uma verificação de domínio para impedir que as pessoas abram sites externos no aplicativo. Além disso, funciona em iOS 5.
Ian
funciona no iOS 5 para mim também. Às vezes, o problema pode estar no cache. Ao testar diferentes abordagens, não consegui forçar o iOS a invalidar seu cache e recuperar a nova versão dos arquivos JS (o Safari capturou as alterações, mas não mais depois de adicionar o aplicativo à Tela inicial). Mudar a porta do meu servidor dev ajudou. Se você tiver um conjunto de idade máxima = 0 (ou equivalente), isso provavelmente não afetará você.
Lukasz Korzybski
5

Se estiver usando o jQuery Mobile, você experimentará a nova janela ao usar o atributo data-ajax = 'false'. De fato, isso acontecerá sempre que o ajaxEnabled for desativado, por um link externo, por uma configuração $ .mobile.ajaxEnabled ou por um atributo target = ''.

Você pode corrigi-lo usando este:

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

(Obrigado a Richard Poole pelo método live () - não estava trabalhando com bind ())

Se você desativou o ajaxEnabled globalmente, precisará remover o [data-ajax = 'false'].

Demorei um pouco para descobrir, pois esperava que fosse um problema específico do jQuery Mobile, onde na verdade era o link do Ajax que realmente proibia a nova janela.

Jason Prawn
fonte
Perfeito, você me salvou :)
saulob /
3

Este código funciona para o iOS 5 (funcionou para mim):

Na tag head:

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

No link que você deseja abrir na mesma janela:

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

Eu recebi esse código deste comentário: iphone web app meta tags

SerinEleven
fonte
Por alguma razão, acho que é o mais fácil de entender.
21416 Jerrybibo
3

Talvez você deva permitir abrir links em uma nova janela quando o destino também estiver explicitamente definido como "_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
fonte
Muito obrigado! Este é o único código que funcionou para iOS5 com Twitter Bootstrap. Porém, não funciona na produção.
Chim Kan
Mmm não tenho certeza por que não funcionaria na produção, mas acho que é outra coisa. Deixe-me saber!
Daformat
2

Você também pode vincular quase normalmente:

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

E você pode remover a tag hash e o href, tudo o que faz afeta a aparência.

JuR
fonte
2

Isto é o que funcionou para mim no iOS 6 (adaptação muito pequena da resposta do 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
fonte
2

Esta é uma versão ligeiramente adaptada do Sean, que estava impedindo o botão Voltar

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

Para aqueles com 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; 
  }   
});

Os links de exclusão ainda estão funcionando dessa maneira.

wouf
fonte
1

Prefiro abrir todos os links no modo de aplicativo da web independente, exceto os que têm target = "_ blank". Usando jQuery, é claro.

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

Uma solução alternativa que usei para um aplicativo da web para iOS foi que eu criei todos os links (que eram botões por CSS) nos botões de envio de formulário. Então, eu abri um formulário que foi postado no link de destino e digite type = "submit" Não é o melhor caminho, mas foi o que descobri antes de encontrar esta página.

dster77
fonte
1

Para aqueles que usam JQuery Mobile, as soluções acima quebram o diálogo pop-up. Isso manterá os links no webapp e permitirá pop-ups.

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

Também poderia fazê-lo por:

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

Aqui está o que eu usaria para todos os links em uma página ...

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

Se você estiver usando jQuery ou Zepto ...

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

Você pode simplesmente remover essa metatag.

<meta name="apple-mobile-web-app-capable" content="yes">
Soohwan Park
fonte