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

Flutter evaluateJavascript仅生效一次,Android需卸载清缓存恢复

问题解决:Flutter WebView注入JS仅生效一次(Android专属问题)

核心问题分析

你当前使用的DOMSubtreeModified是已废弃的DOM事件API,Android系统的WebView内核(基于Chromium)对该API的实现存在兼容性问题,多次触发后可能被浏览器主动节流或失效,导致后续DOM变化时无法重新绑定事件。而iOS的WebKit内核对废弃API的兼容性处理更宽松,因此未出现问题。此外,反复对元素执行off('click').on('click')也可能导致事件绑定逻辑混乱,在Android上积累错误状态。

解决方案1:使用事件委托(推荐)

无需监听DOM变化,直接将点击事件委托到document上,不管目标元素何时动态生成,都能触发回调。这种方式更高效稳定:

await webViewController.evaluateJavascript(source: """
  document.addEventListener('click', function(e) {
    const target = e.target;
    if (target.tagName === 'A' && target.href.startsWith('/GenericUpload/GetFile')) {
      e.preventDefault(); // 阻止默认跳转行为
      window.flutter_inappwebview.callHandler('MobileAppDownload', target.href);
    }
  }, true);
""");

解决方案2:替换为MutationObserver(标准DOM监听API)

如果必须监听DOM变化,用标准的MutationObserver替代废弃的DOMSubtreeModified,它能精准控制监听范围,避免不必要的性能损耗:

await webViewController.evaluateJavascript(source: """
  // 配置观察规则:监听子元素的添加/移除
  const observerConfig = { childList: true, subtree: true };
  const targetNode = document.body;

  const observer = new MutationObserver(function(mutations) {
    mutations.forEach(function(mutation) {
      // 仅处理新增节点的情况
      if (mutation.addedNodes.length > 0) {
        document.querySelectorAll("a[href^='/GenericUpload/GetFile']").forEach(link => {
          // 先移除已有绑定,避免重复触发
          link.removeEventListener('click', handleDownloadClick);
          link.addEventListener('click', handleDownloadClick);
        });
      }
    });
  });

  // 定义统一的点击处理函数
  function handleDownloadClick(e) {
    e.preventDefault();
    window.flutter_inappwebview.callHandler('MobileAppDownload', this.href);
  }

  // 启动DOM观察
  observer.observe(targetNode, observerConfig);

  // 初始化时绑定已有元素
  document.querySelectorAll("a[href^='/GenericUpload/GetFile']").forEach(link => {
    link.addEventListener('click', handleDownloadClick);
  });
""");

额外Android适配建议

  • 检查WebView缓存设置,避免页面缓存旧的JS逻辑:
    WebView(
      initialUrl: "your_target_url",
      javascriptMode: JavascriptMode.unrestricted,
      onWebViewCreated: (controller) {
        controller.settings.cacheMode = WebSettings.LOAD_NO_CACHE;
      },
    )
    
  • 确保JS注入时机正确,建议在onPageFinished回调中执行注入,避免页面未加载完成时DOM不存在的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 02:19:57