我有一个Android应用程序(一个Web浏览器),它使用默认的Webview加载网页。通过重载shouldInterceptRequest
方法,我使用OkHTTP3库加载页面。
之所以这样做,是因为我想在执行任何Javascript之前将JavaScript注入每个页面。使用evaluateJavascript
无法做到这一点,因为它是异步的,因此不能保证将首先执行代码。这是它的代码:
override fun shouldInterceptRequest(view: WebView, request: WebResourceRequest): WebResourceResponse? {
val httpRequestBuilder = Request.Builder()
when (request.method) {
"GET" -> httpRequestBuilder.get()
}
httpRequestBuilder.url(url)
httpRequestBuilder.headers(Headers.of(request.requestHeaders))
val httpRequest = httpRequestBuilder.build()
val httpResponse = OkHttpClient().newCall(httpRequest).execute()
httpResponse?.run {
val contentType = body()?.contentType()
val mime = contentType?.type() + "/" + contentType?.subtype()
val encoding = contentType?.charset()?.name() ?: "utf-8"
val message = if (message().isEmpty()) {
"OK"
} else {
message()
}
val header = HashMap<String, String>()
headers().toMultimap().forEach { entry ->
header[entry.key] = entry.value[0]
}
val contentStream = if (contentType?.subtype() == "html") {
object : InputStream() {
val streams = arrayOf(
ByteArrayInputStream("<script type=\"text/javascript\">".toByteArray()),
context.assets.open("MyJS.js"),
ByteArrayInputStream("</script>".toByteArray()),
body()?.byteStream()!!
)
var currentIndex = 0
override fun read(): Int {
while (currentIndex < streams.size) {
val res = streams[currentIndex].read()
if (res != -1) {
return res
}
currentIndex++;
}
return -1;
}
}
} else {
body()?.byteStream()!!
}
return WebResourceResponse(mime, encoding, code(), message, header, contentStream)
}
注入的JavaScript本质上修改了一些原型。它还尝试将自身插入页面上的框架和iframe中以进行相同的修改。这是脚本自身的一部分:
(function() {
var self = document.currentScript;
var observer = new window.MutationObserver(function (changes) {
for (var index = 0; index < changes.length; index++) {
var change = changes[index];
if (change.type == "childList") {
for (var i = 0; i < change.addedNodes.length; i++) {
var node = change.addedNodes[i];
switch (node.nodeName) {
case "IFRAME":
var orig_sandbox = node.sandbox;
node.sandbox = "allow-scripts";
node.contentDocument.write("<script type=\"text/javascript\">" + self.text + "<\\/script>");
node.sandbox = orig_sandbox;
break;
case "FRAME":
node.contentDocument.write("<script type=\"text/javascript\">" + self.text + "<\\/script>");
}
}
}
}
});
observer.observe(document.documentElement, {childList: true, subtree: true});
})();
目标是将此JavaScript注入未从网络加载的框架中(无论如何,这些框架都将由shouldInterceptRequest
方法处理),而不是未从网络加载或由其他JavaScript创建的框架中。
现在我有一个问题,那就是它不起作用。它没有注入子帧中。
有人知道有可能将Javascript注入此类框架吗?