使用 Flutter InAppWebView 创建 WebView 内容拦截器
2023-12-24 16:41:39 Author: www.uedbox.com(查看原文) 阅读量:25 收藏

  • 发表于
  • flutter

在本文中,我们将学习如何使用插件 flutter_inappwebview 为我们的 WebView 实例创建自定义内容拦截器。

内容拦截器通常用于拦截广告,但您也可以使用它们来拦截任何其他内容。阻止行为包括隐藏元素、阻止加载,以及在 iOS 和 macOS 上从 WebView 请求中剥离 Cookie。

请记住,一般来说,内容拦截器无法实现与 AdBlock 或 AdBlock Plus 等专用扩展程序相同级别的功能。内容阻止程序是一组规则,当 WebView 找到需要阻止的内容时,它们永远不会收到来自 WebView 的任何回调或通知。

通过 InAppWebViewSettings 类的 contentBlockers 属性,我们可以定义 WebView 将使用的 ContentBlocker 实例列表。

ContentBlocker 类

我们在 ContentBlocker 类中定义内容阻止行为。每个属性都包含一个 action 属性和一个 trigger 属性。该操作告诉 WebView 在遇到触发器匹配项时要执行的操作。触发器告诉 WebView 何时执行相应的操作。

下面是一个基本示例:

initialSettings: InAppWebViewSettings(contentBlockers: [

ContentBlocker(

   trigger: ContentBlockerTrigger(

     urlFilter: ".*",

     resourceType: [

       ContentBlockerTriggerResourceType.IMAGE,

       ContentBlockerTriggerResourceType.STYLE_SHEET

     ]

   ),

   action: ContentBlockerAction(

     type: ContentBlockerActionType.BLOCK

   )

)

]),

在此示例中,ContentBlocker 阻止加载每个 URL 的每个图像和样式表。

将触发器添加到内容拦截器

触发器必须定义必需 urlFilter 的属性,该属性将正则表达式指定为字符串以匹配 URL。其他属性是可选的,它们修改触发器的行为。例如,可以将触发器限制为特定域,或者在 WebView 找到特定域的匹配项时不应用触发器。

下面是一个内容阻止程序的示例,其中包含 WebView 在任何域上找到的图像和样式表资源的触发器,但指定的域除外:

initialSettings: InAppWebViewSettings(contentBlockers: [

ContentBlocker(

   trigger: ContentBlockerTrigger(

     urlFilter: ".*",

     resourceType: [

       ContentBlockerTriggerResourceType.IMAGE,

       ContentBlockerTriggerResourceType.STYLE_SHEET

     ],

     unlessDomain: ["example.com", "github.com", "pub.dev"]

   ),

   action: ContentBlockerAction(

     type: ContentBlockerActionType.BLOCK

   )

)

]),

要进行更深入的触发器自定义,可以使用以下属性: ContentBlockerTrigger

  • urlFilterIsCaseSensitive :如果 URL 匹配应区分大小写。默认情况下,它不区分大小写。
  • resourceType :表示规则应匹配的资源类型(浏览器打算如何使用资源)的“ContentBlockerTriggerResourceType”列表。如果未指定,则规则将匹配所有资源类型。
  • ifDomain :与URL的域匹配的字符串列表;它将操作限制为特定域的列表。对于非 ASCII 字符,值必须为小写 ASCII 或 Punycode。在前面添加 * 以匹配域和子域。它不能与 unlessDomain 一起使用。
  • unlessDomain :与URL的域匹配的字符串列表;作用于除所提供列表中的域之外的任何站点。对于非 ASCII,值必须为小写 ASCII 或 Punycode。在前面添加 * 以匹配域和子域。它不能与 ifDomain 一起使用。
  • loadType : ContentBlockerTriggerLoadType 该列表可以包含两个互斥值之一。如果未指定,则规则将匹配所有荷载类型。 ContentBlockerTriggerLoadType.FIRST_PARTY 仅当资源与主页资源具有相同的方案、域和端口时才会触发。 ContentBlockerTriggerLoadType.THIRD_PARTY 如果资源与主页资源不来自同一域,则触发。
  • ifTopUrl :与整个主文档 URL 匹配的字符串列表;它将操作限制为特定的 URL 模式列表。对于非 ASCII 字符,值必须为小写 ASCII 或 Punycode。它不能与 unlessTopUrl 一起使用。
  • unlessTopUrl :与整个主文档 URL 匹配的字符串数组;它作用于除所提供列表中的 URL 模式之外的任何站点。对于非 ASCII 字符,值必须为小写 ASCII 或 Punycode。它不能与 ifTopUrl 一起使用。
  • loadContext :指定加载上下文的字符串数组。
  • ifFrameUrl :用于匹配 iframe 的 URL 的正则表达式列表。

查看每个特定属性的代码文档,了解哪个平台支持该功能。

向内容拦截器添加操作

当触发器与资源匹配时,WebView 会评估所有触发器并按顺序执行操作。

将具有类似操作的规则组合在一起以提高性能。例如,首先指定阻止内容加载的规则,然后指定阻止 Cookie 的规则。

操作只有两个有效属性: type 和 selector 。操作类型是必需的。

如果类型为 ContentBlockerActionType.CSS_DISPLAY_NONE ,则 a selector 也是必需的;否则,是可选的 selector 。

下面是一个简单的示例:

