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() следует вызывать, когда

  1. страница закончила загрузку

  2. Пользователь нажал на изображение

Проблема: 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