iOS9: Try to open app via scheme if possible, or redirect to app store otherwise
Asked Answered
U

6

39

My question is about iOS9 only!

I have an HTML landing page, and I try to redirect the user to my app via URL scheme if the app is installed, or redirect to the Appstore otherwise.

My code is:

document.addEventListener("DOMContentLoaded", function(event) {

  var body = document.getElementsByTagName('body')[0];
  body.onclick = function () {
    openApp();
  };
});

var timeout;

function preventPopup() {

    clearTimeout(timeout);
    timeout = null;
    window.removeEventListener('pagehide', preventPopup);
}

function openApp(appInstanceId, platform) {

  window.addEventListener('pagehide', preventPopup);
  document.addEventListener('pagehide', preventPopup);

  // create iframe
  var iframe = document.createElement("iframe");
  document.body.appendChild(iframe);
  iframe.setAttribute("style", "display:none;");
  iframe.src = 'myscheme://launch?var=val';

  var timeoutTime = 1000;
  timeout = setTimeout(function () {

    document.location = 'https://itunes.apple.com/app/my-app';

  }, timeoutTime);
}

The problem is that the iframe trick doesn't work in Safari iOS9.

Any idea why?

My iframe trick based on this answer.

Unbearable answered 21/9, 2015 at 7:22 Comment(10)
the openApp redirect to safari or notRowenarowland
@Rowenarowland What do u mean?Unbearable
sorry , in your condition redirect to safari or notRowenarowland
But I want to switch app if possible (and don't show any alert if it's impossible) or redirect to app store. I don't want to redirect any way..Unbearable
friend , I don't know javascript, but I worked on URL schema on more than three apps in iOS, I surely support you to find the solution ,Rowenarowland
Friend, Thanks for your help, and same thanks to your support. I asked about JavaScript+Safari+iOS+URLScheme not only about iOS and not only about URLSchemeUnbearable
@Unbearable have you tested it removing display:none? Maybe Safari on iOS9 doesn't open url/iframe not displayed...Conal
@LuigiSaggese Yes, same problem :/Unbearable
@Unbearable i have same issue! Some websites made it with 2-3 redirect (i.e. LinkedIn). I don't like st.derrick solution, but maybe replacing redirect to store with a redirect to another, or same page skipping uri-scheme launch, could be a solution. What do you think?Conal
@LuigiSaggese I think we can't run away from the big brother (He'll keep watching us..), and we must use Universal Links by AppleUnbearable
V
23

The iframe trick no longer works -- my guess is that Apple knows it will encourage more developers to implement Universal Links, more quickly.

