Aplikasi Web Safari iPhone membuka tautan di jendela baru

155

Saya memiliki masalah dengan web setelah menambahkan ikon ke Layar Utama. Jika web diluncurkan dari Layar Utama, semua tautan akan terbuka di jendela baru di Safari (dan kehilangan fungsionalitas layar penuh). Bagaimana saya bisa mencegahnya? Saya tidak dapat menemukan bantuan, hanya pertanyaan yang sama yang belum terjawab.

Pavel Linkesch
sumber
3
Anda sekarang dapat menggunakan scopeparameter dalam manifest.json. Lihat jawaban saya untuk lebih jelasnya. Saya telah mengujinya di iOS 11.3 dan tidak berfungsi.
Amir Raminfar
3
Untuk menegaskan kembali, bagi siapa saja yang berjuang dengan iOS 11.3 membuka Safari, silakan lihat jawaban @ AmirRaminfar di sini: stackoverflow.com/a/49604315/32055
Chris Haines

Jawaban:

110

Saya menemukan solusi JavaScript dalam kerangka kerja 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
sumber
25
Untuk menyatakan yang jelas dan membuat ini eksplisit: iOS memperlakukan tautan di Aplikasi Web sebagai sesuatu yang harus dibuka di Safari, dan lokasi javascript berubah sebagai tindakan dalam aplikasi yang diizinkan untuk disimpan di aplikasi web. Kode di atas berfungsi karena mencegah perilaku tautan default, menggantikannya dengan panggilan js nav.
Oskar Austegard
6
Apakah ada contoh yang sebaliknya? Memaksa aplikasi web iPhone untuk membuka halaman di Safari walaupun itu perubahan lokasi javascript?
tkahn
1
@Pavel terima kasih telah menyebutkan iwebkit :). Membantu mendapatkan lalu lintas: D
cmplieger
3
[].forEach.call(document.links, function(link) { link.addEventListener("click", function(event) { event.preventDefault(); window.location = this.href; }) });
alex
1
Apakah ini memiliki efek samping?
pingu
94

Solusi lain di sini tidak memperhitungkan tautan eksternal (yang mungkin ingin Anda buka secara eksternal di Safari) atau tidak memperhitungkan tautan relatif (tanpa domain di dalamnya).

Proyek html5 mobile-boilerplate menautkan ke inti ini yang memiliki diskusi yang bagus tentang topik ini: https://gist.github.com/1042026

Inilah kode terakhir yang mereka buat:

<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
sumber
Ini berfungsi baik kecuali untuk satu halaman, halaman "Hubungi kami" untuk perusahaan kami. Alih-alih menunjukkan halaman, itu membuka aplikasi "Peta" dan menunjukkan kantor kami. Apa yang menyebabkan hal ini, dan bagaimana cara memperbaikinya?
Jonathan
@ Jonathan, aku tidak yakin. Apakah itu tidak terjadi jika Anda menghapus skrip ini? Mungkin memposting tautan ke situs Anda? Atau buka pertanyaan baru, itu mungkin lebih baik.
rmarscher
@rmarscher Ini hanya terjadi ketika menjalankan kode yang Anda berikan dan bukan tanpa itu. Saya sendiri seorang pengembang web dan saya tidak mengerti mengapa ini akan menangani tautan dengan cara ini. Saya tidak memiliki URL halaman karena saat ini tidak menjalankan kode sehingga Anda tidak akan menyadarinya. Juga, itu mempengaruhi Safari biasa juga, dan tidak hanya mandiri. Terima kasih atas jawaban anda!
Jonathan
Ini harus menjadi jawaban yang diterima dan bekerja dengan sangat baik pada klien layar penuh iPad1 saya yang dibuat dengan PHPRunner dengan menempatkan kode di header. Tidak yakin mengapa itu begitu dikaburkan karena tampaknya sedikit kode yang dapat ditulis dengan jelas tanpa banyak overhead BW ... Itu hanya pemilih meskipun dan umumnya benar-benar ingin mengucapkan terima kasih.
sradforth
4
Ini memecah hal-hal Bootstrappy seperti tautan href = "#" yang digunakan oleh fungsi js
Sean
47

