Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android Webview: Scripts may close only the windows that were opened by it

I am loading a particular url

For eg.

webview.loadUrl("some.domain.com")

Afterwords I am redirecting it to some other domain and then coming back to my domain. Then I try to close the window in my javascript (window.close()). I get the below error while debugging remotely on chrome developer tools

Scripts may close only the windows that were opened by it.

I am getting the above error even though I am on the same domain with which I opened it.

Any help would be very much appreciated. Thank you.

like image 200
Binary Baba Avatar asked Feb 26 '18 13:02

Binary Baba


People also ask

How do you fix Scripts may close only the windows that were opened by it?

Scripts may close only the windows that were opened by it. A workaround now is redirect user to another page rather than close the window, you could redirect user to a notification page to show "The items has been closed successfully" using window. location. href="PageUrl".

How do I close WebView?

To close a WebViewPrefab (or CanvasWebViewPrefab), destroy it either by calling WebViewPrefab. Destroy() or by destroying its parent with Object.

How do I close a window using JavaScript?

The Window. close() method closes the current window, or the window on which it was called. This method can only be called on windows that were opened by a script using the Window. open() method.


1 Answers

This answer will be from Android App Developer perspective. I hope it will help someone.

The problem was very similar for me: I was opening a web site via webview, and some of the links were opening in a new window. The thing is that webview cannot work with web windows out of the box. I mean, it can be possible, but not as expected (in my case, when a link was opened in a separate window from javascript perspective, it were overriding previously opened page, and cannot be closed with a window.close() from javascript, which eventually were causing a state loss on a previous page).

So the task in my case was to open a single link in a window and go back to previous page without any state loss. That was my solution. I had two separate WebViews - one as a main one, and one for links in window. To be able to react on a "link in new window" event, I'll configured main webView with this code:

    webView.settings.javaScriptEnabled = true
    webView.settings.javaScriptCanOpenWindowsAutomatically = true
    webView.settings.setSupportMultipleWindows(true)

    webView.webChromeClient = object : WebChromeClient() {

    override fun onCreateWindow(view: WebView?, isDialog: Boolean, isUserGesture: Boolean,
                                resultMsg: Message?): Boolean {
        handleCreateWebWindowRequest(resultMsg)
        return true
    }
}

We need only onCreateWindow callback to override in main webView chrome client, since it will only open new windows. And also allow a multiwindow support in webView.settings. When an onCreateWindow callback triggers, do the following:

@SuppressLint("SetJavaScriptEnabled")
override fun handleCreateWebWindowRequest(resultMsg: Message?) {
    if (resultMsg == null) return
    if (resultMsg.obj != null && resultMsg.obj is WebView.WebViewTransport) 
        {
        val transport = resultMsg.obj as WebView.WebViewTransport
        windowWebView = WebView(this)
        windowWebView?.layoutParams = ViewGroup.LayoutParams(
                ViewGroup.LayoutParams.MATCH_PARENT, 
        ViewGroup.LayoutParams.MATCH_PARENT)

        windowWebView?.settings?.javaScriptEnabled = true
        windowWebView?.settings?.javaScriptCanOpenWindowsAutomatically = true
        windowWebView?.settings?.setSupportMultipleWindows(true)
        windowWebView?.webViewClient = WebViewClient()
        windowWebView?.webChromeClient = object : WebChromeClient() {
            override fun onCloseWindow(window: WebView?) {
                super.onCloseWindow(window)
                handleCloseWebWindowRequest()
            }
        }

        container.addView(windowWebView)
        webView.visibility = View.GONE
        transport.webView = windowWebView
        resultMsg.sendToTarget()
    }
}

Basically we're sending this (create window) request to a separate webView. In it we should also allow a multiwindow support and attach a chrome client, in wich we should listen only onCloseWindow event, since this webView should behave as a window. When onCloseWindow triggers, we're just closing (hiding/removing) webView that should act as a window, and returning to the main one. Here isWebWindowOpened method call just checks if the windowWebView is not null and visible.

private fun handleCloseWebWindowRequest() {
    if (!isWebWindowOpened()) return

    container.removeView(windowWebView)
    webView.visibility = View.VISIBLE
    windowWebView = null
}

The only thing I can mention, is that when a windowWebView is opened, onBackPressed action should close it calling handleCloseWebWindowRequest.

like image 78
Demigod Avatar answered Sep 27 '22 20:09

Demigod