Search code examples
javascriptjavaandroidwebviewandroid-webview

How Android WebView gets the URL of the new window from the Message object?


public boolean onCreateWindow(WebView view, boolean dialog, boolean userGesture, Message resultMsg)

I found a way to do it at StackOverflow, but it doesn't get the "window.open('example.com')" url.

Message href = view.getHandler().obtainMessage();
view.requestFocusNodeHref(href);
String url = href.getData().getString("url");

// Only get "<a href='example.com' target='_blank'>" url.

Solution

  • webChromeClient doesn't expose the URL of the tapped link when creating a new window.

    If you need to handle the tapped URL, the only way to handle window.open() case is through webViewClient's shouldOverrideUrlLoading, which is something like below:

    webChromeClient = object : WebChromeClient() {
        override fun onCloseWindow(window: WebView?) {
            super.onCloseWindow(window)
        }
    
        override fun onCreateWindow(
            view: WebView?,
            isDialog: Boolean,
            isUserGesture: Boolean,
            resultMsg: Message?
        ): Boolean {
    
            if (view?.context == null) {
                return false
            }
            if (resultMsg == null) {
                return false
            }
    
            // Use CustomTabs to open the link when the hitTestResult is not null
            if (view.hitTestResult.extra != null) {
                val colorParam = CustomTabColorSchemeParams.Builder().setToolbarColor(getColor(context, R.color.blue)).build()
                val intent = CustomTabsIntent.Builder()
                    .setDefaultColorSchemeParams(colorParam)
                    .setShowTitle(true)
                    .build()
                intent.launchUrl(view.context, Uri.parse(view.hitTestResult.extra))
                return false
            }
    
            // Use a new webViewClient to handle window.open() case
            val newWebView = WebView(view.context)
            newWebView.webViewClient = object : WebViewClient() {
                override fun shouldOverrideUrlLoading(
                    view: WebView?,
                    request: WebResourceRequest?
                ): Boolean {
                    if (request?.url == null) {
                        return true
                    }
                    val url = request.url.toString()
                    if (url.contains("example.com")) {
                        // Here you can handle “example.com” and do whatever you want
                        return true
                    }
                    return true
                }
            }
            val transport = resultMsg.obj as WebView.WebViewTransport
            transport.webView = newWebView
            resultMsg.sendToTarget()
    
            return true
        }
    }
    

    By the way, don't forget to add JS settings to WebView.

    webView.apply {
        settings.javaScriptEnabled = true
        settings.javaScriptCanOpenWindowsAutomatically = true
        settings.setSupportMultipleWindows(true)
    }
    

    Hope this will help.