Jika Anda menggunakan jQuery, Anda dapat melakukan:

$("a").click(function (event) {
    event.preventDefault();
    window.location = $(this).attr("href");
});
David H.
sumber
1
Tolong jelaskan mengapa .live () mungkin lebih baik?
ajcw
8
live akan mengikat acara ke semua tautan termasuk yang belum ada, klik hanya akan mengikat yang saat ini ada
msaspence
Terima kasih! penyelamat. Saya hanya menghabiskan waktu berjam-jam untuk mencari tahu mengapa safari memuat semua waktu.
Steve
1
+1 dari saya - digunakan this.hrefdaripada casting ke objek jQuery, tapi terima kasih atas jawaban ini. Bekerja di iOS6.
Fenton
17
.live () tidak digunakan lagi pada jQuery 1.7 , dan dihapus pada 1.9 . Gunakan $ (dokumen) .pada ('klik', 'a', fungsi () {...}) sebagai gantinya.
Tom Davies
21

Ini berfungsi untuk saya di iOS 6.1 dan dengan tautan Bootstrap JS (mis. Menu dropdown dll)

$(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
sumber
1
+1. Ini sebenarnya memeriksa apakah Anda menggunakan webapp sebelum memperbaiki tautan.
Trolley
1
Bekerja di iOS 8.0.2! Terima kasih
Joel Murphy
1
@sean Saya punya webapp lain yang berjalan di iPad yang menggunakan peta gambar sebagai href dan kode ini tidak berfungsi .. Ini berfungsi dengan baik untuk semua tautan lainnya. Ada ide bagaimana membuat kode ini berfungsi dengan peta gambar? Saya telah mencoba menyalin seluruh chunk dan mengganti $('a').on('click', function (e) {`with $('area').on('click', function (e) {` tetapi itu sepertinya tidak berhasil juga. Ada ide?
nematoth
Jika Anda sudah memiliki fungsi klik yang ditentukan adengan href="#"maka Anda dapat lebih spesifik pada pemilih jquery, misalnya$('a[href!="#"]')
cjk
13

Ini adalah pertanyaan lama dan banyak solusi di sini menggunakan javascript. Sejak itu, iOS 11.3 telah dirilis dan sekarang Anda dapat menggunakan anggota lingkup . Anggota lingkup adalah URL seperti di "/"mana semua jalur di bawah lingkup itu tidak akan membuka halaman baru.

Anggota lingkup adalah string yang mewakili cakupan navigasi dari konteks aplikasi aplikasi web ini.

Ini contoh saya:

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

Anda juga dapat membaca lebih lanjut di sini . Saya juga merekomendasikan menggunakan generator yang akan menyediakan fungsionalitas ini.

Jika Anda menentukan cakupan, semuanya berfungsi seperti yang diharapkan mirip dengan Android, tujuan di luar cakupan akan terbuka di Safari - dengan tombol kembali (yang kecil di bilah status) ke PWA Anda.

Amir Raminfar
sumber
7
Sayangnya, saya tidak percaya bahwa Anda dapat memasukkan situs web lain (seperti login OAuth di domain lain) dalam ruang lingkup.
bhollis
Hei @Amir, saya telah membuat pwa menggunakan Angular dan di Android, saya mendapatkan 'Tambahkan ke layar awal' karena sepertinya membaca manfest.json saya dengan benar. Namun, di IOs Chrome / Safari, tidak ada prompt ... ada ide?
ustad
5

Berdasarkan jawaban Davids dan komentar Richards, Anda harus melakukan pemeriksaan domain. Jika tidak, tautan ke situs web lain juga akan dibuka di aplikasi web Anda.

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

    if (href.indexOf(location.hostname) > -1)
    {
        event.preventDefault();
        window.location = href;
    }
});
Thomas Kekeisen
sumber
Tambahan yang bagus untuk solusi di atas. Diperlukan pemeriksaan domain untuk mencegah orang membuka situs di luar di aplikasi. Juga berfungsi di iOS 5.
Ian
bekerja di iOS 5 untuk saya juga. Masalahnya kadang-kadang mungkin dengan cache. Saat menguji berbagai pendekatan saya tidak dapat memaksa iOS untuk membatalkan cache dan mengambil versi baru file JS (Safari memang mengambil perubahan tetapi tidak lebih setelah menambahkan aplikasi ke Layar Beranda). Mengubah port server dev saya membantu. Jika Anda memiliki usia maksimum = 0 set (atau setara) maka ini mungkin tidak akan memengaruhi Anda.
Lukasz Korzybski
5

Jika menggunakan jQuery Mobile Anda akan mengalami jendela baru saat menggunakan atribut data-ajax = 'false'. Bahkan, ini akan terjadi setiap kali ajaxEnabled dimatikan, sedang oleh dan tautan eksternal, oleh pengaturan $ .mobile.ajaxEnabled atau dengan memiliki atribut target = ''.

Anda dapat memperbaikinya menggunakan ini:

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

(Terima kasih kepada Richard Poole untuk metode live () - tidak bekerja dengan bind ())

Jika Anda telah mematikan ajaxEnabled secara global, Anda harus melepaskan [data-ajax = 'false'].

Ini butuh waktu agak lama bagi saya untuk mencari tahu karena saya mengharapkannya menjadi masalah khusus jQuery Mobile di mana sebenarnya itu adalah tautan Ajax yang sebenarnya melarang jendela baru.

Jason Prawn
sumber
Sempurna, Anda menyelamatkan saya :)
saulob
3

