You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android WebView注入JS按钮报错:downloadListener未定义

问题根源

  1. JS作用域限制:动态绑定的事件回调中,无法直接访问全局暴露的downloadListener对象,需显式通过window引用。
  2. 内部类访问问题:局部非静态内部类可能存在权限或生命周期问题,改为静态内部类更稳妥。
  3. JS执行时机不当:直接通过post执行JS可能在页面DOM未完全加载时运行,导致找不到目标video元素,同时接口暴露的时序也可能存在问题。

修复方案

1. 重构DownloadListener为静态内部类

避免非静态内部类持有外部类引用引发内存泄漏,同时确保@JavascriptInterface注解的方法能被WebView正确识别。

2. 在JS中通过window访问Java接口

修改事件回调代码,用window.downloadListener替代直接调用downloadListener,确保能访问到全局暴露的Java对象。

3. 延迟JS执行到页面加载完成后

将JS代码的执行逻辑放在WebViewClient的onPageFinished方法中,保证DOM已加载完成,能正确定位到目标video元素。

修复后的完整代码

private void setup(WebView webView, String videoUrl) {
    webView.getSettings().setJavaScriptEnabled(true);
    webView.getSettings().setDomStorageEnabled(true);

    // 改为静态内部类,避免内存泄漏并确保接口可访问
    static class DownloadListener {
        @JavascriptInterface
        public void onDownloadButtonClick(String buttonId, String videoSrc) {
            Log.d("DownloadListener", "Button with id " + buttonId + " was clicked for video with src " + videoSrc);
            // 在这里处理下载逻辑
        }
    }

    // 提前将Java接口暴露到JS环境
    webView.addJavascriptInterface(new DownloadListener(), "downloadListener");

    // 设置WebViewClient,确保页面加载完成后执行JS
    webView.setWebViewClient(new WebViewClient() {
        @Override
        public void onPageFinished(WebView view, String url) {
            super.onPageFinished(view, url);
            // 构造注入的JS代码
            String jsCode = "function addDownloadOverlayToVideo(videoSrc) { " +
                    "  var video = document.querySelector('video[src=\"' + videoSrc + '\"]'); " +
                    "  if (!video) { " +
                    "    console.log('未找到对应src的video元素: ' + videoSrc); " +
                    "    return; " +
                    "  } " +
                    "  var parent = video.parentNode; " +
                    "  parent.style.width = '100%'; " +
                    "  var overlay = parent.querySelector('.download-overlay'); " +
                    "  if (!overlay) { " +
                    "    overlay = document.createElement('div'); " +
                    "    overlay.className = 'download-overlay'; " +
                    "    overlay.style.position = 'absolute'; " +
                    "    overlay.style.display = 'inline-block'; " +
                    "    overlay.style.top = '5px'; " +
                    "    overlay.style.right = '5px'; " +
                    "    overlay.style.margin = '5px'; " +
                    "    overlay.style.zIndex = '9999'; " +
                    "    var button = document.createElement('button'); " +
                    "    button.innerHTML = 'Download'; " +
                    "    var id = 'download-button-' + Date.now(); // 动态生成ID避免重复 " +
                    "    button.id = id; " +
                    "    button.style.backgroundColor = '#FF0000'; " +
                    "    button.style.padding = '10px 20px'; " +
                    "    button.style.borderRadius = '5px'; " +
                    "    button.style.color = '#FFFFFF'; " +
                    "    button.style.fontSize = '18px'; " +
                    "    button.addEventListener('mousedown', function() { " +
                    "      this.style.transform = 'translateY(2px)'; " +
                    "      this.style.backgroundColor = '#000000'; " +
                    "      // 显式通过window访问Java接口 " +
                    "      window.downloadListener.onDownloadButtonClick(this.id, video.src); " +
                    "    }); " +
                    "    overlay.appendChild(button); " +
                    "    parent.style.position = 'relative'; " +
                    "    parent.appendChild(overlay); " +
                    "  } " +
                    "} " +
                    "addDownloadOverlayToVideo('" + videoUrl + "');";

            // 在UI线程执行JS代码
            webView.post(() -> webView.evaluateJavascript(jsCode, null));
        }
    });
}

额外注意事项

  • Android版本兼容:Android 4.2及以上版本,只有添加@JavascriptInterface注解的Java方法才能被JS访问,否则会被安全机制拦截。
  • 元素重复问题:原代码中按钮ID固定,若页面存在多个视频会导致ID冲突,改为动态生成ID可避免该问题。
  • 错误容错:添加video元素不存在的判断,防止JS报错中断后续逻辑执行。

内容的提问来源于stack exchange,提问作者TPX

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 23:33:22