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

React Native安卓端WebView如何监听文件下载事件

React Native安卓端WebView PDF下载捕获方案

已知环境:react-native-webview@^11.15.0,场景为WebView加载链接经多次跳转后触发PDF下载,现有onNavigationStateChange匹配后缀的方案无法覆盖无后缀、响应头触发下载的场景,官方提供的文件下载回调仅支持iOS,安卓端无默认实现。


方案1:原生层加下载监听(推荐,稳定性100%)

安卓系统WebView本身自带下载监听接口,只是react-native-webview没有把这个接口封装到JS层,手动加几行代码就能覆盖所有下载场景,不管跳多少次、链接带不带pdf后缀都能抓到:

  • 找到文件路径 node_modules/react-native-webview/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewManager.java
  • 在WebView实例初始化的代码块里,添加如下下载监听逻辑:
webView.setDownloadListener(new DownloadListener() {
  @Override
  public void onDownloadStart(String url, String userAgent, String contentDisposition, String mimetype, long contentLength) {
    // 匹配PDF类型,要支持其他下载类型直接在这里加判断即可
    if ("application/pdf".equals(mimetype) || url.contains(".pdf")) {
      // 两种处理方式二选一:
      // 方式一:直接唤起系统下载器/浏览器打开PDF,无需额外编写下载逻辑
      Intent intent = new Intent(Intent.ACTION_VIEW);
      intent.setData(Uri.parse(url));
      ((ReactContext)webView.getContext()).startActivity(intent);

      // 方式二:把下载事件抛回JS层处理,比如用rn-fetch-blob实现自定义下载、对接自定义PDF预览组件
      // WritableMap event = Arguments.createMap();
      // event.putString("pdfUrl", url);
      // ((RNCWebView) webView).emit("androidPdfDownload", event);
    }
  }
});
  • 如果选择事件抛回JS层的处理方式,在WebView组件上添加对应事件监听即可:
<WebView
  onNavigationStateChange={handleWebViewNavigationStateChange}
  source={{uri: my_url_link}}
  style={styles.webviewStyles}
  onAndroidPdfDownload={(e) => {
    const pdfUrl = e.nativeEvent.pdfUrl;
    // 编写自定义下载、预览逻辑
    console.log('捕获到PDF下载链接', pdfUrl);
  }}
/>

实用提示:直接修改node_modules下的代码在重装依赖时会丢失,可使用patch-package把该改动打成补丁存入项目,团队成员安装依赖时会自动应用补丁,无需额外编写独立原生模块。


方案2:JS层拦截请求判断(无原生改动,适合快速上线)

不想改动原生代码的话,可以利用onShouldStartLoadWithRequest回调拦截所有跳转请求,通过链接后缀匹配、发送HEAD请求校验响应头Content-Type的方式识别PDF资源:

  • 给WebView组件添加onShouldStartLoadWithRequest回调,实现拦截逻辑:
const handleShouldStartLoad = async (request) => {
  const { url } = request;
  // 优先匹配带.pdf后缀的链接,减少不必要的网络请求
  if (url.includes('.pdf')) {
    console.log('捕获到PDF链接', url);
    // 处理下载/预览逻辑,返回false阻止WebView直接加载该资源
    return false;
  }
  // 对无pdf后缀的链接,发送HEAD请求校验响应类型
  try {
    const headRes = await fetch(url, { method: 'HEAD' });
    const contentType = headRes.headers.get('Content-Type');
    if (contentType?.includes('application/pdf')) {
      console.log('捕获到无后缀PDF链接', url);
      // 处理下载/预览逻辑
      return false;
    }
  } catch (err) {
    // 请求校验失败时直接放行,避免影响正常页面跳转流程
  }
  return true;
};
  • 将回调挂载到WebView组件上:
<WebView
  onNavigationStateChange={handleWebViewNavigationStateChange}
  onShouldStartLoadWithRequest={handleShouldStartLoad}
  source={{uri: my_url_link}}
  style={styles.webviewStyles}
/>

注意:该方案存在兼容性缺陷,如果目标站点配置了防盗链、跨域限制,HEAD请求会被拦截导致判断失效,仅适合站点规则完全可控的内部业务场景。


内容的提问来源于stack exchange,提问作者Miguel Angel Ortega

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 20:57:16