admin管理员组文章数量:1278789
In my project I have a WebView
which loads a page (HTML).
I want to change all images and show a toast when a user clicks on any image.
So I'm adding javascript code which calls Java function:
// code is inside onPageFinished(..) function
JavaScriptInterface jsInterface = new JavaScriptInterface(activity);
webView.getSettings().setJavaScriptEnabled(true);
webView.addJavascriptInterface(jsInterface, "JSInterface");
webView.evaluateJavascript(
"var imgs = document.getElementsByTagName('img');" +
"for (var i = 0; i < imgs.length; i++) {" +
"imgs[i].src = 'file:///android_asset/rules_images_placeholder.png';" +
"imgs[i].addEventListener('click', function() {" +
"window.JSInterface.showToast(); " + // <-- isn't called: see logs
"});" +
"} " +
"window.JSInterface.showToast();" // <-- is called
, null);
JavaScriptInterface class:
public class JavaScriptInterface {
private Activity activity;
public JavaScriptInterface(Activity activity) {
this.activity = activity;
}
@JavascriptInterface
public void showToast() {
Toast.makeText(activity, "Toast message", Toast.LENGTH_SHORT).show();
}
}
showToast()
should be called when
page has finished loading
user has clicked on image
Problem: showToast()
is called only once - when page has finished loading.
When the user clicks on image, showToast()
isn't called, instead the following log appears:
Uncaught TypeError: Cannot read property 'showToast' of undefined", source:
Question
How to call showToast()
on image click?
In my project I have a WebView
which loads a page (HTML).
I want to change all images and show a toast when a user clicks on any image.
So I'm adding javascript code which calls Java function:
// code is inside onPageFinished(..) function
JavaScriptInterface jsInterface = new JavaScriptInterface(activity);
webView.getSettings().setJavaScriptEnabled(true);
webView.addJavascriptInterface(jsInterface, "JSInterface");
webView.evaluateJavascript(
"var imgs = document.getElementsByTagName('img');" +
"for (var i = 0; i < imgs.length; i++) {" +
"imgs[i].src = 'file:///android_asset/rules_images_placeholder.png';" +
"imgs[i].addEventListener('click', function() {" +
"window.JSInterface.showToast(); " + // <-- isn't called: see logs
"});" +
"} " +
"window.JSInterface.showToast();" // <-- is called
, null);
JavaScriptInterface class:
public class JavaScriptInterface {
private Activity activity;
public JavaScriptInterface(Activity activity) {
this.activity = activity;
}
@JavascriptInterface
public void showToast() {
Toast.makeText(activity, "Toast message", Toast.LENGTH_SHORT).show();
}
}
showToast()
should be called when
page has finished loading
user has clicked on image
Problem: showToast()
is called only once - when page has finished loading.
When the user clicks on image, showToast()
isn't called, instead the following log appears:
Uncaught TypeError: Cannot read property 'showToast' of undefined", source:
Question
How to call showToast()
on image click?
-
This is definitely how you would do it (provided the first call works, as you say). Have you simplified the example too much, perhaps, pared to your real code (if this isn't your real code)? Specifically, in your real code, are you using
i
from within the event handler? Because that would be this problem. – T.J. Crowder Commented Jun 28, 2018 at 13:14 - T.J. Crowder: Actually I haven't simplified the code - I have cut and pasted it. – Vitaly Zinchenko Commented Jun 28, 2018 at 13:28
-
In that case, you need to look at what's changed since page load and the click. The error message is telling you that
window.JSInterface
is (now)undefined
, whereas it had a different value (a reference to your object) earlier. For some reason that changed. I don't think we can tell from what's in the question above what changed, but that's what you want to look for. – T.J. Crowder Commented Jun 28, 2018 at 13:50
5 Answers
Reset to default 3 +100I am not sure why, but you can fix this problem by adding a JavaScript interface prior to loading your HTML content.
jsInterface = new JavaScriptInterface(activity);
fragmentWebView.getSettings().setJavaScriptEnabled(true);
fragmentWebView.getSettings().setDomStorageEnabled(true);
fragmentWebView.addJavascriptInterface(jsInterface, "JSInterface");
fragmentWebView.loadDataWithBaseURL("file:///android_asset/", fullHtml, "text/html", "utf-8", null);
fragmentWebView.setWebViewClient(new WebViewClient() {
@Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
view.loadUrl(
"javascript:var imgs = document.getElementsByTagName('img');" +
"for (var i = 0; i < imgs.length; i++) {" +
"imgs[i].src = 'file:///android_asset/rules_images_placeholder.png';" +
"imgs[i].addEventListener('click', function(e) {" +
"window.JSInterface.showToast(); " +
"});" +
"}" +
"console.log(window.JSInterface);" +
"window.JSInterface.showToast(); ");
}
});
Remove the evaluateJavascript methoad and use loadUrl. Try the below code its working for me:-
webView.getSettings().setJavaScriptEnabled(true);
webView.setWebViewClient(new WebViewClient() {
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
}
@Override
public void onPageFinished(final WebView view, String url) {
Log.e("checking", "MYmsg");
webView.loadUrl("javascript: var imgs = document.getElementsByTagName('img');" +
"for (var i = 0; i < imgs.length; i++) {" +
"imgs[i].addEventListener('click', function() {" +
"window.CallToAnAndroidFunction.showToast(); " +
"});" +
"} " );
}
});
webView.addJavascriptInterface(new WebAppInterface(Main2Activity.this),
"CallToAnAndroidFunction");
Interface:-
public class WebAppInterface {
Context mContext;
/** Instantiate the interface and set the context */
WebAppInterface(Context c) {
mContext = c;
}
/** Show a toast from the web page */
@JavascriptInterface
public void showToast() {
Toast.makeText(mContext, "Toast message", Toast.LENGTH_SHORT).show();
}
}
Looks like you don't have <img>
tags
try adding them first and check
Android function
WebView webView= findViewById(R.id.webview);
JavaScriptInterface jsInterface = new JavaScriptInterface(this);
webView.getSettings().setJavaScriptEnabled(true);
webView.addJavascriptInterface(jsInterface, "JSInterface");
webView.evaluateJavascript(
"document.write('<img>');" +
"document.write('<img>');\n"+
"var x = document.getElementsByTagName('IMG');" +
"console.log(x.length);"+
"for (var i = 0; i < x.length; i++) {" +
"x[i].src = 'https://www.imagemagick/Usage/images/badge_overlay.png';" +
"x[i].addEventListener('click', function() {" +
"window.JSInterface.showToast(); " + // <-- now calling :)
"});" +
"} " +
"window.JSInterface.showToast();" // <-- is called
, null);
or you can load html content from assets first. with webView.loadUrl();
You no need to wait for image appearance at dom level.
string code = `
document.addEventListener("click",(e)=> {
if(e.target instanceof Image){
window.JSInterface.showToast();
}
});`
webView.evaluateJavascript(code, null);
At this example I used string literals => https://stackoverflow./a/50155171/5138198
Have you tried taking the Javascript function where you actually call Java and place it inside the html page related to the webview. Place it at headers, so it will definitively be present when click event later takes place, and won't disappear after any evaluation of function, like it probably does now in your case.
<script type="text/javascript">
function showAndroidToast(toast) {
JSInterface.showToast(toast);
}
</script>
Sources I found of similar cases refer always to separate html:
[1] Toast does not work in webview
[2] Android WebView showToast onButtonClick
本文标签: android Cannot run Java function from JavascriptStack Overflow
版权声明:本文标题:android Cannot run Java function from Javascript - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1741244406a2364598.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论