0

I'm running into an issue where entering a bank account triggers an Authenticate pop-up for users inside a WebView. This pop-up is controlled via Stripe.js. Currently, the "Auth" button is shown but nothing happens when the user clicks on it. I can see that the onPageStarted is triggered via the WebViewClient with the url. The user receives an OTP via SMS, but because nothing happens they have nowhere to enter it.

On Chrome, the Auth button opens a new tab where it loads a page for the user to enter the OTP. Why is this new page not loading given the code below? Am I adding the new WebView correctly? I don't see any documentation on this. This is the only example I've found https://stackoverflow.com/a/27010225/1649472

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

    webView.addView(newWebView)

    webView.webChromeClient = object : WebChromeClient() {
       
        override fun onCreateWindow(view: WebView?, isDialog: Boolean, isUserGesture: Boolean, resultMsg: Message?): Boolean {
            val newWebView = WebView(requireActivity())
            newWebView.settings.setSupportZoom(true)
            newWebView.settings.loadWithOverviewMode = true
            newWebView.settings.javaScriptEnabled = true
            newWebView.settings.offscreenPreRaster = true
            newWebView.settings.setSupportMultipleWindows(true)
            newWebView.settings.javaScriptCanOpenWindowsAutomatically = true

            newWebView.webViewClient = object : WebViewClient() {
                override fun onPageStarted(view: WebView?, url: String?, favicon: Bitmap?) {
                    // Starts loading
                    super.onPageStarted(view, url, favicon)
                }

                override fun shouldOverrideUrlLoading(view: WebView?, request: WebResourceRequest?): Boolean {
                    // Never called
                    val newUrl = request?.url?.toString()
                    val browserIntent = Intent(Intent.ACTION_VIEW)
                    browserIntent.data = Uri.parse(newUrl)
                    startActivity(browserIntent)
                    return true
                }

                override fun onReceivedSslError(view: WebView?, handler: SslErrorHandler?, error: SslError?) {
                    // Never called
                    handler?.proceed()
                }

            }

            val transport = resultMsg?.obj as? WebView.WebViewTransport
            transport?.webView = newWebView
            resultMsg?.sendToTarget()

            return true
        }
    }
ono
  • 2,984
  • 9
  • 43
  • 85
  • Did You add the new `WebView` to your view Hierarchy, or display it using dialog? – Watermelon Apr 11 '23 at 01:16
  • @Watermelon i thought this is what adds the view? `transport?.webView = newWebView` not quite sure how that works – ono Apr 11 '23 at 15:26
  • You should also add the child webView to the valid window. `transport?.webView = newWebView ` is for specifying proxy target for IPC to the actual webProcess – Watermelon Apr 12 '23 at 06:45
  • i added this but it seems to have no effect `webView.addView(newWebView)` – ono Apr 12 '23 at 14:41
  • webView does not support adding childView outside the webView framework, child View won't layout properly. And your adding childWebView that is created inside `onCreateWindow` your passing. new WebView even before onCreateWindow` is being called. – Watermelon Apr 13 '23 at 00:22
  • @Watermelon can you provide an example on how do it your way? – ono Apr 13 '23 at 00:26

1 Answers1

1

Inside onCreateWindow you have handle where to display the new childWebview. resultMsg and WebViewTransport is to actually connect the separate webview into one window relation ship. To note that, adding view to webView is unsupported. so you have display the webview else where. For example, adding new webView to the LinearLayout that is wrapping the whole fragmentView.

To summarize the comment and example. Below is minimum functional example of opening new window.

class WebExampleFragment: Fragment() {

    override fun onCreateView(
            inflater: LayoutInflater,
            container: ViewGroup?,
            savedInstanceState: Bundle?
    ) = WebView(inflater.context).apply {
        viewLifecycleOwner.lifecycle.addObserver(LifecycleEventObserver{ _, event ->
            when (event) {
                Lifecycle.Event.ON_PAUSE -> onPause()
                Lifecycle.Event.ON_RESUME -> onResume()
                Lifecycle.Event.ON_DESTROY -> destroy()

                else -> {}
            }
        })
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        val webView = view as WebView
        webView.settings.javaScriptEnabled = true
        webView.settings.domStorageEnabled = true
        webView.settings.javaScriptCanOpenWindowsAutomatically = true
        webView.settings.setSupportMultipleWindows(true)
        webView.webViewClient = WebViewClientCompat()
        webView.webChromeClient = object: WebChromeClient() {

            override fun onCreateWindow(view: WebView, isDialog: Boolean, isUserGesture: Boolean, resultMsg: Message): Boolean {
                val transport = resultMsg.obj as WebViewTransport
                val childWebView = WebView(view.context)
                childWebView.settings.useWideViewPort = true
                childWebView.webViewClient = WebViewClientCompat()
                val dialog = MaterialAlertDialogBuilder(view.context)
                        .setView(childWebView).create()
                transport.webView = childWebView
                childWebView.webChromeClient = object: WebChromeClient() {

                    override fun onCloseWindow(window: WebView) {
                        if (window === childWebView) {
                            dialog.dismiss()
                        }
                    }

                }
                resultMsg.sendToTarget()
                dialog.show()
                return true
            }

        }
        viewLifecycleOwner.lifecycleScope.launch {
            viewLifecycleOwner.withResumed {
                webView.evaluateJavascript("""
            window.open("https://www.google.com");
        """.trimIndent(), null)
            }
        }

    }



}

enter image description here

Watermelon
  • 452
  • 2
  • 5