initialSettings: InAppWebViewSettings(contentBlockers: [

ContentBlocker(

   trigger: ContentBlockerTrigger(

     urlFilter: "https://flutter.dev/.*",

   ),

   action: ContentBlockerAction(

     type: ContentBlockerActionType.CSS_DISPLAY_NONE,

     selector: '.notification, .media, #developer-story'

   )

)

]),

有效类型包括:

  • BLOCK :停止加载资源。如果缓存了资源,则忽略缓存。
  • BLOCK_COOKIES :在将 cookie 发送到服务器之前,从标头中去除 cookie。这只会阻止 WebView 的隐私政策可接受的 cookie。结合 BLOCK_COOKIES IGNORE_PREVIOUS_RULES 使用不会覆盖浏览器的隐私设置。
  • CSS_DISPLAY_NONE :根据 CSS 选择器隐藏页面元素。选择器字段包含选择器列表。任何匹配元素的 display 属性都设置为 none,这将隐藏它。
  • MAKE_HTTPS :将 URL 从 http 更改为 https 。具有指定(非默认)端口的 URL 和使用其他协议的链接不受影响。
  • IGNORE_PREVIOUS_RULES :忽略以前触发的操作。 查看每种特定类型的代码文档,了解哪个平台支持它。 创建简单的广告拦截器

查看每种特定类型的代码文档,了解哪个平台支持它。

创建简单的广告拦截器

让我们使用我们学到的知识创建一个简单的广告拦截器。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

import 'package:flutter/foundation.dart';

import 'package:flutter/material.dart';

import 'package:flutter_inappwebview/flutter_inappwebview.dart';

Future main() async {

WidgetsFlutterBinding.ensureInitialized();

if (!kIsWeb &&

     kDebugMode &&

     defaultTargetPlatform == TargetPlatform.android) {

   await InAppWebViewController.setWebContentsDebuggingEnabled(kDebugMode);

}

runApp(const MaterialApp(home: MyApp()));

}

class MyApp extends StatefulWidget {

const MyApp({Key? key}) : super(key: key);

@override

State<MyApp> createState() => _MyAppState();

}

class _MyAppState extends State<MyApp> {

final GlobalKey webViewKey = GlobalKey();

// list of ad URL filters to be used to block ads from loading

final adUrlFilters = [

   ".*.doubleclick.net/.*",

   ".*.ads.pubmatic.com/.*",

   ".*.googlesyndication.com/.*",

   ".*.google-analytics.com/.*",

   ".*.adservice.google.*/.*",

   ".*.adbrite.com/.*",

   ".*.exponential.com/.*",

   ".*.quantserve.com/.*",

   ".*.scorecardresearch.com/.*",

   ".*.zedo.com/.*",

   ".*.adsafeprotected.com/.*",

   ".*.teads.tv/.*",

   ".*.outbrain.com/.*"

];

final List<ContentBlocker> contentBlockers = [];

var contentBlockerEnabled = true;

InAppWebViewController? webViewController;

@override

void initState() {

   super.initState();

   // for each ad URL filter, add a Content Blocker to block its loading

   for (final adUrlFilter in adUrlFilters) {

     contentBlockers.add(ContentBlocker(

         trigger: ContentBlockerTrigger(

           urlFilter: adUrlFilter,

         ),

         action: ContentBlockerAction(

           type: ContentBlockerActionType.BLOCK,

         )));

   }

   // apply the "display: none" style to some HTML elements

   contentBlockers.add(ContentBlocker(

       trigger: ContentBlockerTrigger(

         urlFilter: ".*",

       ),

       action: ContentBlockerAction(

           type: ContentBlockerActionType.CSS_DISPLAY_NONE,

           selector: ".banner, .banners, .ads, .ad, .advert")));

}

@override

Widget build(BuildContext context) {

   return Scaffold(

       appBar: AppBar(

         title: const Text("Ads Content Blocker"),

         actions: [

           TextButton(

             onPressed: () async {

               contentBlockerEnabled = !contentBlockerEnabled;

               if (contentBlockerEnabled) {

                 await webViewController?.setSettings(

                     settings: InAppWebViewSettings(

                         contentBlockers: contentBlockers));

               } else {

                 await webViewController?.setSettings(

                     settings: InAppWebViewSettings(contentBlockers: []));

               }

               webViewController?.reload();

               setState(() {});

             },

             style: TextButton.styleFrom(foregroundColor: Colors.white),

             child: Text(contentBlockerEnabled ? 'Disable' : 'Enable'),

           )

         ],

       ),

       body: SafeArea(

           child: Column(children: <Widget>[

         Expanded(

           child: Stack(

             children: [

               InAppWebView(

                 key: webViewKey,

                 initialUrlRequest:

                     URLRequest(url: WebUri('https://www.tomshardware.com/')),

                 initialSettings:

                     InAppWebViewSettings(contentBlockers: contentBlockers),

                 onWebViewCreated: (controller) {

                   webViewController = controller;

                 },

               ),

             ],

           ),

         ),

       ])));

}

}

使用这些规则将阻止大量广告出现,例如 Google Ads。

单击“禁用/启用”按钮以禁用或启用广告拦截器功能。

使用 Flutter InAppWebView 创建 WebView 内容拦截器

结论

内容拦截器允许我们编写高性能规则来阻止 WebView 中的内容,同时尊重用户的隐私。

GitHub 上提供了完整的项目代码。这就是今天的全部内容 via


文章来源: https://www.uedbox.com/post/69387/
如有侵权请联系:admin#unsafe.sh