首页 > 解决方案 > 为什么 XMLHttpRequest 在 Android 中打开并发送未使用 javascript 调用?

问题描述

我试图在使用 webView 打开 HTML 页面之前拦截 POST 请求。我按照以下教程进行操作:https://medium.com/@madmuc/intercept-all-network-traffic-in-webkit-on-android-9c56c9262c85 通过资产文件夹中的 .js 文件注入 javascript 文件:

XMLHttpRequest.prototype.origOpen = XMLHttpRequest.prototype.open;
XMLHttpRequest.prototype.open = function(method, url, async, user, password) {
    // these will be the key to retrieve the payload
    this.recordedMethod = method;
    this.recordedUrl = url;
    this.origOpen(method, url, async, user, password);

};
XMLHttpRequest.prototype.origSend = XMLHttpRequest.prototype.send;
XMLHttpRequest.prototype.send = function(body) {
    // interceptor is a Kotlin interface added in WebView
    if(body) recorder.recordPayload(this.recordedMethod, this.recordedUrl, body);
    this.origSend(body);
};

但是,从不调用 open 和 send,我添加了日志进行测试,如果我将 recorder.recordPayload(...)(这是 javascript 接口中的方法)移出这些函数,则recordPayload调用,所以问题不在于接口或从文件。

网络视图类:

class TestWebView : WebView {
    private var urlReturned = false
    private var postbackUrl: String? = "https://www.xxxxx.com"
    private var postbackHandled = false```

    lateinit var recorder: PayloadRecorder
    lateinit var payload: String

    constructor(context: Context?) : super(context) {
        initUI()
    }

    private fun initUI() {
        if (!isInEditMode) {
            settings.javaScriptEnabled = true
            settings.builtInZoomControls = true
            settings.displayZoomControls = false
            settings.loadWithOverviewMode = true
            settings.useWideViewPort = true

            recorder = PayloadRecorder()
            addJavascriptInterface(recorder, "recorder")
            evaluateJavascript(
                context.assets.open("override.js").reader().readText(), null

            )
        }


        val client: WebViewClient = object : WebViewClient() {

            override fun shouldInterceptRequest(
                view: WebView,
                request: WebResourceRequest
            ): WebResourceResponse? {

                val payload = recorder.getPayload(request.method, request.url.toString())
                // handle the request with the given payload and return the response

                return super.shouldInterceptRequest(view, request)
            }

            override fun onPageStarted(
                view: WebView,
                url: String,
                favicon: Bitmap?
            ) {
                Log.i("testURL", url)


                evaluateJavascript(
                    context.assets.open("override.js").reader().readText(),
                    object : ValueCallback<String> {
                        override fun onReceiveValue(value: String?) {
                            Log.i("onReceiveValue", value)

                        }
                    }
                )
            }

        }

        setWebChromeClient(object : WebChromeClient() {
            override fun onConsoleMessage(consoleMessage: ConsoleMessage): Boolean {
                Log.d("WebView", consoleMessage.message())
                return true
            }
        })


    }


    constructor(context: Context?, attrs: AttributeSet?) : super(
        context,
        attrs
    ) {
        initUI()
    }

    constructor(
        context: Context?,
        attrs: AttributeSet?,
        defStyle: Int
    ) : super(context, attrs, defStyle) {
        initUI()
    }

    constructor(
        context: Context?,
        attrs: AttributeSet?,
        defStyle: Int,
        privateBrowsing: Boolean
    ) : super(context, attrs, defStyle) {
        initUI()
    }


    class PayloadRecorder {
        private val payloadMap: MutableMap<String, String> =
            mutableMapOf()

        @JavascriptInterface
        fun recordPayload(
            method: String,
            url: String,
            payload: String
        ) {
            payloadMap["$method-$url"] = payload
            Log.i("payloadRecorder", "recordPayLoad")
        }

        fun getPayload(
            method: String,
            url: String
        ): String? =
            payloadMap["$method-$url"]
    }



    /**
     * The function that is called and starts the html progress
     */
    @JvmOverloads
    fun process(
        acsUrl: String?,
        md: String?,
        paReq: String?,
        postbackUrl: String? = null
    ) {
        urlReturned = false
        postbackHandled = false

        if (!TextUtils.isEmpty(postbackUrl)) {
            this.postbackUrl = postbackUrl
        }
        val postParams: String
        payload = paReq?: ""
        postParams =  //my code

        postUrl(acsUrl, postParams.toByteArray())
    }


    }

recordPayload永远不会被调用,因此 in shouldInterceptRequest payload总是返回 null。

标签: javascriptandroidwebviewxmlhttprequest

解决方案


推荐阅读