iPhone Safari Web App opens links in new window
Asked Answered
Z

20

157

I have problem with web after adding icon to Home Screen. If the web is launched from Home Screen, all links will open in new window in Safari (and lose full screen functionality). How can I prevent it? I couldn't find any help, only the same unanswered question.

Zloty answered 24/5, 2010 at 17:5 Comment(2)
You can now use the scope parameter in manifest.json. See my answer for more details. I have tested it in iOS 11.3 and it does work.Jehial
To reiterate, for anyone struggling with iOS 11.3 opening Safari, please see @AmirRaminfar's answer here: https://mcmap.net/q/150948/-iphone-safari-web-app-opens-links-in-new-windowGiron
Z
111

I found JavaScript solution in iWebKit framework:

var a=document.getElementsByTagName("a");
for(var i=0;i<a.length;i++)
{
    a[i].onclick=function()
    {
        window.location=this.getAttribute("href");
        return false
    }
}
Zloty answered 24/5, 2010 at 18:0 Comment(8)
To state the obvious and make this explicit: iOS treats links in Web Apps as something that should be opened in Safari, and javascript location changes as an in-app action that is allowed to saty in the web-app. The code above works because it prevents the default link behavior, replacing it with a js nav call.Antilogarithm
Is there an example of the opposite? Forcing an iPhone web app to open a page in Safari eventhough it's a javascript location change?Wifehood
@Pavel thank you for mentioning iwebkit :). Helps to get some traffic :DInflationism
I found this script didn't work for iOS5. This solution did work though: https://mcmap.net/q/150948/-iphone-safari-web-app-opens-links-in-new-windowCasebound
If you're doing javascript-y things and have href="#", you might want the following modification if this script is breaking their functionality: thunked.org/p/view/pub/uccr0k3srMesquite
[].forEach.call(document.links, function(link) { link.addEventListener("click", function(event) { event.preventDefault(); window.location = this.href; }) });Militarism
Does this have any side effects?Dunigan
@Pavel Linkesch May I know how should run the above code once user click on a hyperlink ?Chaplet
H
96

The other solutions here either don't account for external links (that you probably want to open externally in Safari) or don't account for relative links (without the domain in them).

The html5 mobile-boilerplate project links to this gist which has a good discussion on the topic: https://gist.github.com/1042026

Here's the final code they came up with:

<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>
Hittite answered 17/11, 2011 at 19:34 Comment(7)
This works great except for one page, the "Contact us" page for our company. Instead of showing the page, it opens the application "Maps" and pinpoints our office. What could be causing this, and how can we fix it?Piperpiperaceous
@Piperpiperaceous I'm not sure. Does it not happen if you remove this script? Maybe post a link to your site? Or open a new question, that might be better.Hittite
@Hittite This only happens when running the code you provided and not without it. I'm a web developer myself and I don't understand why it would handle the link this way. I don't have a page URL because it's currently not running the code so you won't notice it. Also, it affects the regular Safari as well, and not only standalone. Thanks for your answer!Piperpiperaceous
This should be the accepted answer and worked a charm on my iPad1 fullscreen client made with PHPRunner by placing the code in the header. Not sure why it's so obfuscated as it seems quite concise bit of code that could be written legibly without much BW overhead... that's just being picky though and generally really want to say thanks.Allanite
This breaks Bootstrappy things such as href="#" links that are used by js functionsLw
Luckily my workmate had some code lying around. i will add an answerLw
This works perfectly if you use it like this. If I tried to include this code from a js file it did not worked anymore. (just wanted to tell everybody no to do this because i waisted a lot of time finding out this)Ravenravening
M
47

If you are using jQuery, you can do:

$("a").click(function (event) {
    event.preventDefault();
    window.location = $(this).attr("href");
});
Mudra answered 1/4, 2011 at 4:45 Comment(6)
Please explain why .live() might be better?Ex
live will bind the event to all links including those that don't exist yet, click will only bind to ones that currently existTibbitts
thanks! lifesaver. I just spent hours trying to figure out why safari was loading all the time.Lineman
For Rails 3.1 apps, this seems to break traditional delete links and redirects them to the show action instead.Carlyncarlynn
+1 from me - used this.href rather than casting to a jQuery object, but thanks for this answer. Works on iOS6.Apocarp
.live() is deprecated as of jQuery 1.7, and removed as of 1.9. Use $(document).on('click', 'a', function(){...}) instead.Abvolt
L
21

This is working for me on iOS 6.1 and with Bootstrap JS links (i.e dropdown menus 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;
        }
      });
    }
  });
Lw answered 8/2, 2013 at 3:18 Comment(3)
+1. This actually checks whether you're using a webapp before fixing the links.Redwood
@sean I have another webapp running in an iPad which is using an image map as href and this code doesn't work..It works fine for all other links. Any ideas how to make this code work with image maps? I have tried copying the whole chunk and replacing $('a').on('click', function(e){` with $('area').on('click', function(e){` but that doesn't seem to work either. Any ideas?Benignity
In case you already have click functions defined on a with href="#" then you can be more specific on the jquery selector, e.g. $('a[href!="#"]')Rabblement
J
20

This is an old question and many of the solutions here are using javascript. Since then, iOS 11.3 has been released and you can now use the scope member. The scope member is a URL like "/" where all paths under that scope will not open a new page.

