android Не удается запустить Java-функцию из Javascript
В моем проекте у меня есть WebView
который загружает страницу (HTML). Я хочу изменить все изображения и показать тост, когда пользователь нажимает на любое изображение.
Поэтому я добавляю код javascript, который вызывает функцию Java:
// 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:
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()
следует вызывать, когда
-
страница закончила загрузку
-
Пользователь нажал на изображение
Проблема: showToast()
вызывается только один раз - когда страница закончила загрузку. Когда пользователь нажимает на изображение, showToast()
не вызывается, вместо этого появляется следующий журнал:
Uncaught TypeError: Не удается прочитать свойство showToast неопределенного ", source:
Вопрос
Как вызвать showToast()
при щелчке изображения?
Ответы
Ответ 1
Я не уверен, почему, но вы можете исправить эту проблему, добавив интерфейс JavaScript до загрузки содержимого HTML.
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(); ");
}
});
Ответ 2
Удалите методу оценки JavaScript и используйте loadUrl. Попробуйте приведенный ниже код для меня:
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");
Интерфейс:-
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();
}
}
Ответ 3
Похоже, у вас нет тегов <img>
попробуйте добавить их сначала и проверьте
Android-функция
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.org/Usage/images/badge_overlay.png';" +
"x[i].addEventListener('click', function() {" +
"window.JSInterface.showToast(); " + // <-- now calling :)
"});" +
"} " +
"window.JSInterface.showToast();" // <-- is called
, null);
или вы можете сначала загрузить html-контент из активов. с webView.loadUrl();
Ответ 4
Вам не нужно ждать появления изображения на уровне dom.
string code = '
document.addEventListener("click",(e)=> {
if(e.target instanceof Image){
window.JSInterface.showToast();
}
});'
webView.evaluateJavascript(code, null);
В этом примере я использовал строковые литералы => fooobar.com/questions/17934/...
Ответ 5
Пробовали ли вы использовать функцию Javascript, где вы на самом деле вызываете Java и размещаете ее на странице html, связанной с веб-просмотром. Поместите его в заголовки, так что он будет окончательно присутствовать при последующем событии клика и не исчезнет после какой-либо оценки функции, как это, вероятно, теперь происходит в вашем случае.
<script type="text/javascript">
function showAndroidToast(toast) {
JSInterface.showToast(toast);
}
</script>
Источники, которые я нашел из подобных случаев, всегда ссылаются на отдельный html:
[1] Тост не работает в webview
[2] Android WebView showToast onButtonClick