是有可能访问通过web视图POST方法HTML表单数据?是有、视图、表单、方法

2023-09-05 07:51:43 作者:花开雨落又逢春

我已经开始写一个应用程序,它提供了通过的WebView的HTML表单的用户。由于形式下,我控制不,填补了数据可发送为GET或POST请求。我的应用程序是需要捕捉的形式传输数据,也就是获得什么输入到表单字段保留。

I've started to write an app which provides the user with an HTML form via a WebView. As the form is not under my control, the data filled in may be sent as either GET or POST request. My app is required to capture the transported form data, that is, get a hold on what was entered into the form fields.

使用从WebViewClient适当的回调,如 onPageLoaded(),很容易从一个GET请求获取表单数据。但是,我找不到任何合适的方法,让同为发布的数据,即,能够访问包含表单数据的HTTP POST邮件正文。我缺少相关的回调在这里或在那里根本就没有办法完成给定的API(即使是最新的8级)?

Using an adequate callback from WebViewClient such as onPageLoaded(), it is easy to capture form data from a GET request. However, I cannot find any appropriate method to allow the same for POSTed data, i.e., be able to access the HTTP POST message body containing the form data. Am I missing a relevant callback here or is there simply no way to accomplish the specified goal with the given API (even the latest level 8)?

假设这是不可能的,我考虑重写,并以引入传递的POST体某种程度上新回调钩子延伸android.webkit的零件。这样一来,我的应用程序可以附带一个自定义浏览器/ WebViewClient,满足所需的功能。但是,我找不到任何好地方下手,在code和。将很高兴在这方面的任何提示的情况下(方法看起来很有希望的话)。

Assuming it wasn't possible, I considered overriding and extending parts of android.webkit in order to introduce a new callback hook that is passed the POST body somehow. That way, my app could be shipped with a customized browser/WebViewClient that fulfills the desired feature. However, I couldn't find any good spot to start with in the code and would be glad for any hints in this regards (in case the approach looks promising at all).

在此先感谢!

推荐答案

正如我自己的意见,以原来的问题,JavaScript的注射方法效果。基本上,你需要做的是添加一些一段JavaScript code到DOM onsubmit事件,有它解析形式的领域,并返回结果返回给Java注册的功能。

As indicated in my own comment to the original question, the JavaScript injection approach works. Basically, what you need to do is add some piece of JavaScript code to the DOM onsubmit event, have it parse the form's fields, and return the result back to a Java-registered function.

code例如:

public class MyBrowser extends Activity {
    private final String jsInjectCode = 
        "function parseForm(event) {" +
        "    var form = this;" +
        "    // make sure form points to the surrounding form object if a custom button was used" +
        "    if (this.tagName.toLowerCase() != 'form')" +
        "        form = this.form;" +    
        "    var data = '';" +
        "    if (!form.method)  form.method = 'get';" +
        "    data += 'method=' + form.method;" +
        "    data += '&action=' + form.action;" +        
        "    var inputs = document.forms[0].getElementsByTagName('input');" +
        "    for (var i = 0; i < inputs.length; i++) {" +
        "         var field = inputs[i];" +
        "         if (field.type != 'submit' && field.type != 'reset' && field.type != 'button')" +
        "             data += '&' + field.name + '=' + field.value;" +
        "    }" +
        "    HTMLOUT.processFormData(data);" +
        "}" +
        "" +
        "for (var form_idx = 0; form_idx < document.forms.length; ++form_idx)" +
        "    document.forms[form_idx].addEventListener('submit', parseForm, false);" +    
        "var inputs = document.getElementsByTagName('input');" +
        "for (var i = 0; i < inputs.length; i++) {" +
        "    if (inputs[i].getAttribute('type') == 'button')" +
        "        inputs[i].addEventListener('click', parseForm, false);" +
        "}" +
        "";

    class JavaScriptInterface {
        @JavascriptInterface
        public void processFormData(String formData) {
            //added annotation for API > 17 to make it work
            <do whatever you need to do with the form data>
        }
    }

    onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.browser);
        WebView browser = (WebView)findViewById(R.id.browser_window);
        browser.getSettings().setJavaScriptEnabled(true);
        browser.addJavascriptInterface(new JavaScriptInterface(), "HTMLOUT");
        browser.setWebViewClient(new WebViewClient() {
        @Override
        public boolean shouldOverrideUrlLoading(WebView view, String url) {
            view.loadUrl(url);
            return true;
        }

        @Override
        public void onPageFinished(WebView view, String url) {
            view.loadUrl("javascript:(function() { " + 
                      MyBrowser.jsInjectCode + "})()");
        }
}

通俗地说,这是什么做的是注入的自定义JavaScript code(作为的onsubmit 处理程序),每当一个页面完成加载。在提交的表单,用JavaScript解析表单数据,并通过 JavaScriptInterface 对象传递回Java的土地。

Informally, what this does is inject the custom JavaScript code (as a onsubmit handler) whenever a page finishes loading. On submission of a form, Javascript will parse the form data and pass it back to Java land through the JavaScriptInterface object.

为了解析表单域,Javascript的code补充形式的onsubmit 和按钮的onclick 处理程序。前者可以通过常规的提交按钮操作规范的表单提交,而后者处理自定义提交按钮,即按钮,做一些额外的JavaScript魔术之前调用 form.submit()

In order to parse form fields, the Javascript code adds form onsubmit and button onclick handlers. The former can handle canonical form submissions through a regular submit button while the latter deals with custom submit buttons, i.e., buttons that do some additional Javascript magic before calling form.submit().

请注意,Javascript的code可能不是完美的:可能有其他的方法来提交表单,我的注入code可能无法赶上。不过,我相信,注入code可以进行更新,以应对这种可能性。

Please be aware that the Javascript code may not be perfect: There might be other methods to submit a form that my injected code may not be able to catch. However, I'm convinced that the injected code can be updated to deal with such possibilities.