了解Android的webview addjavascriptinterface

时间:2012-06-09 15:18:43

标签: java javascript android webview

我知道要从Javascript到Java进行交互,你必须使用webview中的addjavascriptInterface方法注入一个Java对象。

这是我面临的问题。

  1. 我使用addJavascriptInterface方法注册一个java对象,以便在我的JS中使用。

  2. 我使用webview.loadURL("javascript:XXX");

  3. 在webview中注入了少量JS
  4. 当我完成注入JS时,我发送了一个JS事件。

  5. 问题是如果在第1步之后立即执行以下Javascript:

    mWebView.loadUrl("javascript:if(window.myobject) console.log('myobject found---------'); else {console.log('myobject not found----');}");
    

    我在控制台的日志中找到了“myobject not found”。

    我想知道如果有一段时间我可以访问我的对象,如果有,我怎么知道应该等多少时间来调用我的对象?

3 个答案:

答案 0 :(得分:46)

  

我想知道如果有一段时间我可以访问我的对象

是的,我认为存在延迟,因为WebView.addJavascriptInterface将在WebView的内部工作线程中运行。也许您已经考虑过这一点,并意识到WebView必须至少维护一个工作线程来执行异步网络IO。也许您在使用WebView时也注意到了DDMS中的这些线程。

事实证明,它还使用一个线程为许多其他公共方法工作。我真的希望谷歌的文档更清晰!但我希望我可以帮助并向您展示我是如何为自己确认的。

跟我来看看WebView的源代码。它具有相当的可读性,即使你无法完全按照正在发生的事情进行操作,也可以通过回答关于线程的一些问题进行追踪。

您可以通过SDK管理器工具下载Android框架源代码,但它也会在Github上进行镜像,这就是我在此处链接的内容。我猜测并选择了一个与某些版本的ICS接近的标签。找到WebView.addJavascriptInterface并不难。我刚用Googled“WebView.java site:github.com/android”。

方法WebView.addJavascriptInterfaceWebViewCore的实例发送消息:

mWebViewCore.sendMessage(EventHub.ADD_JS_INTERFACE, arg);

WebViewCore.java中有一堆称为sendMessage的重载方法,但我们并不需要知道究竟是哪个被调用,因为它们几乎完全相同。甚至有一个很好的评论给我们一个提示,我们在正确的地方!所有这些都委托给EventHub的实例,这是一个内部类。 This method结果是同步的,并且正在向Handler的实例发送消息,这很好地表明这可能在另一个线程中运行,但为了完整起见,让我们找出来! / p>

EventHub.transferMessagesHandler实例化了run。这里还有一些跳,但最终我发现这是从WebCoreThread Runnable的子类中的Thread调用的,它与新的{{1}一起实例化}右WebViewCore.initialize

多么冒险!所以,即使我真的无法确定所有这些移动部件的发生情况,我很自信地说这个方法不是同步的,并向WebView的工作线程发送消息。我希望这是有道理的!

  

如果是这样,我怎么知道应该等多久才能打电话给我的对象?

不幸的是,我不知道答案。我正在研究这个确切的问题,并在我的谷歌搜索过程中在StackOverflow上发现了这个问题。我认为您有以下选择,其中一些比其他选项更好或更容易:

1)只需Thread.sleep 100毫秒或addJavascriptInterfaceloadUrl("javascript:...")之间的内容。 Blech,我不喜欢这个,但它可能是最简单的。

2)另一种可能性是,您可以使用JavaScript片段调用WebView.loadUrl,该片段专门测试接口是否已设置,并捕获在尚未设置的情况下引发的ReferenceError。但是,正如您可能已经猜到的那样,这种方法涉及向WebView添加JavaScript接口!

3)改为调用WebView.setWebChromeClient,然后抓住JavaScript的alert()console.log。从我的实验来看,这种方法是同步的,所以没有延迟。 (我已经在源代码中确认了这一点,但我会将详细信息作为练习留给读者)你应该想出一些特殊字符串来调用alert并在onJsAlert内检查它,所以你不只是抓住所有alert()

对不起这个答案的长度,我希望有所帮助。祝你好运!

答案 1 :(得分:1)

确保您需要从Java访问的HTML / Javascript中声明的Javascript对象被声明为全局,否则很可能会收集它们。我有代码执行此操作(Android是我的界面添加了addJavascriptInterface):

<script>
  var cb = function(location) {
     alert('location is ' + location);
  }
  Android.getLocation('cb');
</script>

getLocation方法调用Android的LocationManager.requestSingleUpdate,然后在LocationListener触发时调用回调。

如果没有“var”,我发现当位置查找调用回调时,回调函数已被垃圾收集。

答案 2 :(得分:0)

(从a similar question上的回复中复制)

我把Jason Shah和S先生的实施作为我修复的基石,并对其进行了很大的改进。

我只是链接到这个评论的代码太多了。

要点是:

  • 适用于所有版本的Gingerbread(2.3.x)
  • 从JS到Android的调用现在是同步的
  • 不再需要手动映射接口方法
  • 修正字符串分隔符破坏代码的可能性
  • 更容易更改JS签名和界面名称