使用 Flutter InAppWebView 创建 WebView 内容拦截器
- 发表于
- 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 :忽略以前触发的操作。 查看每种特定类型的代码文档,了解哪个平台支持它。 创建简单的广告拦截器
查看每种特定类型的代码文档,了解哪个平台支持它。
创建简单的广告拦截器
让我们使用我们学到的知识创建一个简单的广告拦截器。
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。
单击“禁用/启用”按钮以禁用或启用广告拦截器功能。
结论
内容拦截器允许我们编写高性能规则来阻止 WebView 中的内容,同时尊重用户的隐私。
原文连接
的情况下转载,若非则不得使用我方内容。