You can still set window.location='your-uri-scheme://'; and fallback to the App Store after 500ms. There is a "dance" between popups if you take this approach, as we do at Branch (we do as a fallback if Universal Links don't work).

window.location = 'your-uri-scheme://'; // will result in error message if app not installed
setTimeout(function() {
   // Link to the App Store should go here -- only fires if deep link fails                
   window.location = "https://itunes.apple.com/us/app/myapp/id123456789?ls=1&mt=8";
}, 500);

I wish I had a better answer for you. iOS 9 is definitely more limited.

For a helpful overview of what's needed for Universal Links should you go that route, check out my answer here or read this tutorial

Viperish answered 25/9, 2015 at 4:13 Comment(8)
@formatjam yes, if the app is not installed. It's unfortunate.Viperish
When the location change and the fallback timer are invoked from a user interaction event (e.g. an onclick handler on a button), as opposed to running e.g. onload, the location change in the timer always executes and the user always ends up being bumped to the app store. It looks like in this interactive scenario, the "Open this page in 'appname'" popup dialog that gets shown as a result of the first window.location assignment doesn't prevent further location changes from happening. Also, it appears the timeout can be as low as 1ms, I didn't see any diff between 500 and 1, Chrome included.Faunia
Further to my comment above, to ensure the flow works as expected even in the interactive scenario, you will need to 'create indirection' by wrapping the entire thing (i.e. incl. the first window.location assignment) in another timeout. E.g.: setTimeout(function () {window.location = 'your-uri-scheme://'; setTimeout(function () { window.location = 'itunes.apple.com/us/app/myapp/id123456789?ls=1&mt=8' }, 1); }, 1);Faunia
@Faunia I don't see how wrapping it in another timeout help. Im my case it didn't.Outspan
This doesn't seem to be working for me - it will show the "Open in app myapp?" dialog for a second and then it will redirect to my fallback url in the setTimeout method. Any idea as to why?Uncovered
Has anyone figured this out?Uncovered
@tommy.bonderenka Looks like a 9.2 thing where the "Open this page" dialog is no longer modal, so the redirect is not prevented.Dorren
on iOS versions >12.3, after opening the App from Safari it redirects to App Store in a split second.Cheapjack
F
3

As already mentioned setting window.location on iOS 9 still works. However, this brings up an Open in App dialog. I've put an example on https://bartt.me/openapp that:

  1. Launches Twitter when the Open in Twitter app is clicked.
  2. Falls back to the Twitter app in the App Store.
  3. Redirects to Twitter or the App Store without the user selecting Open in the Open in App dialog.
  4. Works in all browsers on iOS and Android.

Look at the source of https://lab.bartt.me/openapp for more information.

Fourdrinier answered 6/10, 2015 at 1:30 Comment(6)
It does again, was temporarily turned off.Fourdrinier
Re point 3, I tested in iOS 9.3.5, and it doesn't appear to be able to open Twitter without the user clicking open in the "Open" button in the "Open this page in 'Twitter'" dialog.Imhoff
+1 Does it work in iOS 9 without the "Open in app" dialog? Thanks for sharing. May you please add your code to the post to be in compliance with Stack Overflow rules.Qualifier
@BartTeeuwisse can you please provide the code? The linked page results in a 404. Thanks!Roundhead
@der_gluateng I've updated the link to the source code.Fourdrinier
This doesn't seem to work in the iOS Safari browser (anymore?). When user doesn't have Twitter installed on iOS 13 and taps the button, you get the generic 'Safari cannot open this page because it's invalid' alert.Volz
C
3

Answering this since it's 2023 now and some changes have happened. This suggestion is generally correct however there is a major issue: the app store will still open even if does successfully open the app.

The way to get around this is to detect when the first popup happens by monitoring the window blur event. If the blur occurs then don't perform the fallback because the user has successfully opened the app. But if the app is focused then perform the app store fallback.

You also need to use the hidden app store deep link itms-appss://....

var isBlurred = false;
var didFallback = false;

window.addEventListener('blur', function() {
  isBlurred = true;
});

window.addEventListener('focus', function() {
  isBlurred = false;
  appStoreFallback();
});

function appStoreFallback() {
  if (isBlurred || didFallback) return;

  // Since we are using the native deep link, we wrap it in a custom
  // confirm prompt to prevent it from opening immediately.
  if (window.confirm(`Open in "App Store"?`)) {
    window.top.location = "itms-appss://apps.apple.com/app/idYOUR_ID_HERE";
  }
  
  didFallback = true;
}

window.top.location = 'your-uri-scheme://'; 
setTimeout(function() {
  appStoreFallback();
}, 500);

As an aside, this is basically what Branch.io does under the hood and wanted to share. I've used them for a couple of years but now but stopped since their URLs get marked by spam filters and their costs are high if your app has any moderate amount of usage.

Caelum answered 13/12, 2023 at 18:48 Comment(1)
Thanks! the solution works fine also for Android and Windows PWA. As a simple alternative you could also use clearTimeout in the blur event callback.Vehicle
F
1

Maybe try giving you app support to Universal Links

Idea: Avoid custom (JavaScript, iframe) solutions in Safari, replace you code with a supported Universal Link.

Example

<html>
<head>
...
</head>
<body>
    <div class"app-banner-style">
        <a href="http://yourdomain.com">In app open</a> 
    </div>
...content
</body>
</html>

if you app support Universal Links (e.g. yourdomain.com), you muss configure your domain (and path) and iOS9 should be react to it link opening you App. That is only theory, but I guess should be work :)

https://developer.apple.com/library/prerelease/ios/documentation/General/Conceptual/AppSearch/UniversalLinks.html#//apple_ref/doc/uid/TP40016308-CH12

Fibrilliform answered 24/9, 2015 at 10:28 Comment(3)
@Fibrilliform that is a good way to approach to problem, but question refer to javascript, iframe, SafariConal
This should be the correct answer @Fibrilliform ... the only problem is the universal links binding is way too complex. But you were right. I up-scored you.Solitta
but it does not open appstore if the app is not installedPopelka
G
0

iframe hack doesn't work in ios9 anymore. Possible solution is use two buttons. Example:

$('#goToStoreBtn').text( "go to store" ).click(function(event){
    event.preventDefault();
    event.stopPropagation();
    window.location = storeUrl; // https://itunes.apple.com/...
});

$('#goToAppBtn').text( "go to app" ).click(function(event){
    event.preventDefault();
    event.stopPropagation();
    window.location = appUrl;  // myApp://...
});
Gerbil answered 25/9, 2015 at 8:35 Comment(0)
D
-1

This is relatively old thread, but I have created a library that supports deeplinking on most of the modern mobile browsers. But this requires separate deeplinking page which needs to be hosted in different domain to support universal linking in ios9 facebook browser.

https://github.com/prabeengiri/DeepLinkingToNativeApp

Daves answered 5/12, 2016 at 20:58 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.