Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Capturing page redirects via javascript in Android's WebView

I have a WebView in my app that displays a page not belonging to me. My desired behavior is, if any link is tapped by the user, the device's Browser app is launched, and the resulting page is loaded there. Unfortunately, this page is doing some weird things, so shouldOverrideUrlLoading() does not fire.

My attempted solution is to hook some javascript into pushState and use an interface to run Android code to launch the browser app.

Here is my interface:

public class LaunchExternalBrowserHack {
    Context mContext;

    LaunchExternalBrowserHack(Context c) {
        mContext = c;
    }

    @JavascriptInterface
    public void launchExternalBrowser(String url) {
        openUrl(url);
    }
}

I'm injecting some javascript into the page in onPageFinished():

public void onPageFinished(WebView view, String url) {
     mWebView.loadUrl(javascript);
}

Here is my javascript:

private final String javascript = "javascript:history.pushState = function (state, title, url) { console.log(url); console.log(location.href); Uphoria.launchExternalBrowser(location.origin, url); };";

And, of course, I'm adding the interface to the WebView:

mWebView.addJavascriptInterface(new LaunchExternalBrowserHack(getContext()), "Android");

So this seems to work. The Browser app is launching and the next page is opening.

However, the WebView is also moving forward, too. I want to prevent this, but I cannot find a way to prevent the WebView moving forward while still allowing me to capture the forwarding url and launch the Browser app. As I mentioned earlier, with this webpage, shouldOverrideUrlLoading is not firing.

Ideas?

like image 929
Andrew Avatar asked Mar 30 '16 20:03

Andrew


2 Answers

The user is trying to move away from the page. to stop him from moving out, return false. to let him move away, don't return anything but you can execute any code that you may want. This event is fired immediately when navigation event occurs including page refresh.

private final String javascript = "window.onbeforeunload = function(){ dosomething(); }; window.unload = function(){ dosomething(); }; function dosomething() { /* Write code here */  };"

You need to include the entire javascript code above, since some browsers use onbeforeunload and some use unload

EDIT

After careful reading of your problem I found my solution to be of little use.

Here's another approach using history. If your history is blank, that means its the first page. but if you have some items in history, it means that navigation has occurred.

You can check it as following

private final String javascript = "javascript:"+"if(window.history.length>=1 && document.referrer=='') Android.launchExternalBrowser(location.href);";
like image 155
Rohit Agre Avatar answered Sep 27 '22 20:09

Rohit Agre


This answer is wrong. Kept here because it has importantly relevant comments.

The reason that you are not getting a result from your Javascript, is that you are not calling a function directly. You are assigning a function in your Javascript that returns a value, but it will not return that to your code, it will return that to whatever calls history.pushState().

private final String javascript = "javascript:" + "var pushState = history.pushState; history.pushState = function () " +
        "{ pushState.apply(history, arguments); console.log(arguments); return location.href; " +
        "};";

Instead, you can test whether something like this returns you a value:

private final String javascript = "(function() { return location.href; })();";
like image 28
Knossos Avatar answered Sep 27 '22 18:09

Knossos