如何将 javascript 从 Java 代码注入到 Android WebView 中的 IFrame?

How do I inject javascript to an IFrame from Java code into an Android WebView?

我正在编写一个 Android 应用程序,它在 WebView 中显示网页。其中一些包括 IFrame。我无法控制要显示的页面。

该应用程序的部分功能是将 javascript 代码从我的 Java 代码注入页面(添加 JavaScript 接口和脚本)。我可以很容易地在主页上做到这一点 ,但在 IFrame.

中做到这一点似乎是一项更具挑战性的任务

看起来 WebViewClient 的 onPageFinished 事件 class(注入脚本的适当位置)只针对主页触发,而不针对其中的 IFrames。

关于如何做到这一点有什么想法吗?

据我所知,执行此操作的唯一方法是使用 WebViewClient 并覆盖 shouldInterceptRequest。寻找您想要注入内容的 iframe 的 url,将 url 手动加载到流或文本中,使用字符串操作注入您想要添加的内容或您想要删除的任何内容,然后将其作为 WebResourceResponse 而不是原始请求发送。

这是一些可以转换为 java:

的 kotlin 代码
    webView.webViewClient = object : WebViewClient() {
        private fun shouldInjectToIframe(url: String?): Boolean {
            return !url.isNullOrBlank() && url.indexOf("<string to look for>") > -1
        }
        private fun injectToIframe(url: String): WebResourceResponse? {
            Log.d(TAG, "Intercepted $url")
            val latch = CountDownLatch(1)
            var res: InputStream? = null
            val call = App.instance?.okHttpClient?.newCall(Request.Builder().url(url).build())
            call?.enqueue(object : Callback {
                override fun onFailure(call: Call, e: IOException) {
                    latch.countDown()
                }

                override fun onResponse(call: Call, response: Response) {
                    res = response.body?.byteStream()
                    latch.countDown()
                }
            })

            latch.await()

            val reader = BufferedReader(res?.reader())
            var content: String
            try {
                content = reader.readText()
            } finally {
                reader.close()
            }

            var scriptToInject = "\n&lt;script>\n" +
                "   (function() {\n" +
                "     alert('hi');\n" +
                "   })()\n" +
                "&lt;/script>\n"
            val newContent = "${content.split("&lt;/head>")[0]}${scriptToInject}</head>${content.split("&lt;/head>")[1]}"
            Log.d(TAG, "Inject script to iframe: $newContent")
            val inStream = newContent.byteInputStream()
            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) return WebResourceResponse(
                "text/html",
                "utf-8",
                inStream
            )
            val statusCode = 200
            val reasonPhase = "OK"
            val responseHeaders: MutableMap<String, String> = HashMap()
            return WebResourceResponse("text/html", "utf-8", statusCode, reasonPhase, responseHeaders, inStream)
        }

        override fun shouldInterceptRequest(view: WebView?, url: String?): WebResourceResponse? {
            if (shouldInjectToIframe(url)) return injectToIframe(url!!)
            if (Util.SDK_INT &lt; Build.VERSION_CODES.LOLLIPOP) return super.shouldInterceptRequest(view, url)
            return null
        }

        @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
        override fun shouldInterceptRequest(view: WebView?, request: WebResourceRequest): WebResourceResponse? {
            if (shouldInjectToIframe(request.url.toString())) return injectToIframe(request.url.toString())
            return super.shouldInterceptRequest(view, request)
        }
    }