hampusohlsson / browser-deeplink

Redirect mobile website users to your native iOS and/or Android app
MIT License
493 stars 173 forks source link

Doesn't work on iOS 9 #16

Closed sgtpepper43 closed 5 years ago

sgtpepper43 commented 8 years ago

Trying to open the link always fails on iOS 9, whether you have the app or not.

ohh2ahh commented 8 years ago

I can confirm that it doesn't work on iOS 9. Works fine on iOS 8.4.1.

It seems that the following doesn't get executed:

iframe.onload = function() {
  clearTimeout(timeout);
  iframe.parentNode.removeChild(iframe);
  window.location.href = uri;
};
stefangomez commented 8 years ago

iOS 9 added privacy features where apps can't navigate or "detect" apps installed --assuming this affected safari as well :/

having a link like <a href="deeplink://destination">link</a> works though.

sgtpepper43 commented 8 years ago

Even just assigning window.location works. It seems that after all the effort of introducing their new "Universal Links" thing that automatically checks if an app exists for links between different apps, they decided doing the same thing for Safari was not something they wanted to pursue... I guess.

shailendher commented 8 years ago

The below approach fixes this issue: https://github.com/mderazon/node-deeplink/issues/8 but creates new one: https://github.com/mderazon/node-deeplink/issues/9

omihailo commented 8 years ago

Can we expect fixing of this issue soon? The users are migrating to iOS 9 very fast, so we are already experiencing some issues with it. There are apps which really depends on the deeplink script.

lukasnagl commented 8 years ago

@omihailo As @sgtpepper43 already mentioned, Apple likely expects you to implement universal links (see the WWDC talk).

As long as your app is not an app launcher or something, implementing universal links is likely the way to go, since Apple seems to conceptually treat hitting Safari as the “no deeplink recognized” fallback. Differently stated: Safari conceptually doesn’t expect automatically triggered deeplinks, since universal links are recognized before the page is fully loaded in Safari.

kennyth01 commented 8 years ago

as @shailu highlighted, here's the quick fix for this issue: go to line 188 replace and use the snippet below:

var ua = window.navigator.userAgent;
        if (ua.match(/CriOS/) || (ua.match(/Safari/) && ua.match(/Version\/9/))) {
            //do another approach...
            document.location = uri;
        } else {
            var iframe = document.createElement("iframe");
            iframe.onload = function() {
                clearTimeout(timeout);
                iframe.parentNode.removeChild(iframe);
                window.location.href = uri;
            };
            iframe.src = uri;
            iframe.setAttribute("style", "display:none;");
            document.body.appendChild(iframe);
        }
andyvb commented 8 years ago

@kennyth01, unfortunately as @shailu mentioned, the workaround causes an error dialog to appear if the user doesn't have your app installed. Unfortunately that's a non-starter for us. The only real solution for us is to use Universal Links.

kennyth01 commented 8 years ago

@andyvb what do you mean by "error" dialog? I didn't saw any error dialog?

Edited: saw it already, disregard this post. But I think it should be okay to have that for as long as you combine deep-linking with a custom smart app banner.

andyvb commented 8 years ago

@kennyth01 It's in the ticket shailu linked to (https://github.com/mderazon/node-deeplink/issues/9). You see this dialog if you don't have the app installed: safari_canot_open_page

Edited: There's no way to absolutely prevent the user from seeing that dialog regardless whether you have a smart app banner. The slightly better UX is to trigger the script from some user interaction like when they tap a button on the web page like, "hey open the page in my app". The problem is they'll see the error dialog if you don't have the app installed. There is no workaround with pure Javascript to 100% prevent the error dialog.

The best UX that supports deep linking across iOS versions is:

  1. On iOS 8 and older, keep using this script.
  2. On iOS 9, implement Universal Links. Do not use document.location.
kopiro commented 8 years ago

The best solution I found is to:

location.href = DEEP_LINK
location.href = FALLBACK_LINK

With this solution, if the app is not installed, an error dialog is thrown, but after clicking OK another dialog appear with the question "Open App store?".


I print also a small HTML with a link to the fallback, in the case the user clicks "Cancel" of the dialogs.

mderazon commented 8 years ago

ios 9.2 has made things worse. see this blog post

shailendher commented 8 years ago

From the link:

"What changed in iOS 9.2?

Apple changed the 'Open App' modal from a blocking modal to a non blocking modal. When you try to >open up the app, the modal will no longer block Javascript from executing, meaning that the fallback >redirect to the App Store will execute immediately before the user can click 'Open App'."

Wasn't this the case even in ios 9.0?

leonyu commented 8 years ago

In iOS 9.0, setting a new URL after the "non-blocking modal" cause the dialog box to be dismissed as if user clicked "Open", which is useful behavior.

In 9.1, the app launch dialog box is blocking, while the error dialog box is non-blocking.

In 9.2, both dialog boxes are non-block. Also setting a new URL causes dialog box to be dismissed as if user clicked "Cancel", which is does not help the cause.

robindra commented 8 years ago

@kopiro: Is there any way to detect user click on cancel button in the popup so that we can directly redirect to the fallback url without printing the small html page.

kopiro commented 8 years ago

I think you cant, it's an OS dialog you can't just control.

leonyu commented 8 years ago

For user action, you can guess using requestAnimationFrame. Due to the fact that both dialog box and app switching takes up more GPU than scrolling a page, the timing difference between successive requestAnimationFrame could be used to differentiate various user actions. It is fairly complicated and requires benchmarking to get any meaningful result, so it is not worthwhile for most uses, since you can't use it to tell if app is installed or not.

Also there is slight difference in window.open('customURL://blah') on 9.2 between having the app and not having the app. If the app exists, the popup would close automatically when user cancel, if the app doesn't exist, the popup would stay. This may be used to detect if user has the app installed if we preemptively open and close a pop-up. However, given the horrid user experience that would entail, I didn't bother investigating further. No clue if it is still the case in 9.3 or 10.

albandaft commented 7 years ago

@leonyu this could be a nice hack (but apple is annoying with this changes....)

sgtpepper43 commented 5 years ago

I'm closing this because it's been three years and I don't want to see this in my issues list anymore :grin: Plus as of b0bd1cf5bcb7e220fc02c3174b54589e49ef5e67 this project is no longer maintained.