Android:拦截WebView中的AJAX调用

16
我希望能够创建一个基于HTML/JavaScript的应用程序,通过WebView发起AJAX调用,并由Java代码处理。 最好的情况是仅拦截调用(很容易,只需使用shouldOverrideUrlLoading()),并返回一些数据。 但是,我找不到将响应“返回”给WebView的方法,除了使用loadUrl()调用JavaScript函数。 这对我来说行不通,因为HTML/JavaScript应用程序是一个我无法控制的预设应用程序。就HTML/JavaScript应用程序而言,它只是发起AJAX调用并接收一些数据。 您对此有何想法?

可以在发送表单数据后获取 Ajax 响应吗?表单网页从远程 URL 在 Webview 中显示。 - Mansukh Ahir
4个回答

35

好消息,从API级别11开始,他们将shouldInterceptRequest方法放入了WebViewClient类中。 它还会在应用程序内部触发的WebView请求上触发。你可以按如下方式重写它:

@Override
public WebResourceResponse shouldInterceptRequest(WebView view, String url)
{
    if (magicallyMatch(url))
        return new WebResourceResponse("application/json", "utf-8", magicallyGetSomeInputStream());

    return null;
}

根据Android参考文档:

public WebResourceResponse shouldInterceptRequest (WebView view, String url)

自 API level 11 开始提供。

通知宿主应用程序资源请求,并允许应用程序返回数据。如果返回值为空,WebView 将按原样继续加载资源。否则将使用返回的响应和数据。注意:此方法由网络线程调用,因此客户端在访问私有数据时应谨慎。

参数

view 请求资源的 WebView

url 资源的原始 URL。

返回值

包含响应信息的 WebResourceResponse 对象或 null,如果WebView应该自行加载资源。

还请查看WebResourceResponse

希望这可以帮助您。


1
可以在发送表单数据后获取Ajax响应吗?表单网页从远程URL在Webview中显示。 - Mansukh Ahir

13
您可以使用JavascriptInterface来拦截AJAX调用,以及使用JQuery方法ajaxStartajaxComplete按以下方式进行:
// our JavascriptInterface
public class AjaxHandler {

    private static final String TAG = "AjaxHandler";
    private final Context context;

    public AjaxHandler(Context context) {
        this.context = context;
    }

    public void ajaxBegin() {
        Log.w(TAG, "AJAX Begin");
        Toast.makeText(context, "AJAX Begin", Toast.LENGTH_SHORT).show();
    }

    public void ajaxDone() {
        Log.w(TAG, "AJAX Done");
        Toast.makeText(context, "AJAX Done", Toast.LENGTH_SHORT).show();
    }
}

以下是如何在Activity中使用AjaxHandler

    public class MainActivity extends Activity {

    private static final String TAG = "MainActivity";

    private WebView webView;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.main);

        // get web view
        webView = (WebView) findViewById(R.id.web); 

        // configure web view 
        final WebSettings webSettings = webView.getSettings();
        webSettings.setBuiltInZoomControls(true);
        webSettings.setJavaScriptEnabled(true);

        webView.loadUrl("http://foo.com");

        // add javascript interface
        webView.addJavascriptInterface(new AjaxHandler(this), "ajaxHandler");

        // override onPageFinished method of WebViewClient to handle AJAX calls 
        webView.setWebViewClient(new WebViewClient() {

                @Override
                public void onPageFinished(WebView view, String url) {
                    super.onPageFinished(view, url);

                    view.loadUrl("javascript:$(document).ajaxStart(function (event, request, settings) { " +
                            "ajaxHandler.ajaxBegin(); " + // Event called when an AJAX call begins
                            "});");
                    view.loadUrl("javascript:$(document).ajaxComplete(function (event, request, settings) { " +
                            "ajaxHandler.ajaxDone(); " + // Event called when an AJAX call ends
                            "});");

            });
    }
}

主要思想来自这里,稍作修改后呈现出来。
虽然提交答案有点晚了,但希望这也能帮助其他人!


这是一个很好的解决方案。但我该如何从js代码中获取AjaxHandler中的请求参数? - b-boy sh1ft
1
非常好的解决方案,谢谢。另外,我想提醒一下,在这种情况下,使用ajaxStop可能更好,因为它在ajax实际停止加载时触发。 来源:https://dev59.com/w2855IYBdhLWcg3wUCaC#4421115 - Luis Pereira
@S1LENT WARRIOR 我按原样放置了代码,但是 Toast 无论如何都没有显示。 - Mansukh Ahir
可以在提交表单数据后获取Ajax响应吗?表单网页从远程URL在网络视图中显示。 - Mansukh Ahir
1
这个很好用!但是我不得不像这里描述的那样,使用@JavascriptInterface属性来装饰本地的ajaxDone和ajaxBegin方法:https://developer.android.com/reference/android/webkit/WebView.html - Fredrik Johansson
这段代码不清楚,我复制了它但是不起作用!!你能否在GitHub上创建一个项目? - A. Albrg

0

最终我还是使用了问题中描述的方法;

我拦截了一些特定的请求,例如:foo://bar/get/1?callback=foobar,然后解析了URL并调用了一个带有实际数据的JavaScript回调函数。
回调函数在URL的查询部分中定义,因此在上面的示例中,它将是:foobar();

调用该函数很容易,只需使用:yourWebView.loadUrl("javascript:foobar('somedata')");


1
Erik,请您详细说明一下,您是如何为处理AJAX请求重载URL的?并且告诉我如何从Java中处理AJAX请求。另外,我不知道调用拦截机制...我陷入了同样的问题...需要帮助...谢谢。 - jyotin

0

现在是2023年,我遇到了同样的问题。

我使用了shouldInterceptRequest()方法来解决它。这个技巧是通过过滤被拦截的请求并根据情况采取行动。

shouldInterceptRequest()方法拦截所有在你的WebView上发出的请求。在我的情况下,我知道正在进行的确切请求以及与请求相关联的确切URL。

@Nullable
@Override
public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {

  String sURLPatternExpected = "";
  if (request.getUrl().toString().contains(sURLExpected)) {

    String sExactURLExpected = "";
    if (!request.getUrl().toString().equals(sExactURLExpected)) {
      //  User is going outside your expected URL.
    } else {
      //  User is going outside your expected URL.
    }

  }

  return null;
}

在上面的代码片段中,首先检查请求URL是否与你要查找的模式匹配。例如,如果你对像http://example.com/app/resource?message=hello这样的URL感兴趣,则通过以上方式进行过滤,将防止你对像http://example.com/favicon.ico这样的URL采取行动。
接下来,现在需要检查被过滤的URL组中你所期望的确切URL。
最后,我返回null以让WebView正常处理请求。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接