Kode ini berfungsi untuk iOS 5 (berfungsi untuk saya):

Di tag kepala:

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

Di tautan yang ingin Anda buka di jendela yang sama:

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

Saya mendapat kode ini dari komentar ini: tag meta aplikasi web iphone

SerinEleven
sumber
Untuk beberapa alasan saya pikir ini adalah yang paling mudah untuk dipahami.
Jerrybibo
3

Mungkin Anda harus mengizinkan untuk membuka tautan di jendela baru ketika target secara eksplisit diatur ke "_blank" juga:

$('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
sumber
Terima kasih banyak! Ini adalah satu-satunya kode yang berfungsi untuk iOS5 dengan Twitter Bootstrap. Itu tidak bekerja pada produksi sekalipun.
Chim Kan
Mmm tidak begitu yakin mengapa itu tidak akan berhasil dalam produksi tetapi saya pikir itu sesuatu yang lain. Biarkan saya tahu!
daformat
2

Anda juga dapat melakukan penautan hampir secara normal:

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

Dan Anda dapat menghapus tag hash dan href, semua yang dilakukannya mempengaruhi penampilan ..

JuR
sumber
2

Inilah yang bekerja untuk saya di iOS 6 (adaptasi yang sangat sedikit dari jawaban 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
sumber
2

Ini adalah versi Sean yang sedikit diadaptasi yang mencegah tombol kembali

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

Bagi mereka dengan Twitter Bootstrap dan Rails 3

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

Hapus tautan masih bekerja dengan cara ini.

wouf
sumber
1

Saya lebih suka membuka semua tautan di dalam mode aplikasi web mandiri kecuali yang memiliki target = "_ blank". Menggunakan jQuery, tentu saja.

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

Satu solusi yang saya gunakan untuk aplikasi web iOS adalah bahwa saya membuat semua tautan (yang merupakan tombol oleh CSS) dari tombol kirim. Jadi saya membuka formulir yang diposting ke tautan tujuan, lalu input type = "submit" Bukan cara terbaik, tapi itulah yang saya temukan sebelum saya menemukan halaman ini.

dster77
sumber
1

Bagi yang menggunakan JQuery Mobile, solusi di atas memecah dialog popup. Ini akan menjaga tautan di dalam webapp dan memungkinkan popup.

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

Bisa juga dengan:

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

Inilah yang akan saya gunakan untuk semua tautan di halaman ...

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

Jika Anda menggunakan jQuery atau Zepto ...

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

Anda cukup menghapus tag meta ini.

<meta name="apple-mobile-web-app-capable" content="yes">
Taman Soohwan
sumber