从Java - Android监听JavaScript函数调用

3

我在服务器上托管了一些HTML5/javascript文件。当HTML5页面上的按钮被点击时,会调用一个javascript函数。我想监听函数被调用的时机,并获取函数返回的json数据。以前我是在设备上打开端口,但这在Android 3.0上似乎不起作用。我听说可以使用外部接口来监听javascript调用,但我不知道如何实现。


你是在WebView中运行你的页面吗? - Olegas
2个回答

3
要使用外部接口,您需要在WebView中运行您的站点。此外,以下解决方案意味着:
1. 您需要知道要拦截的所有函数名称, 2. 这些函数必须在JS代码的公共作用域中。
要注册您的接口,您需要在WebView实例上调用addJavascriptInterface方法。您需要为其选择一个名称并创建一个实现。您的接口应该拦截函数调用并报告它们的结果,因此,让我们对其进行描述…
class FunctionCallInterceptor {
    public void reportCall(String functionName, String result) {
      // some code, handling interception
    }
}

并注册它...

mWebView.addJavascriptInterface(new FunctionCallInterceptor(), 'Interceptor');

更多关于JavaScript接口的信息,请参阅绑定JavaScript

接下来,您需要将函数结果“传输”到您的接口…这里需要一些JavaScript代码。

function wrapFunc(name) {
  if(typeof window[name] == 'function') {  // If target is accessible
    var original = window['__' + name] = window[name];  // remember original one
    window[name] = function() {  // and replace with wrapper
        var result = original.apply(this, arguments); // call original                
        Interceptor.reportCall(name, result.toString()); // report to interceptor
        return result;  // return result as usual
    }
  }
}

要包装您的函数,请使用以下代码

wrapFunc('myFunction'); // wraps myFunction in the source

此外,请务必启用JavaScript。
mWebView.getSettings().setJavaScriptEnabled(true);

在没有访问外部JS代码的情况下,何时以及如何将此代码嵌入到您的外部页面中...要在页面上下文中执行任意代码,您可以使用WebViewloadUrl方法。

mWebView.loadUrl('javascript:some... js... code...');

这不会触发页面重新加载,只有JavaScript将被执行。请注意,在页面完全加载后执行此操作所需的内容。您可以通过以下代码获取此内容:

mWebView.setWebViewClient(new WebViewClient {
    @Override
    public void onPageFinished (WebView view, String url) {
        // here page is loaded
    }
});

请参阅setWebViewClientonPageFinished了解详细信息。
另外请注意,通过loadUrl调用传输到页面的代码不能包含换行符。因此,您需要通过String.replace或类似方法将其删除。 补充 所以,最终解决方案是:
String wrapFuncCode = "function wrapFunc ...... "; // or maybe place it in resources?
mWebView.addJavascriptInterface(new FunctionCallInterceptor(), 'Interceptor');
mWebView.getSettings().setJavaScriptEnabled(true);
mWebView.setWebViewClient(new WebViewClient {
    @Override
    public void onPageFinished (WebView view, String url) {
       // inject wrapper
       // don't forget to remove newline chars
       mWebView.loadUrl("javascript:" + wrapFuncCode.replace('\n', ''));

       // wrap all the functions needed
       String[] funcToWrap = new String[] { 'myFunc1', ... };
       for(String f : funcToWrap) {
           mWebView.loadUrl("javascript:wrapFunc('" + f + "myFunction');");  
       }  
    }
});

你好,您能否详细说明一下这个函数wrapFunc(name)的作用?{ if(typeof window[name] == 'function') { // 如果目标可访问 var original = window['__' + name] = window[name]; // 记住原始函数 window[name] = function() { // 并用包装器替换 var result = original.apply(this, arguments); // 调用原始函数 Interceptor.reportCall(name, result.toString()); // 报告给拦截器 return result; // 像平常一样返回结果 } } } 然后执行wrapFunction('myFunction')。请问我应该在哪里添加这段代码呢? - Vibhuti
是的,我正在使用 WebView 运行我的页面,我知道我想要拦截的函数名称,而且它们确实在 JS 代码的公共范围内。 - Vibhuti
我已经添加了完整的解决方案。如果事情不会更清楚,请提出具体的问题。 - Olegas

2

我采用了不同的方法,很容易就成功了。我使用了window.external.notify(String message)。在我的Java代码中,我使用了webview.addJavascriptInterface(new JSInterface(),"external"),并且在我的JSInterface类中,我编写了一个公共函数public void notify(String messg),messg包含了来自JavaScript的响应。


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