Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I gracefully interrupt loading of a certain URL in Cordova's InAppBrowser and open it in the system browser?

I am using Cordova's inappbrowser plugin to display web parts in my app. On the website, there are sharing links, e.g. for WhatsApp:

<a href="whatsapp://send?text=Check this out">Share on WhatsApp</a>

Now when clicking these links in inappbrowser, it simply tries to load whatsapp://send?... as a URL and displays an error page.

What I want to do instead is open links that start with whatsapp:// using the given system's browser/URI handler so it resembles the behavior when clicking such link in the system's browser. To do that, I did the following:

urlChanged = function(event) {
    // when a "whatsapp://" link is clicked, open it in the system browser
    if(event.url.startsWith("whatsapp://")) {
        window.open(event.url, "_system");
        return;
    } 
}
// Add an "loadstart" event listener to the inappbrowser:    
browser.addEventListener("loadstart", urlChanged);

So far, this somewhat works, but with quirks:

  1. While the event immediately fires when the user clicks a WhatsApp link (checked that by firing an alert), it takes like two or three seconds for the system browser to actually open.
  2. While waiting these 2-3 seconds and when returning to the app, the user sees an inappbrowser error page that the whatsapp:// link could not be opened ("unknown url scheme").

To mitigate point 2, I also tried the following in the event listener, without success (the behavior is exactly the same):

urlChanged = function(event) {
    if(event.url.startsWith("whatsapp://")) {
        // stop loading the whatsapp:// link in inappbrowser
        browser.stop(); 
        // go back in history to display page where whatsapp:// link was on
        browser.history.back(); 
        window.open(event.url, "_system");
        return;
    } 
}
browser.addEventListener("loadstart", urlChanged);

Can you guide me how to solve points 1 and 2?

like image 303
fjc Avatar asked May 01 '15 06:05

fjc


People also ask

What is InAppBrowser?

The InAppBrowser is a web browser view that displays when calling [window. open](window. open. html)() , or when opening a link formed as <a target="_blank"> . var ref = window.

How do I close InAppBrowser?

In order to close the InAppBrowser window by itself, you can either use the loadstart or the message event listeners.

What is Cordova plugin InAppBrowser?

You can show helpful articles, videos, and web resources inside of your app. Users can view web pages without leaving your app. To get a few ideas, check out the sample at the bottom of this page or go straight to the reference content.


2 Answers

So I ended up with the following code:

openWithSystemBrowser = function(url) {
    window.open(url, "_system");
    location.href = "index.html";
};

shareOnWhatsapp = function(url) {
    openWithSystemBrowser(url);
};

/**
 * Handles URL changes in in-app browser, e.g. to handle logouts or
 * unsuccessful logins
 */
urlChanged = function(event) {
    if(event.url.startsWith("http://whatsapp://")) {
        shareOnWhatsapp(event.url.substr("http://".length));
        return;
    }
    if(event.url.startsWith("whatsapp://")) {
        shareOnWhatsapp(event.url);
        return;
    }
};

This is of course slightly lame as you're always brought back to index.html, but for my purposes it was enough. Interested to see if anyone's found a more elegant solution.

It also solved the 2-3 second delay before opening the system browser, but I don't have any clue why, frankly.

like image 111
fjc Avatar answered Sep 27 '22 20:09

fjc


I found an approach with a better user experience: When loading an external URL in the system browser, I close the InAppBrowser and reopen it with the last internal URL.


var appUrl = 'https://www.my-website.com';

var app = {

    currentUrl: appUrl,

    initialize: function() {
        document.addEventListener('deviceready', this.onDeviceReady.bind(this), false);
    },

    onDeviceReady: function() {
        app.openBrowser();
    },

    openBrowser: function() {
        var target = '_blank';
        var options = [
            "location=no",
            "clearcache=no",
            "clearsessioncache=no",
            "footer=no",
            "hardwareback=no",
            "hideurlbar=yes",
            "zoom=no",
            "hidenavigationbuttons=no",
            "toolbar=yes",
            "hidespinner=yes",
            "toolbarcolor=#000000",
            "toolbartranslucent=no",
            "navigationbuttoncolor=#ffffff",
            "closebuttoncolor=#000000",
            "closebuttoncaption="
        ];

        browser = cordova.InAppBrowser.open(app.currentUrl, target, options.join());

        // reopen the browser if it was closed via "Done" button
        browser.addEventListener('exit', function(){ app.openBrowser(); } );

        // open external urls in system browser window
        browser.addEventListener('loadstart', function(event){ app.handleUrl(event.url, browser); });
    },

    handleUrl: function(url, browser) {
        var extension = url.split('.').pop();

        // load internal urls that are not pdf files in the app browser
        if (extension != 'pdf' && url.startsWith(appUrl)) {
            app.currentUrl = url;
            return;
        }

        // open website in system browser window
        var ref = cordova.InAppBrowser.open(url, '_system', 'location=no');

        // since the inapp browser is loading the website too, close it and open it again with the last internal url visited
        browser.close();
        app.openBrowser();

        return;
    }
};

app.initialize();

like image 36
kcm Avatar answered Sep 27 '22 19:09

kcm