evaluateJavascript(String script, ValueCallback<String> resultCallback)
method is added to WebView on Android in SDK 19.
Android documentation quotes:
If non-null, resultCallback will be invoked with any result returned from that execution.
I am using this method as shown below, but somehow my callback is not being invoked. I can see from debugging that the evaluateJavascript()
is called, but the call back is not being invoked in Android API 19, 20 & 21. From API 22 (LOLLIPOP_MR1) onwards, everything is working as expected.
Calling webview.loadURL("")
before evaluateJavascript()
makes it work on all the API levels. I want to understand why and would appreciate if somebody can shed some light / share any links about this. If I can understand why, I want to see if calling loadURL()
could be avoided. There is another unrelated problem which makes loadURL()
a non-preferable solution.
Code:
private void webViewTest() {
WebView webview = new WebView(this);
webview.getSettings().setJavaScriptEnabled(true);
Log.d("TEST", "BEFORE"); // LOGGED
// webview.loadUrl(""); // Enabling this makes it work on all Android versions
webview.evaluateJavascript("(function(){return 'test'})()", new ValueCallback<String>() {
@Override
public void onReceiveValue(String s) {
Log.d("TEST", "From JS: " + s); // NEVER LOGGED on API 19-21
}
});
Log.e("TEST", "AFTER"); // LOGGED
}
runOnUiThread(new Runnable() {
@Override
public void run() {
webViewTest();
}
});
Please find an example of this problem at https://github.com/bashok001/TestApp
From the docs:
Asynchronously evaluates JavaScript in the context of the currently displayed page. In ContentViewCore
EvaluateJavascript
checks for renderview. Looks like for that particular versions of WebView
integrated within 19,20,21 - the RenderView
is just not created until loadUrl
get called.
I found following FIX that could be relevant:
It's modify WebContentsAndorid native implementation of EvaluateJavaScript from :
void WebContentsAndroid::EvaluateJavaScript(JNIEnv* env,
jobject obj,
jstring script,
jobject callback,
jboolean start_renderer) {
RenderViewHost* rvh = web_contents_->GetRenderViewHost();
DCHECK(rvh);
if (start_renderer && !rvh->IsRenderViewLive()) {
if (!static_cast<WebContentsImpl*>(web_contents_)->
CreateRenderViewForInitialEmptyDocument()) {
...
}
}
...
to :
void WebContentsAndroid::EvaluateJavaScript(JNIEnv* env,
jobject obj,
jstring script,
jobject callback) {
RenderViewHost* rvh = web_contents_->GetRenderViewHost();
DCHECK(rvh);
if (!rvh->IsRenderViewLive()) {
if (!static_cast<WebContentsImpl*>(web_contents_)->
CreateRenderViewForInitialEmptyDocument()) {
...
}
}
....
And in ContentViewCore
there was following code which passing false
as start_renderer
:
public void evaluateJavaScript(String script, JavaScriptCallback callback) {
assert mWebContents != null;
mWebContents.evaluateJavaScript(script, callback, false);
}
This mean that on WebView
built prior to mentioned fix calls to evaluateJavaScript
does not create RenderView
and as result WebContext
can't handle java script execution.
So when you use loadUrl
you force creation of render view and all starts working as expected.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With