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

后端 未结 1 2099
耶瑟儿~
耶瑟儿~ 2020-12-21 05:11

I am loading a particular url

For eg.

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

Afterwords I am redirecting it to some other domain and

相关标签:
1条回答
  • 2020-12-21 05:39

    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.

    0 讨论(0)
提交回复
热议问题