WebView loadUrl ("javascript: ...") doesn't work
I am playing with an Android WebView: I have a sample text "asdf" that needs to be colored when the user clicks a button (red, green, or blue). To make things a little more complicated, the WebView first tells the Java code to initiate a color change, and then from within Java the WebView changes:
public class MainActivity extends ActionBarActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final WebView myWebView = (WebView) findViewById(R.id.webview);
WebSettings webSettings = myWebView.getSettings();
webSettings.setJavaScriptEnabled(true);
webSettings.setDomStorageEnabled(true);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
WebView.setWebContentsDebuggingEnabled(true);
}
final WebAppInterface webAppInterface = new WebAppInterface(this, myWebView);
myWebView.addJavascriptInterface(webAppInterface, "Android");
myWebView.loadUrl("file:///android_asset/index.html");
}
}
This is the interface:
public class WebAppInterface {
Context context;
WebView webView;
WebAppInterface(Context context, WebView webView) {
this.context = context;
this.webView = webView;
}
@JavascriptInterface
public void dye(String color) {
switch (color) {
case "red":
webView.loadUrl("javascript:dyeRed()");
break;
case "green":
webView.loadUrl("javascript:dyeGreen()");
break;
case "blue":
webView.loadUrl("javascript:dyeBlue()");
break;
}
}
}
There are 3 buttons in my html file:
<button onClick="callDyeRed()">
RED
</button>
And inside a javascript file that is loaded successfully, I have functions like this:
function callDyeRed() {
Android.dye("red");
}
function dyeRed() {
document.getElementsByTagName('body')[0].style.color = 'red';
}
When I click on the button, I see that a line is being executed inside the WebAppInterface webView.loadUrl("javascript:dyeRed()")
. This way js-> Java linking works. However, the opposite is not true: after that, the JavaScript code is not executed.
What am I missing here?
If I change the color from the WebViewClient the communication works:
myWebView.setWebViewClient(new WebViewClient() {
@Override
public void onPageFinished(WebView webView, String url) {
webView.loadUrl("javascript:dyeGreen()");
}
});
source to share
The JavaScript-related object runs on a different thread ("JavaBridge") than the thread ("Looper") in which it was created. All WebView methods must be called on the same thread. Therefore, you cannot call the loadUrl method on a newly created thread.
Possible workaround:
Webappinterface.java
class WebAppInterface {
Context context;
WebView webView;
WebAppInterface(Context context, WebView webView) {
this.context = context;
this.webView = webView;
}
@JavascriptInterface
public String dye(String color) {
switch (color) {
case "red":
return "dyeRed";
case "green":
return "dyeGreen";
case "blue":
return "dyeBlue";
default:
return "alert";
}
}
}
script.js
function callDyeRed() {
window[Android.dye("red")]();
}
function dyeRed() {
document.getElementsByTagName('body')[0].style.backgroundColor = 'red';
}
source to share