The scope member is a string that represents the navigation scope of this web application's application context.

Here is my example:

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

You can also read more about it here. I also recommend using the generator which will provide this functionality.

If you specify the scope, everything works as expected similar to Android, destinations out of the scope will open in Safari — with a back button (the small one in the status bar) to your PWA.

Jehial answered 2/4, 2018 at 1:40 Comment(1)
Unfortunately, I don't believe that you can include other websites (such as OAuth logins on another domain) in the scope.Senile
K
5

Based on Davids answer and Richards comment, you should perform a domain check. Otherwise links to other websites will also opened in your web app.

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

    if (href.indexOf(location.hostname) > -1)
    {
        event.preventDefault();
        window.location = href;
    }
});
Kele answered 24/10, 2011 at 9:53 Comment(2)
Good addition to the above solutions. Needed a domain check to keep people from opening outside sites in the app. Also, works on iOS 5.Misjoinder
works on iOS 5 for me too. The problem sometimes might be with the cache. While testing different approaches I was unable to force iOS to invalidate its cache and retrieve new version of JS files (Safari did pick up the changes but no more after adding app to Home Screen). Changing port of my dev server helped. If you have max-age=0 set (or equivalent) then this probably won't affect you.Coloquintida
M
5

If using jQuery Mobile you will experience the new window when using the data-ajax='false' attribute. In fact, this will happen whenever ajaxEnabled is turned off, being by and external link, by a $.mobile.ajaxEnabled setting or by having a target='' attribute.

You may fix it using this:

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

(Thanks to Richard Poole for the live() method - wasn't working with bind())

If you've turned ajaxEnabled off globally, you will need to drop the [data-ajax='false'].

This took me rather long to figure out as I was expecting it to be a jQuery Mobile specific problem where in fact it was the Ajax linking that actually prohibited the new window.

Moncrief answered 7/8, 2012 at 12:23 Comment(0)
D
3

This code works for iOS 5 (it worked for me):

In the head tag:

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

In the link that you want to be opened in the same window:

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

I got this code from this comment: iphone web app meta tags

Diandre answered 7/4, 2012 at 14:25 Comment(1)
For some reason I think this is the easiest to comprehend.Fruity
B
3

Maybe you should allow to open links in new window when target is explicitly set to "_blank" as well :

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

});
Boman answered 26/4, 2012 at 9:39 Comment(2)
Thanks a lot! This is the only code that worked for iOS5 w/ Twitter Bootstrap. It doesn't work on production though.Edmead
Mmm not so sure why it would not work in production but I think it's something else. Do let me know!Boman
I
3

I've found one that is very complete and efficient because it checks to be running only under standalone WebApp, works without jQuery and is also straightforward, just tested under iOS 8.2 :

Stay Standalone: Prevent links in standalone web apps opening Mobile Safari

Issacissachar answered 14/7, 2015 at 1:13 Comment(0)
H
2

You can also do linking almost normally:

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

And you can remove the hash tag and href, everything it does it affects appearance..

Highlands answered 29/10, 2012 at 12:5 Comment(0)
R
2

This is what worked for me on iOS 6 (very slight adaptation of rmarscher's answer):

<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>
Rockwell answered 1/8, 2013 at 21:1 Comment(0)
F
2

This is slightly adapted version of Sean's which was preventing back button

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

});

Foetation answered 23/1, 2014 at 15:2 Comment(0)
O
1

For those with Twitter Bootstrap and Rails 3

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

Delete links are still working this way.

Outpost answered 10/1, 2013 at 22:42 Comment(0)
A
1

I prefer to open all links inside the standalone web app mode except ones that have target="_blank". Using jQuery, of course.

$(document).on('click', 'a', function(e) {
    if ($(this).attr('target') !== '_blank') {
        e.preventDefault();
        window.location = $(this).attr('href');
    }
});
Acre answered 4/8, 2013 at 0:39 Comment(0)
P
1

One workaround i used for an iOS web app was that I made all links (which were buttons by CSS) form submit buttons. So I opened a form which posted to the destination link, then input type="submit" Not the best way, but it's what I figured out before I found this page.

Paresis answered 11/5, 2014 at 18:22 Comment(0)
O
1

I created a bower installable package out of @rmarscher's answer which can be found here:

http://github.com/stylr/iosweblinks

You can easily install the snippet with bower using bower install --save iosweblinks

Oslo answered 21/10, 2014 at 15:56 Comment(0)
M
1

For those using JQuery Mobile, the above solutions break popup dialog. This will keep links within webapp and allow for popups.

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

Could also do it by:

$(document).on('click','a', function (event){
    if($(this).attr('data-rel') == 'popup'){
        return true;
    }
    event.preventDefault();
    window.location = $(this).attr('href');     
});
Milomilon answered 7/4, 2016 at 14:56 Comment(0)
M
0

Here is what I'd use for all links on a page...

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

If you're using jQuery or Zepto...

$("body").on("click", "a", function(event) {
   event.target.target != "_blank" && (window.location = event.target.href);
});
Militarism answered 13/6, 2012 at 7:54 Comment(0)
F
-3

You can simply remove this meta tag.

<meta name="apple-mobile-web-app-capable" content="yes">
Figure answered 29/8, 2018 at 9:41 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.