14

I'm trying to develop a custom browser with WebView using Android API level 10 (sdk 2.3.3), unfortunately I don't know how to intercept request from the webpageto open URL in new browser window, like taps on links with target="_blank".

In conformity with the API Doc I have overridden the onCreateWindow of WebChromeClient, but is not called when such a link is tapped. Could be a bug of this API level? I'm also overriding shouldOverrideUrlLoading to avoid WebView opening subsequent links in the built-in browser.

Here is my sample code that opens google.com. To test it, tap "News" and then tap on any news title. The Android built-in browser normally opens it in a new browser window.

package com.myexample;

import android.app.Activity;
import android.os.Bundle;
import android.os.Message;
import android.util.Log;
import android.webkit.WebChromeClient;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.Toast;

public class HelloAndroidActivity extends Activity {

  private static String TAG = "WebViewTest";
  private WebView mWebView;

  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    Log.i(TAG, "onCreate");
    setContentView(R.layout.main);

    mWebView = (WebView) findViewById(R.id.mywebview);

    mWebView.setWebViewClient(new WebViewClient() {
      @Override
      public boolean shouldOverrideUrlLoading(WebView view, String url) {
        view.loadUrl(url);
        return true;
      }
    });

    mWebView.setWebChromeClient(new WebChromeClient() {
      @Override
      public boolean onCreateWindow(WebView view, boolean dialog, boolean userGesture, Message resultMsg) {
        Toast.makeText(getApplicationContext(), "OnCreateWindow", Toast.LENGTH_LONG).show();
        return true;
      }
    });
    mWebView.loadUrl("http://www.google.com");
  }

}

Parth Doshi
  • 4,200
  • 15
  • 79
  • 129
Lotzy
  • 489
  • 1
  • 6
  • 14
  • Lotzy, onCreateWindow will get called only if you return true from shouldOverrideUrlLoading. Seems to be a web view bug, because in most cases you can't return false from shouldOverride... – myself May 16 '12 at 07:40
  • Well, as you can see there is a return true; in the shouldOverrideUrlLoading method. – Lotzy Nov 26 '12 at 17:33

4 Answers4

30

Make sure you set supportMultipeWindows to true. Without it the onCreateWindow of the WebChromeClient will never get called.

WebSettings settings = webView.getSettings();
settings.setSupportMultipleWindows(true);

Then register a WebChromeClient and override onCreateWindow

 webView.setWebChromeClient(new WebChromeClient() {
        @Override public boolean onCreateWindow(WebView view, boolean dialog, boolean userGesture, Message resultMsg)
        {
            WebView newWebView = new WebView(getContext());
            addView(newWebView);
            WebView.WebViewTransport transport = (WebView.WebViewTransport) resultMsg.obj;
            transport.setWebView(newWebView);
            resultMsg.sendToTarget();
            return true;
        }
    });
