V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
• 请不要在回答技术问题时复制粘贴 AI 生成的内容
Mistsink
V2EX  ›  程序员

怎么用原生开发使 react native 实现对 webview 的广告拦截

  •  
  •   Mistsink · 15 天前 · 1038 次点击

    如题,我使用 expo 开发 react native 应用时,使用 react-native-webview 作为 RN 中的 Webview 组件。希望能够使用如 ghostery/adblocker 这样的第三方库来完成广告拦截。但是发现这个 Webview 组件没有开放什么接口可以拦截或者获取一个网页中所有的资源请求,如各种 js 文件,css 文件,这些资源请求没法拦截,所以没法使用 adblocker 完成相应的拦截。

    我有一个想法能不能使用原生开发,替换 android 、ios 底层的 webview 组件,然后开放几个函数用于 onLoadStart 、onLoadEnd ,这几个函数可以在 RN 层级中作为参数传给 Webview 组件。这个方案是否可行呢?如果可行的话我的顾虑是:RN 中使用的 react-native-webview 的 webview 组件会不会是自己在底层替换的 webview 组件呢?如果不是,这个应该怎么解决呢?

    如果解决思路有问题,非常想请教大家有没有更好的思路呢?

    16 条回复    2024-12-05 16:19:20 +08:00
    mxT52CRuqR6o5
        1
    mxT52CRuqR6o5  
       15 天前
    用 injectedJavaScriptBeforeContentLoaded 注入 js 代码,hook 会导致资源加载的 api 并 MutationObserver 监视资源加载,进行阻止,不知道行不行
    Mistsink
        2
    Mistsink  
    OP
       15 天前
    @mxT52CRuqR6o5 MutationObserver 只能监听 dom 变化吧,不能监听网络请求呢,这个应该没法做到广告拦截的效果呢,我看主流的那些方案都是拦截网络请求+注入 css+注入 js 来实现的。现在的难点就是怎么拦截所有的网络请求。
    mxT52CRuqR6o5
        3
    mxT52CRuqR6o5  
       15 天前
    @Mistsink #2 加载 css 、js 通常需要把 link 、script 标签加载到 html 里(但我不清楚 html 首屏的 script 标签 MutationObserver 能不能监听到)
    Mistsink
        4
    Mistsink  
    OP
       15 天前
    @mxT52CRuqR6o5 这里感觉不好控制呢,一旦 MutationObserver 创建的慢了就会漏掉很多,而且可能也会造成性能压力。你觉得呢?
    br_wang
        5
    br_wang  
       15 天前
    @Mistsink #4 MutationObserver 创建前先对现有的 DOM 标签筛选、处理一遍?
    Mistsink
        6
    Mistsink  
    OP
       15 天前
    @br_wang 这种方案我觉着可能有些 hack 呢,不好接入现成的拦截方案。
    ltaoo1o
        7
    ltaoo1o  
       15 天前
    没用过 react-native-webview ,用过 flutter-inappwebivew ,思路应该类似。

    1. FlutterInAppWebivew
    2. Windows Webview2 (原生组件)

    在 flutter 端调用 webview 组件并传入 shouldInterceptRequest 属性,此时原生代码调用 Webiview2 ,Webview2 调用 add_WebResourceRequestd 方法可以监听所有网络请求
    https://github.com/pichillilorenzo/flutter_inappwebview/blob/master/flutter_inappwebview_windows/windows/in_app_webview/in_app_webview.cpp#L874

    并调用 flutter 传入的 shouldInterceptRequest
    https://github.com/pichillilorenzo/flutter_inappwebview/blob/master/flutter_inappwebview_windows/windows/in_app_webview/in_app_webview.cpp#L945

    在回调中判断 shouldInterceptRequest 是否有返回值,如果没有就不响应(等于拦截了请求),也可以修改响应(返回自定义结果)
    上面是 Windows 代码,它还有 ios 和 android 不过我没用上,你可以参考他的原生代码那块。

    另外 flutter-inappwebivew 内置了 ad block 功能,也可以参考他是怎么实现的
    https://github.com/pichillilorenzo/flutter_inappwebview_examples/tree/main/webview_ad_blocker
    br_wang
        8
    br_wang  
       15 天前
    @Mistsink #6 最后都是一遍一遍扫,只是补齐触发时机点而已。针对 ad 的现有拦截方案也都是这个思路吧。
    Mistsink
        9
    Mistsink  
    OP
       15 天前
    @br_wang 明白,也可以实现,但有的情况,就比如一个 script 标签,我应该拦截他,不能让他加载,但是这种方案不能保证我在他加载运行之前就把他删掉吧?
    Mistsink
        10
    Mistsink  
    OP
       15 天前
    @li1218040201 是,我记得好像 flutter 是开放了这种细粒度的接口,可以针对每个资源的网络请求决定是否拦截,但是 RN 的 webview 没有这种细粒度的,就只有这个网页要不要加载。
    我是不是还得像题目里说的那样去改 rn 的 webview 源码,用原生去写呐😂
    daysv
        11
    daysv  
       15 天前
    注入 service worker , 然后统一拦截
    br_wang
        12
    br_wang  
       15 天前
    @Mistsink #9 不光外部脚本会插广告,网站自己内部脚本也会啊。纯靠脚本拦截,就无法拦截网站自己脚本插入的广告吧。
    Mistsink
        13
    Mistsink  
    OP
       15 天前
    @br_wang 嗷那也确实,写在 script 里面的 js 那是没法拦截了,后面我试试扫一遍再注入 js 的法子。
    @daysv webview 中也可以注入 service worker 吗? service worker 不是浏览器自己整的一个独立的 js 进程吗?这块我不太懂 hhh ,不清楚能不能把别的扩展的 service worker 直接拿来用
    Mistsink
        14
    Mistsink  
    OP
       15 天前
    @br_wang 破案了,根据 html 中的 dom 标签,然后注入相应的 css 和 js 行不通呢,我是拿 https://adblock-tester.com/测试的,分数没变
    ltaoo1o
        15
    ltaoo1o  
       15 天前
    我看了下 API 文档,有个 onShouldStartLoadWithRequest ,具体说明就是可以决定是否继续某个请求,看 issue 也有人问 https://github.com/react-native-webview/react-native-webview/issues/286 ,也是说用这个 API ,这个试试看呢?
    Mistsink
        16
    Mistsink  
    OP
       15 天前
    @li1218040201 hh 就是这个不行呢,只有网页加载时候执行一次,里面的 js 等资源请求时不会触发
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2068 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 22ms · UTC 00:42 · PVG 08:42 · LAX 16:42 · JFK 19:42
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.