WebView 是一种可以在移动应用或桌面应用中嵌入网页内容的组件。
一、功能特点
二、应用场景
flutter_webview 是 Flutter 中的插件,用于在应用中显示网页内容。它能加载指定 URL、支持 JavaScript 与 Dart 交互、提供导航控制等功能,具有跨平台、简洁易用、性能优化等优势,但使用时要注意安全、兼容性和性能调优问题。
打开项目下的pubspec.yaml 文件, 在dependencies 下写入以下内容
dependencies:
flutter:
sdk: flutter
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^1.0.8
webview_flutter: ^4.10.0 class _MyHomePageState extends State<MyHomePage> {
WebViewController? _webViewController; // WebView 的控制器
}class _MyHomePageState extends State<MyHomePage> {
WebViewController? _webViewController; // WebView 的控制器
@override
void initState() {
super.initState();
// 初始化 WebViewController
_initializeWebView();
}
// 初始化 WebView 的方法
Future<void> _initializeWebView() async {
// 确保 WebView 已经初始化
_webViewController = WebViewController()
..setJavaScriptMode(JavaScriptMode.unrestricted) // 允许 JavaScript
..setBackgroundColor(const Color(0x00000000)) // 设置透明背景
..loadRequest(Uri.parse('https://flutter.dev')); // 加载初始 URL
}
} // 初始化 WebView 的方法
Future<void> _initializeWebView() async {
// 确保 WebView 已经初始化
_webViewController = WebViewController()
..setJavaScriptMode(JavaScriptMode.unrestricted) // 允许 JavaScript
..setBackgroundColor(const Color(0x00000000)) // 设置透明背景
..setNavigationDelegate(
NavigationDelegate(
onProgress: (progress) {
setState(() {
_progress = progress; // 更新加载进度
});
},
onPageStarted: (url) {
// 页面开始加载时调用
},
onPageFinished: (url) {
// 页面加载完成时调用
},
onWebResourceError: (error) {
// 处理网页资源错误(例如,显示错误消息)
},
onNavigationRequest: (request) {
// 阻止导航到 YouTube 链接
if (request.url.startsWith('https://www.youtube.com/')) {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: const Text('提示'),
content: const Text('该站点(YouTube)被拦截,无法访问'),
actions: [
TextButton(
child: const Text('确定'),
onPressed: () {
Navigator.of(context).pop();
},
),
],
);
});
return NavigationDecision.prevent;
}
return NavigationDecision.navigate; // 允许导航到其他 URL
},
),
)
..loadRequest(Uri.parse('https://flutter.dev')); // 加载初始 URL
}我们通过onNavigationRequest回调函数, 捕获到request,通过判断request 的 url 是否以
https://www.youtube.com/开头, 将所有www.youtube.com/ 开头的请求url 进行拦截.
WebViewController类
_webViewController = WebViewController() -> 控制主机平台提供的 WebView。
将其传递给WebViewWidget以显示 WebView。
一个WebViewController一次只能被一个WebViewWidget使用。
setJavaScriptMode方法 设置 WebView 使用的 JavaScript 执行模式。
两种模式的说明 (借助ai打比方: 以下是对两种 JavaScript 模式的间接说明:
方法定义, 其中url为必传参数, 剩下的method,headers,body为命名可选参数,可传可不传. 该方法会发送特定的Http 请求并在webview中加载响应
Future<void> loadRequest(
Uri uri, {
LoadRequestMethod method = LoadRequestMethod.get,
Map<String, String> headers = const <String, String>{},
Uint8List? body,
})主要用来设置包含在导航事件期间可调用的一些回调方法的. 该方法传入了一个NavigationDelegate类型的参数
Future<void> setNavigationDelegate(NavigationDelegate delegate) {
return platform.setPlatformNavigationDelegate(delegate.platform);
}NavigationDelegate的一些回调函数
import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
// 这是应用程序的根部件
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
// 设置应用的颜色方案
colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue.shade200),
useMaterial3: true, // 启用 Material 3
),
home: const MyHomePage(title: 'Flutter WebView Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
final String title;
const MyHomePage({super.key, required this.title});
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
WebViewController? _webViewController; // WebView 的控制器
int _progress = 0; // 加载进度
@override
void initState() {
super.initState();
// 初始化 WebViewController
_initializeWebView();
}
// 初始化 WebView 的方法
Future<void> _initializeWebView() async {
// 确保 WebView 已经初始化
_webViewController = WebViewController()
..setJavaScriptMode(JavaScriptMode.unrestricted) // 允许 JavaScript
..setBackgroundColor(const Color(0x00000000)) // 设置透明背景
..setNavigationDelegate(
NavigationDelegate(
onProgress: (progress) {
setState(() {
_progress = progress; // 更新加载进度
});
},
onPageStarted: (url) {
// 页面开始加载时调用
},
onPageFinished: (url) {
// 页面加载完成时调用
},
onWebResourceError: (error) {
// 处理网页资源错误(例如,显示错误消息)
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: const Icon(Icons.error),
content: Text('加载网页失败,错误信息:${error.description}'),
actions: [
TextButton(
child: const Text('确定'),
onPressed: () {
Navigator.of(context).pop();
},
),
],
);
});
},
onNavigationRequest: (request) {
// 阻止导航到 YouTube 链接
if (request.url.startsWith('https://www.youtube.com/')) {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: const Text('提示'),
content: const Text('该站点(YouTube)被拦截,无法访问'),
actions: [
TextButton(
child: const Text('确定'),
onPressed: () {
Navigator.of(context).pop();
},
),
],
);
});
return NavigationDecision.prevent;
}
return NavigationDecision.navigate; // 允许导航到其他 URL
},
),
)
..loadRequest(Uri.parse('https://fl1utter.dev')); // 加载初始 URL
}
// 定义一个刷新页面的方法
void _reloadPage() {
if (_webViewController != null) {
_webViewController!.reload();
}
}
// 定义一个方法 跳转到
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: Center(
child: Text(
widget.title,
style: const TextStyle(fontSize: 16),
),
),
actions: [
IconButton(
icon: const Icon(Icons.refresh),
onPressed: _reloadPage,
),
],
),
body: Center(
child: _webViewController == null
? const CircularProgressIndicator() // 显示加载指示器
: Stack(
children: [
WebViewWidget(controller: _webViewController!),
if (_progress < 100)
LinearProgressIndicator(
value: _progress / 100,
backgroundColor: Colors.white,
color: Colors.red,
),
],
),
),
);
}
}