Geert Weening
  • 1,480
  • 1
  • 13
  • 17
  • 2
    For me it's not working, that Toast from onCreateWindow() method is not shown. I also put a breakpoint in that line and launched the app with the debugger but execution does not stops in that line. – Lotzy Nov 26 '12 at 17:37
  • Awesome, finally works with this ! Jsut a question, why "addView(newWebView)" ? I don't get this line. And I also don't use it. Could you explain the point of this line ? thx – Seynorth Sep 24 '14 at 14:49
  • @Seynorth It's been a long time since I answered this question. The addView was probably needed to add the newly created WebView to the view hierarchy. Otherwise it's just a view object that's not being attached anywhere in the view hierarchy and probably won't show up or render. If you didn't need to do that, I'm wondering how you made it work. – Geert Weening Oct 01 '14 at 16:47
  • is it possible to obtain current URL(i mean clicked url) from "onCreateWindow" method, bce i would like to open url in same webview. – evan Nov 04 '14 at 15:07
  • When do you remove the view,if ever? :) – rogerdpack Oct 11 '17 at 08:58
  • This worked for me too. Just like @Seynorth, I also do not use/need the "addview(newWebView. Am I correct in assuming that onCreateWindow only gets called for links that have a target="_blank"? – iDoes Nov 30 '17 at 13:14
  • I think addView is needed when you create a Webview from nothing as you do ( WebView newWebView = new WebView(getContext()); In my case, I use the webview given as entry parameter. That is why I don't need it. And I don't really get it why recreating a new webview instead of using the one provided as entry parameter – Seynorth Dec 01 '17 at 08:03
  • Maybe, because it will be a redirection to url that represents new window, and it can/will cause a data/state loss. – Demigod Apr 11 '18 at 09:30
  • is it possible to get Clicked Url in onCreateWindow? – Ahmad Apr 01 '20 at 08:40
  • onCreateWindow never called. any solution ? – Jithish P N Dec 23 '20 at 11:54
8

Could not find any solution other than injecting javascript code. I even tried to compile the built-in android browser code downloaded from google source repository but will not compile as I found out that uses some non public API. Dolphin browser also uses its own extented WebView so I had no luck finding out how they implement open new window request detection.

This javascript code gets all link tags on the loaded page and analyze if there is an attribute with target="_blank". For each of these links will add "newtab:" in front of the url value of the href attribute. Then in the shouldOverrideUrlLoading() method I check if url begins with "newtab:" string, in which case I open a new tab.

Here are the code snipets:

    mWebView.setWebViewClient(new WebViewClient() {

        @Override
        public void onPageFinished(WebView view, String url) {
            // Find all <a> with target="_blank" and append "newtab:" at the beginning. 
            // Make sure a null is at the end to avoid displaying a blank page
            view.loadUrl("javascript: var allLinks = document.getElementsByTagName('a'); if (allLinks) {var i;for (i=0; i<allLinks.length; i++) {var link = allLinks[i];var target = link.getAttribute('target'); if (target && target == '_blank') {link.setAttribute('target','_self');link.href = 'newtab:'+link.href;}}} null");
        }



        @Override
        public boolean shouldOverrideUrlLoading(WebView view, String urls) {
            if (urls.startsWith("newtab:")) {
                addTab(); //add a new tab or window
                loadNewURL(urls.substring(7)); //strip "newtab:" and load url in the webview of the newly created tab or window
            }
            else {
                view.loadUrl(urls); //load url in current WebView
            }
            return true;
        }
    }

moyo
  • 1,312
  • 1
  • 13
  • 29
Lotzy
  • 489
  • 1
  • 6
  • 14
6

You need to take a look at this:

webView.getSettings().setSupportMultipleWindows(true);

Then onCreateWindow will get called.

oers
  • 18,436
  • 13
  • 66
  • 75
Jon B
  • 61
  • 2
0

All the answers that override onCreateWindow from WebChromeClient, didn't work for me. Sometimes it opened an image in a browser instead of opening the url, as expected.

The only solution that fully works is the answer by @Lotzy combined with @Vaughn Armada addition (adding null to the end of the javascript snippet). Using this code, all links with target="_blank" will open in a new browser window, and without that target, they will open inside the same WebView.

webView.webViewClient = object : WebViewClient() {
    override fun onPageFinished(view: WebView, url: String) {
        // Check all <a>'s with target="_blank" so that it opens in browsers when it's supposed to.
        // Make sure a null is at the end to avoid displaying a blank page
        view.loadUrl("javascript: var allLinks = document.getElementsByTagName('a'); if (allLinks) {var i;for (i=0; i<allLinks.length; i++) {var link = allLinks[i];var target = link.getAttribute('target'); if (target && target == '_blank') {link.setAttribute('target','_self');link.href = 'newtab:'+link.href;}}} null");
    }

    override fun shouldOverrideUrlLoading(view: WebView, url: String): Boolean {
        if (url.startsWith("newtab:")) {
            // Open browser with the url, removing the added "newtab:"
            view.context.startActivity(Intent(Intent.ACTION_VIEW).setData(Uri.parse(url.removePrefix("newtab:"))))
        } else {
            // Load inside webview
            view.loadUrl(url)
        }
        return true
    }
}
moyo
  • 1,312
  • 1
  • 13
  • 29