了解 Android 的 webview addjavascriptinterface

2022-09-02 00:32:59

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

这就是我面临的问题。

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

  2. 我在Web视图中注入了几个JSwebview.loadURL("javascript:XXX");

  3. 当我完成注入JS时,我发送一个JS事件。

问题是,如果紧接在步骤1之后,如果我执行以下Javascript:

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

我在控制台的日志中收到“找不到我的对象”。

我想知道,如果有一段时间我可以访问我的对象,如果是这样,我如何知道我应该等待多少时间才能调用我的对象?


答案 1

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

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

事实证明,它还使用线程来为许多其他公共方法工作。我真的希望谷歌的文档能更清楚地说明这一点!但我希望我能提供帮助,并向您展示我如何试图为自己确认这一点。

跟着我看看WebView的源代码。它具有合理的可读性,即使您无法准确了解正在发生的事情,也可以通过回答有关线程的一些问题进行跟踪。

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

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

mWebViewCore.sendMessage(EventHub.ADD_JS_INTERFACE, arg);

其中有一堆重载方法称为sendMessage,但我们真的不需要知道究竟在调用哪个,因为它们几乎做同样的事情。甚至还有一个很好的评论,给我们一个暗示,我们来对地方了!它们都委托给 EventHub 的一个实例,该实例是某个内部类。此方法结果是同步的,并且正在向 的实例发送一条消息,这很好地表明它可能在另一个线程中运行,但为了完整性,让我们找出答案!WebViewCore.javaHandler

这是在EventHub.transferMessages中实例化的,它是从WebViewCore.initialize调用的。这里还有几个跃点,但最终我发现这是从 in (subclass of ) 调用的,它与此处的新右键一起实例化。HandlerrunWebCoreThreadRunnableThread

真是一场冒险!因此,即使我真的不能确定所有这些移动部件发生了什么,但我非常有信心地说这种方法不是同步的,并向WebView的工作线程发送消息。我希望这是有道理的!

如果是这样,我如何知道我应该等待多长时间才能调用我的对象?

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

1)只是100毫秒或介于和之间。Blech,我不喜欢这样,但它可能是最简单的。Thread.sleepaddJavascriptInterfaceloadUrl("javascript:...")

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

3)改为调用,并捕获JavaScript或代替。从我的实验来看,这种方法同步的,所以没有延迟。(我已经在源代码中确认了这一点,但我会留下细节作为读者的练习)你应该想出一些特殊的字符串来调用并在里面检查它,所以你不只是抓住所有的。WebView.setWebChromeClientalert()console.logalertonJsAlertalert()

很抱歉这个答案的长度,我希望这有帮助。祝你好运!


答案 2

确保在 HTML/Javascript 中声明的 Javascript 对象(您需要从 Java 访问)被声明为全局,否则它们很可能会被收集。我有代码可以做到这一点(其中Android是我添加的界面,添加了addJavascriptInterface):

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

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

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