javascript 了解Android的webview addjavascriptinterface
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/10962150/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Understanding Android's webview addjavascriptinterface
提问by Akshat
I know that to interact from Javascript to Java you have to inject a Java object using the addjavascriptInterface method in webview.
我知道要从 Javascript 到 Java 进行交互,您必须在 webview 中使用 addjavascriptInterface 方法注入一个 Java 对象。
Here is the problem I am facing.
这是我面临的问题。
I register a java object using
addJavascriptInterface
method to be available in my JS.I inject few JS in the webview using
webview.loadURL("javascript:XXX");
I send a JS event when I am done with injecting the JS.
我使用
addJavascriptInterface
方法注册了一个 java 对象,以便在我的 JS 中可用。我在 webview 中注入了一些 JS 使用
webview.loadURL("javascript:XXX");
完成注入 JS 后,我发送一个 JS 事件。
The problem is that if immediately after step 1, if I execute the following Javascript:
问题是,如果在步骤 1 之后立即执行以下 Javascript:
mWebView.loadUrl("javascript:if(window.myobject) console.log('myobject found---------'); else {console.log('myobject not found----');}");
I get "myobject not found" in my console's log.
我在控制台的日志中看到“找不到我的对象”。
I want to know that if there is some time before I can access my object and if so, how do I get to know how much time should I wait to call my object?
我想知道是否还有一段时间才能访问我的对象,如果是这样,我如何知道我应该等待多长时间来调用我的对象?
回答by michiakig
I want to know that if there is some time before i can access my object
我想知道是否还有一段时间才能访问我的对象
Yes, I think there is a delay, because WebView.addJavascriptInterface
will run in the WebView's internal worker thread. Perhaps you've thought about this, and realized that WebView has to maintain at least one worker thread to do asynchronous network IO. Maybe you also noticed these threads in DDMS while using a WebView.
是的,我认为有延迟,因为WebView.addJavascriptInterface
会在 WebView 的内部工作线程中运行。或许你已经想过这个,意识到WebView至少要维护一个工作线程来做异步网络IO。也许您在使用 WebView 时也注意到 DDMS 中的这些线程。
It turns out that it also uses a thread to do work for a number of other public methods. I really wish the docs from Google made this clearer! But I hope I can help and show you how I tried to confirm this for myself.
事实证明,它还使用一个线程为许多其他公共方法工作。我真的希望 Google 的文档更清楚地说明这一点!但我希望我能帮上忙,并向您展示我如何尝试为自己确认这一点。
Follow me as I take a look at the source for WebView. It's reasonably readable, even if you can't follow exactly what's going on, it's possible to trace through answer some questions with respect to threads.
跟我来看看 WebView 的源代码。它具有合理的可读性,即使您无法准确了解正在发生的事情,也可以通过回答一些与线程相关的问题来追踪。
You can download the Android framework source through the SDK manager tool, but it's also mirrored on Github, so that's what I've linked to here. I guessed and picked a tag that's close to some version of ICS. It's not hard to find WebView.addJavascriptInterface
. I just Googled "WebView.java site:github.com/android".
您可以通过 SDK 管理器工具下载 Android 框架源代码,但它也已在 Github 上进行了镜像,因此我已将其链接到此处。我猜测并选择了一个接近某些版本的 ICS 的标签。不难找到WebView.addJavascriptInterface
。我只是在 Google 上搜索了“WebView.java 站点:github.com/android”。
The method WebView.addJavascriptInterface
sends a message to an instance of WebViewCore
:
该方法WebView.addJavascriptInterface
向 的实例发送消息WebViewCore
:
mWebViewCore.sendMessage(EventHub.ADD_JS_INTERFACE, arg);
In WebViewCore.java
there are a bunch of overloaded methods called sendMessage
, but we don't really need to know which exactly is being called, since they do pretty much the same thing. There's even a nice comment to give us a hint that we're in the right place! All of them are delegating to an instance of EventHub
which is some inner class. This methodturns out to be synchronized, and is sending a message to an instance of Handler
, which is a good indication that this is probably running in another thread, but for completeness sake, let's find out!
在WebViewCore.java
有一堆所谓的重载方法sendMessage
,但我们并不真正需要知道究竟是被称为,因为他们做的是几乎同样的事情。甚至有一个很好的评论给我们一个提示,我们在正确的地方!所有这些都委托给EventHub
某个内部类的实例。这个方法被证明是同步的,并且正在向 的实例发送消息Handler
,这很好地表明这可能正在另一个线程中运行,但为了完整起见,让我们找出来!
That Handler
is instantiated in EventHub.transferMessages
which is called from WebViewCore.initialize
. There are a few more hops here, but eventually I found out that this is called from run
in WebCoreThread
(subclass of Runnable
), which is instantiated along with a new Thread
right here.
这Handler
被实例化EventHub.transferMessages
是从所谓的WebViewCore.initialize
。这里还有一些跃点,但最终我发现这是从run
in WebCoreThread
(的子类Runnable
)调用的,它与新的Thread
right here一起实例化。
What an adventure! So, even though I really can't say for sure what's going on with all these moving parts, I am pretty confident to say that this method is not synchronous, and sends a message to the WebView's worker thread. I hope that makes sense!
多么冒险!所以,即使我真的不能确定所有这些移动部件发生了什么,我非常有信心地说这个方法不是同步的,并向 WebView 的工作线程发送消息。我希望这是有道理的!
if so, how do i get to know how much time should i wait to call my object?
如果是这样,我如何知道我应该等待多长时间来调用我的对象?
Unfortunately, I don't know the answer to this. I was researching this exact issue and found this question on StackOverflow in the course of my Googling. I think you have the following options, some of which are nicer or easier than others:
不幸的是,我不知道这个问题的答案。我正在研究这个确切的问题,并在我的谷歌搜索过程中在 StackOverflow 上发现了这个问题。我认为您有以下选择,其中一些比其他选择更好或更容易:
1) Just Thread.sleep
for 100 ms or something between addJavascriptInterface
and loadUrl("javascript:...")
. Blech, I don't like this, but it is potentially the easiest.
1) 仅Thread.sleep
100 毫秒或介于addJavascriptInterface
和之间的时间loadUrl("javascript:...")
。Blech,我不喜欢这个,但它可能是最简单的。
2) Another possibility is that you could call WebView.loadUrl
with a snippet of JavaScript that specifically tests if the interface is set, and catches the ReferenceError that is thrown if it's not set yet. However, as you might have guessed, this kind of involves adding a JavaScript interface to the WebView!
2) 另一种可能性是,您可以WebView.loadUrl
使用一段 JavaScript 代码段进行调用,该代码段专门测试接口是否已设置,并捕获尚未设置时抛出的 ReferenceError。然而,正如您可能已经猜到的,这种涉及向 WebView 添加 JavaScript 接口!
3) Call WebView.setWebChromeClient
instead, and catch JavaScript's alert()
or console.log
instead. From my experiments, this method issynchronous, so there is no delay. (I have confirmed this in source, but I'll leave details as an exercise for the reader) You should probably come up with some special string to call alert
with and check for it inside onJsAlert
, so you aren't just catching all alert()
s.
3)WebView.setWebChromeClient
改为调用,并捕获 JavaScript 的alert()
或console.log
代替。从我的实验来看,这个方法是同步的,所以没有延迟。(我已经在源代码中确认了这一点,但我会将详细信息留给读者作为练习)您可能应该想出一些特殊的字符串来调用alert
并在内部检查它onJsAlert
,这样您就不会只是捕获所有alert()
s。
Sorry for the length of this answer, I hope that helps. Good luck!
对不起,这个答案的长度,我希望有帮助。祝你好运!
回答by Richard Jones
Ensure your Javascript objects declared in your HTML / Javascript that you need to access from Java are declared global otherwise they will most likely be collected. I have code that does this (where Android is my interface added with addJavascriptInterface):
确保您需要从 Java 访问的 HTML/Javascript 中声明的 Javascript 对象被声明为全局对象,否则它们很可能会被收集。我有执行此操作的代码(其中 Android 是我使用 addJavascriptInterface 添加的界面):
<script>
var cb = function(location) {
alert('location is ' + location);
}
Android.getLocation('cb');
</script>
The getLocation method invokes Android's LocationManager.requestSingleUpdate which then invokes the callback when the LocationListener fires.
getLocation 方法调用 Android 的 LocationManager.requestSingleUpdate,然后在 LocationListener 触发时调用回调。
Without the "var" I find that by the time the location lookup invokes the callback the callback function has been garbage collected.
如果没有“var”,我发现当位置查找调用回调时,回调函数已被垃圾收集。
回答by twig
(copied from my response on a similar question)
(复制自我对类似问题的回答)
I've taken Jason Shah's and Mr S's implementation as the building block for my fix and improved upon it greatly.
我已经将 Jason Shah 和 Mr S 的实现作为我修复的基石,并对其进行了很大的改进。
There's just far too much code to put into this comment I'll just link to it.
有太多代码可以放入此评论中,我将链接到它。
- Details: http://twigstechtips.blogspot.com/2013/09/android-webviewaddjavascriptinterface.html
- Source: https://github.com/twig/twigstechtips-snippets/blob/master/GingerbreadJSFixExample.java
- 详情:http: //twigstechtips.blogspot.com/2013/09/android-webviewaddjavascriptinterface.html
- 来源:https: //github.com/twig/twigstechtips-snippets/blob/master/GingerbreadJSFixExample.java
Key points are:
关键点是:
- Applies to all versions of Gingerbread (2.3.x)
- Calls from JS to Android are now synchronous
- No longer have to map out interface methods manually
- Fixed possibility of string separators breaking code
- Much easier to change JS signature and interface names
- 适用于所有版本的 Gingerbread (2.3.x)
- 从 JS 到 Android 的调用现在是同步的
- 不再需要手动绘制接口方法
- 修复了字符串分隔符破坏代码的可能性
- 更容易更改 JS 签名和接口名称