Android - 如何在 API 级别 4 的 android WebViewClient 中拦截表单 POST

Posted

技术标签:

【中文标题】Android - 如何在 API 级别 4 的 android WebViewClient 中拦截表单 POST【英文标题】:Android - how to intercept a form POST in android WebViewClient on API level 4 【发布时间】:2011-04-09 12:44:12 【问题描述】:

我有一个WebViewClient 附加到我的WebView,如下所示:

webView.setWebViewClient(new MyWebViewClient());

这是我对MyWebViewClient的实现:

private class MyWebViewClient extends WebViewClient 

    @Override
    public boolean shouldOverrideUrlLoading(WebView view, String url) 
      webView.loadUrl(url);
      return true;
        

我给WebView 一个URL 以通过loadUrl() 加载。如果页面中有链接(a href...),我的shouldOverrideUrlLoading方法被调用,我可以拦截链接点击。

但是,如果我有一个方法为POST 的表单,则不会调用shouldOverrideUrlLoading 方法。

我在这里注意到一个类似的问题:http://code.google.com/p/android/issues/detail?id=9122 这似乎建议在我的WebView 中覆盖postUrl。但是,此 API 仅从 API 级别 5 开始可用。

如果我处于 API 级别 4,我该怎么办?有没有其他方法可以拦截表单帖子?

【问题讨论】:

您可以尝试在 WebViewClient 中覆盖 onPageStarted 回调。 谢谢。我试过了,它工作正常,但问题是我不想加载表单的页面 - 这是一个虚假的 URL,所以我最终得到了 webview 错误页面。如果 URL 与我的表单 URL 匹配,我通过检查 onPageStarted 来解决此问题,如果是,则在我的应用程序中处理此问题,然后告诉 webViewClient 返回。这听起来合理吗? 您找到解决方案了吗? 这些天,我们有WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) 可以拦截 POST。它仍然不够完美。您不能简单地设置自定义标头并让请求继续 - 您必须 handle it all yourslef 【参考方案1】:

您真的需要使用 POST 吗?如果您想在本地处理表单数据,为什么不让一段 javascript 使用 addJavascriptInterface 处理您的表单并与“本机”java 代码接口。例如

WebView engine = (WebView) findViewById(R.id.web_engine);       
engine.getSettings().setJavaScriptEnabled(true); 
engine.addJavascriptInterface(new MyBridge(this), "bridge");
engine.loadUrl(...)

你的桥基本上可以是任何类,你应该能够直接从 javascript 访问它的方法。例如

public class MyBridge 

    public MyBridge(Context context) 
         // ...
    

    public String doIt(String a, String b) 
            JSONArray result = new JSONArray();
            result.put("Hello " + a);
            result.put("Hello " + b);
            return result.toString();       
    

您的 html / javascript 可能如下所示:

<script type="text/javascript">
    $("#button").click(function() 
        var a = $("#a").val();
        var b = $("#b").val();

        var result=JSON.parse(bridge.doIt(a, b));
        // ...
    
</script>

<input id="a"><input id="b"><button id="button">click</button>

【讨论】:

这是理想的解决方案,但不幸的是似乎不适用于 2.3 模拟器和那一代的各种手机。查找 VM 崩溃并出现以下错误:JNI WARNING: jarray 0x40533560 points to non-array object (Ljava/lang/String;) Google for that for more information【参考方案2】:

这是一个已知问题,shouldOverrideUrlLoading 不会捕获 POST。有关详细信息,请参阅http://code.google.com/p/android/issues/detail?id=9122。

使用 GET!我个人尝试使用 POST,因为我预计 GET 参数会受到一些限制(即 URL 的长度),但我只是在本地通过 GET 成功传递了 32000 个字节,没有任何问题。

【讨论】:

我真的需要找到解决方案。因为,就我而言,实际上切换到 GET 不在我的手中。我无法理解它是如何在 android 中丢失的。原因是什么。 webView 中覆盖postUrl。这从 API 级别 5 开始可用。 我做了,没有成功。不处理。 我也需要一个解决方案。我需要为通过我的 WebView 发出的所有请求添加一个自定义标头。我首先加载了一个重定向(通过 POST wheee!)到另一个页面的 url,但我无法捕获该重定向并正确添加自定义标题。我无法控制服务器以及它使用 POST 而不是 GET 的事实。【参考方案3】:

我认为您可以从 WebViewClient 覆盖 onLoadResource(WebView view, String url)。该功能在 API LEVEL 1 中添加。

WebView 将加载给定 url 指定的资源时调用此函数。资源包括jscssiframe 嵌入网址。代码示例如下:

    @Override
    public void onLoadResource(WebView view, String url) 
        if (url.indexOf("http://www.example.com") != -1 && view != null) 
            // open url in default browser
            view.stopLoading();
            view.getContext().startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(url)));
        
    

【讨论】:

在问题中要求拦截 POST 请求而不尝试加载资源。两者都不一样。 对于那些对此响应添加缺点的人:根据HTTP标准,“资源”不仅仅是文件(js,css等)。 “资源”是 URI 指向的任何东西。例如,API 端点也是资源。

以上是关于Android - 如何在 API 级别 4 的 android WebViewClient 中拦截表单 POST的主要内容,如果未能解决你的问题,请参考以下文章

Android各个版本的介绍

如何定位多个 API 级别?

以编程方式获取设备的 Android API 级别?

Google ADs(ADmobs) 需要 API 级别 4.0 Android

Smack 4.1 所需的最低 Android API 级别是多少?

Android系统版本特性(4.4版本--11版本)