10

I have a Cordova app, it is a single page application with a single HTML file.

All links should open in the system browser. I don't want an "embedded" InAppBrowser but really the native system / external browser.

Everywhere we can find example of code using InAppBrowser with something like:

window.open('http://apache.org', '_system');

But why do we need to install InAppBrowser, even if we don't even plan to use an embedded browser?

Can someone really expain what is supposed to be the behavior of a WebView, regarding the target of a link. It is not clear what it is supposed to do with a target=_blank, but I don't see anything else it can do except opening a new browser window.

Notice that the problem seems to only be with iOS because with Android (with Crosswalk plugin) using target=_blank seems to always work fine and open in a new native browser window.

Sebastien Lorber
  • 89,644
  • 67
  • 288
  • 419
  • Well from my understanding you are always in a webview. Now you want to query the main system browser. Now the normal _target blank might not always work especially across all the platforms cordova supports. To get over this, we use the inappbrowser which goes through the native layer to call the browser. This way we can be guaranteed a working solution across all supported platforms. – Sani Yusuf Aug 26 '15 at 04:46
  • @SaniYusuf but then why not create a plugin that is just not an "InAppBrowserPlugin" and does open all links with _blank in system browser? I feel like the plugin is trying to solve 2 distinct problems, one of them not being clearly stated in the plugin's name (but not really sure as it's not really explained) – Sebastien Lorber Aug 26 '15 at 09:06
  • @jcesarmobile I did, and actually it made all Ajax requests fail on Android as far as I know. Also it is not documented here: https://github.com/apache/cordova-plugin-whitelist – Sebastien Lorber Aug 26 '15 at 10:37
  • @jcesarmobile Also you can see in the source code plugin that this option has only effect on Android native code, and is deprecated in favor of `allow-access` according to this warning log: `Found within config.xml. Please use instead.` – Sebastien Lorber Aug 26 '15 at 10:39
  • Sorry, didn't try it before commenting, I've tried now and you are right. The thing is, cordova is a framework for creating mobile apps, so, all the resources should be local and external links make no real sense (at least to me). In case you need them, then you have the inAppBrowser plugin, that allows you to open the links on the inAppBrowser or in the system browser. It's true that is a bit strange that you have to install an "inAppBrowser" plugin to launch an external browser, but you can create your own plugin to launch the browser without the inAppBrowser – jcesarmobile Aug 26 '15 at 11:04
  • @SebastienLorber as discussed with cordova you are always in a webview which is an instance of a browser. When you start fiddling around with target = _blank attribute in a normal browser, you are creating a new instance of a browser. In a webview you dont have this access as allowing user this much power can be catastrophic. For example if you link sometimes, it will replace your entire apps content and that is not ideal behavior. The In app browser makes sense for this and it also has th + of being cross platform and opening a new instance without replacing your current webview. – Sani Yusuf Aug 26 '15 at 12:43
  • @jcesarmobile loads of cordova developers have in the past struggled with this problem, so it seems to make sense to many to link to external websites with `_blank` target :) true I can create my own plugin (or suggest they split the plugin in 2). – Sebastien Lorber Aug 26 '15 at 13:18
  • @SaniYusuf I don't really understand why allowing the user so much power (opening an url in system browser) is catastrophic (user = developer you mean? Because it's the developer that choose to put the link with a `_blank` target not the app user...). I'm not talking at all about opening external links with `_self` target here: of course it is bad and makes page open in the app webview, not allowing the user to even go back to the app... – Sebastien Lorber Aug 26 '15 at 13:22
  • @SebastienLorber maybe I did not make you understand. When you are developing a Phonegap app, you are living within a webview which is like a cut down version of the browser. In order to have a one size fits all approach I am guessing the cordova guys decided to go through the native layer to do this. Even with th _blank in normal web apps, it still goes through this native layer behind the scenes I am guessing. With the approach, the one size fits all makes perfect sense with the plugin – Sani Yusuf Aug 27 '15 at 14:18

1 Answers1

12

So I'm answering my own question with what I've found out. Note I'm only dealing with iOS and Android (with Crosswalk plugin) on Cordova 5.1.1, and it may not apply to other platforms/versions.

InAppBrowser is required

Even if you don't need an embedded browser, InAppBrowser plugin is required. This makes the _system target available that triggers native plugin code to open the system/external browser.

So it seems the plugin is somehow a "2 in 1" plugin: it permits to use an embedded browser + it permits to securely force the external system browser to open.

It is not clear what the default WebView behavior should be relative to _blank links (nor if it is standardized in any way for WebViews) but I've found no way to open the external browser on iOS without this plugin or native code.

Opening _self in WebView, and _blank in native browser

If like me you don't care about the embedded browser, but just want to open all _blank targets to the native external browser in an existing app, without too much pain (particularly if the app is also a mobile website...), you can run the following code at the beginning of your app:

    function openAllLinksWithBlankTargetInSystemBrowser() {
        if ( typeof cordova === "undefined" || !cordova.InAppBrowser ) {
            throw new Error("You are trying to run this code for a non-cordova project, " +
                    "or did not install the cordova InAppBrowser plugin");
        }

        // Currently (for retrocompatibility reasons) the plugin automagically wrap window.open
        // We don't want the plugin to always be run: we want to call it explicitly when needed
        // See https://issues.apache.org/jira/browse/CB-9573
        delete window.open; // scary, but it just sets back to the default window.open behavior
        var windowOpen = window.open; // Yes it is not deleted !

        // Note it does not take a target!
        var systemOpen = function(url, options) {
            // Do not use window.open becaus the InAppBrowser open will not proxy window.open
            // in the future versions of the plugin (see doc) so it is safer to call InAppBrowser.open directly
            cordova.InAppBrowser.open(url,"_system",options);
        };


        // Handle direct calls like window.open("url","_blank")
        window.open = function(url,target,options) {
            if ( target == "_blank" ) systemOpen(url,options);
            else windowOpen(url,target,options);
        };

        // Handle html links like <a href="url" target="_blank">
        // See https://issues.apache.org/jira/browse/CB-6747
        $(document).on('click', 'a[target=_blank]', function(event) {
            event.preventDefault();
            systemOpen($(this).attr('href'));
        });
    }
Mansour Alnasser
  • 4,446
  • 5
  • 40
  • 51
Sebastien Lorber
  • 89,644
  • 67
  • 288
  • 419