Flutter WebView插件webview_flutter_wkwebview_pagecall的使用
Flutter WebView插件webview_flutter_wkwebview 的使用
使用说明
webview_flutter_wkwebview 是 webview_flutter 插件的 Apple WKWebView 实现。通过使用此插件,开发者可以在 Flutter 应用中轻松嵌入 WebView,并实现丰富的网页交互功能。
该插件已被官方推荐为 endorsed federated plugin,因此你可以直接使用 webview_flutter,而无需额外配置即可自动包含此插件的功能。
完整示例代码
以下是一个完整的 Flutter 示例代码,展示了如何使用 webview_flutter_wkwebview 插件来加载网页并实现一些高级功能,如导航拦截、JavaScript 通道等。
示例代码:example/lib/main.dart
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// ignore_for_file: public_member_api_docs
import 'dart:async';
import 'dart:convert';
import 'dart:typed_data';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:webview_flutter_platform_interface/webview_flutter_platform_interface.dart';
import 'navigation_decision.dart';
import 'navigation_request.dart';
import 'web_view.dart';
void main() {
runApp(MaterialApp(home: _WebViewExample()));
}
const String kNavigationExamplePage = '''
<!DOCTYPE html><html>
<head><title>Navigation Delegate Example</title></head>
<body>
<p>
The navigation delegate is set to block navigation to the youtube website.
</p>
<ul>
<ul><a href="https://www.youtube.com/">https://www.youtube.com/</a></ul>
<ul><a href="https://www.google.com/">https://www.google.com/</a></ul>
</ul>
</body>
</html>
''';
class _WebViewExample extends StatefulWidget {
const _WebViewExample({Key? key}) : super(key: key);
[@override](/user/override)
_WebViewExampleState createState() => _WebViewExampleState();
}
class _WebViewExampleState extends State<_WebViewExample> {
final Completer<WebViewController> _controller = Completer<WebViewController>();
[@override](/user/override)
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Flutter WebView 示例'),
// 显示一个下拉菜单,展示 Flutter 小部件可以覆盖 WebView
actions: <Widget>[
_NavigationControls(_controller.future),
_SampleMenu(_controller.future),
],
),
// 使用 Builder 来获取一个 Scaffold 下的上下文,以便调用 Scaffold.of(context) 显示 SnackBar
body: Builder(builder: (context) {
return WebView(
initialUrl: 'https://app.pagecall.com/meet?room_id=64c36ca02e98292a17562053',
onWebViewCreated: (WebViewController controller) {
print('onWebViewCreated!!');
_controller.complete(controller);
},
javascriptChannels: {
// 创建一个 JavaScript 通道,用于与 WebView 中的 JavaScript 进行通信
JavascriptChannel(
name: 'jurung',
onMessageReceived: (JavascriptMessage message) {
print('JavascriptChannel: $message');
}),
},
javascriptMode: JavascriptMode.unrestricted,
navigationDelegate: (NavigationRequest request) {
// 拦截导航请求,阻止访问 YouTube 网站
if (request.url.startsWith('https://www.youtube.com/')) {
print('阻止导航到 $request}');
return NavigationDecision.prevent;
}
print('允许导航到 $request');
return NavigationDecision.navigate;
},
);
}),
floatingActionButton: favoriteButton(),
);
}
Widget favoriteButton() {
return FutureBuilder<WebViewController>(
future: _controller.future,
builder: (BuildContext context, AsyncSnapshot<WebViewController> controller) {
if (controller.hasData) {
return FloatingActionButton(
onPressed: () async {
final String url = (await controller.data!.currentUrl())!;
// 忽略:deprecated_member_use
},
child: const Icon(Icons.favorite),
);
}
return Container();
});
}
}
Set<JavascriptChannel> _createJavascriptChannels(BuildContext context) {
return {
// 创建一个 JavaScript 通道,用于向用户显示 SnackBar 消息
JavascriptChannel(
name: 'Snackbar',
onMessageReceived: (JavascriptMessage message) {
ScaffoldMessenger.of(context)
.showSnackBar(SnackBar(content: Text(message.message)));
}),
};
}
enum _MenuOptions {
showUserAgent,
listCookies,
clearCookies,
addToCache,
listCache,
clearCache,
navigationDelegate,
doPostRequest,
}
class _SampleMenu extends StatelessWidget {
_SampleMenu(this.controller);
final Future<WebViewController> controller;
[@override](/user/override)
Widget build(BuildContext context) {
return FutureBuilder<WebViewController>(
future: controller,
builder:
(BuildContext context, AsyncSnapshot<WebViewController> controller) {
return PopupMenuButton<_MenuOptions>(
onSelected: (_MenuOptions value) {
switch (value) {
case _MenuOptions.showUserAgent:
_onShowUserAgent(controller.data!, context);
break;
case _MenuOptions.listCookies:
_onListCookies(controller.data!, context);
break;
case _MenuOptions.clearCookies:
_onClearCookies(controller.data!, context);
break;
case _MenuOptions.addToCache:
_onAddToCache(controller.data!, context);
break;
case _MenuOptions.listCache:
_onListCache(controller.data!, context);
break;
case _MenuOptions.clearCache:
_onClearCache(controller.data!, context);
break;
case _MenuOptions.navigationDelegate:
_onNavigationDelegateExample(controller.data!, context);
break;
case _MenuOptions.doPostRequest:
_onDoPostRequest(controller.data!, context);
break;
}
},
itemBuilder: (BuildContext context) => <
PopupMenuItem<_MenuOptions>>[
PopupMenuItem<_MenuOptions>(
value: _MenuOptions.showUserAgent,
child: const Text('显示用户代理'),
enabled: controller.hasData,
),
const PopupMenuItem<_MenuOptions>(
value: _MenuOptions.listCookies,
child: Text('列出 Cookie'),
),
const PopupMenuItem<_MenuOptions>(
value: _MenuOptions.clearCookies,
child: Text('清除 Cookie'),
),
const PopupMenuItem<_MenuOptions>(
value: _MenuOptions.addToCache,
child: Text('添加到缓存'),
),
const PopupMenuItem<_MenuOptions>(
value: _MenuOptions.listCache,
child: Text('列出缓存'),
),
const PopupMenuItem<_MenuOptions>(
value: _MenuOptions.clearCache,
child: Text('清除缓存'),
),
const PopupMenuItem<_MenuOptions>(
value: _MenuOptions.navigationDelegate,
child: Text('导航委托示例'),
),
const PopupMenuItem<_MenuOptions>(
value: _MenuOptions.doPostRequest,
child: Text('POST 请求'),
),
],
);
},
);
}
void _onShowUserAgent(
WebViewController controller, BuildContext context) async {
// 发送一条消息到 WebView 中的 JavaScript,显示用户代理字符串
await controller.runJavascript(
'Snackbar.postMessage("User Agent: " + navigator.userAgent);');
}
void _onListCookies(
WebViewController controller, BuildContext context) async {
final String cookies =
await controller.runJavascriptReturningResult('document.cookie');
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Column(
mainAxisAlignment: MainAxisAlignment.end,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
const Text('Cookies:'),
_getCookieList(cookies),
],
),
));
}
void _onAddToCache(WebViewController controller, BuildContext context) async {
await controller.runJavascript(
'caches.open("test_caches_entry"); localStorage["test_localStorage"] = "dummy_entry";');
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
content: Text('添加了一个测试条目到缓存中。'),
));
}
void _onListCache(WebViewController controller, BuildContext context) async {
await controller.runJavascript('caches.keys()'
'.then((cacheKeys) => JSON.stringify({"cacheKeys" : cacheKeys, "localStorage" : localStorage}))'
'.then((caches) => Snackbar.postMessage(caches))');
}
void _onClearCache(WebViewController controller, BuildContext context) async {
await controller.clearCache();
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
content: Text("缓存已清除。"),
));
}
void _onClearCookies(
WebViewController controller, BuildContext context) async {
final bool hadCookies = await WebView.platform.clearCookies();
String message = '存在 Cookie。现在它们已经消失了!';
if (!hadCookies) {
message = '不存在 Cookie。';
}
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text(message),
));
}
void _onNavigationDelegateExample(
WebViewController controller, BuildContext context) async {
final String contentBase64 =
base64Encode(const Utf8Encoder().convert(kNavigationExamplePage));
await controller.loadUrl('data:text/html;base64,$contentBase64');
}
void _onDoPostRequest(
WebViewController controller, BuildContext context) async {
WebViewRequest request = WebViewRequest(
uri: Uri.parse('https://httpbin.org/post'),
method: WebViewRequestMethod.post,
headers: {'foo': 'bar', 'Content-Type': 'text/plain'},
body: Uint8List.fromList('Test Body'.codeUnits),
);
await controller.loadRequest(request);
}
Widget _getCookieList(String cookies) {
if (cookies == null || cookies == '""') {
return Container();
}
final List<String> cookieList = cookies.split(';');
final Iterable<Text> cookieWidgets =
cookieList.map((String cookie) => Text(cookie));
return Column(
mainAxisAlignment: MainAxisAlignment.end,
mainAxisSize: MainAxisSize.min,
children: cookieWidgets.toList(),
);
}
}
class _NavigationControls extends StatelessWidget {
const _NavigationControls(this._webViewControllerFuture)
: assert(_webViewControllerFuture != null);
final Future<WebViewController> _webViewControllerFuture;
[@override](/user/override)
Widget build(BuildContext context) {
return FutureBuilder<WebViewController>(
future: _webViewControllerFuture,
builder:
(BuildContext context, AsyncSnapshot<WebViewController> snapshot) {
final bool webViewReady =
snapshot.connectionState == ConnectionState.done;
final WebViewController? controller = snapshot.data;
return Row(
children: <Widget>[
IconButton(
icon: const Icon(Icons.arrow_back_ios),
onPressed: !webViewReady
? null
: () async {
if (await controller!.canGoBack()) {
await controller.goBack();
} else {
// 忽略:deprecated_member_use
return;
}
},
),
IconButton(
icon: const Icon(Icons.arrow_forward_ios),
onPressed: !webViewReady
? null
: () async {
if (await controller!.canGoForward()) {
await controller.goForward();
} else {
// 忽略:deprecated_member_use
return;
}
},
),
IconButton(
icon: const Icon(Icons.replay),
onPressed: !webViewReady
? null
: () {
controller!.reload();
},
),
],
);
},
);
}
}
/// 回调类型,用于处理从 WebView 中 JavaScript 发送的消息。
typedef void JavascriptMessageHandler(JavascriptMessage message);
更多关于Flutter WebView插件webview_flutter_wkwebview_pagecall的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter WebView插件webview_flutter_wkwebview_pagecall的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
webview_flutter_wkwebview_pagecall 是一个 Flutter 插件,用于在 iOS 平台上使用 WKWebView 来加载网页内容,并且支持通过 JavaScript 与 Flutter 进行双向通信。这个插件是基于 webview_flutter 插件的一个扩展,专门为 iOS 平台提供了更强大的功能。
以下是如何使用 webview_flutter_wkwebview_pagecall 插件的基本步骤:
1. 添加依赖
首先,你需要在 pubspec.yaml 文件中添加 webview_flutter_wkwebview_pagecall 插件的依赖:
dependencies:
flutter:
sdk: flutter
webview_flutter_wkwebview_pagecall: ^1.0.0 # 请使用最新版本
然后运行 flutter pub get 来安装依赖。
2. 导入插件
在你的 Dart 文件中导入插件:
import 'package:webview_flutter_wkwebview_pagecall/webview_flutter_wkwebview_pagecall.dart';
3. 创建 WebView
使用 WebView 控件来加载网页内容。你可以通过 WebViewController 来控制 WebView 的行为。
class MyWebView extends StatefulWidget {
[@override](/user/override)
_MyWebViewState createState() => _MyWebViewState();
}
class _MyWebViewState extends State<MyWebView> {
late WebViewController _controller;
[@override](/user/override)
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('WebView Example'),
),
body: WebView(
initialUrl: 'https://flutter.dev',
onWebViewCreated: (WebViewController webViewController) {
_controller = webViewController;
},
javascriptMode: JavascriptMode.unrestricted,
onPageStarted: (String url) {
print('Page started loading: $url');
},
onPageFinished: (String url) {
print('Page finished loading: $url');
},
gestureNavigationEnabled: true,
),
);
}
}
4. JavaScript 与 Flutter 通信
webview_flutter_wkwebview_pagecall 插件允许你通过 JavaScript 与 Flutter 进行双向通信。你可以通过 WebViewController 来注册 JavaScript 通道,并在 Flutter 中处理来自 JavaScript 的消息。
[@override](/user/override)
void initState() {
super.initState();
_controller = WebViewController()
..setJavaScriptMode(JavaScriptMode.unrestricted)
..addJavaScriptChannel('Flutter', onMessageReceived: (JavaScriptMessage message) {
// 处理来自 JavaScript 的消息
print('Received message from JavaScript: ${message.message}');
})
..loadRequest(Uri.parse('https://flutter.dev'));
}
在 JavaScript 中,你可以通过 Flutter.postMessage() 来发送消息到 Flutter:
Flutter.postMessage('Hello from JavaScript!');
5. 处理页面加载事件
你可以通过 onPageStarted 和 onPageFinished 回调来处理页面加载的开始和结束事件。
onPageStarted: (String url) {
print('Page started loading: $url');
},
onPageFinished: (String url) {
print('Page finished loading: $url');
},
6. 处理手势导航
你可以通过 gestureNavigationEnabled 来启用或禁用手势导航。
gestureNavigationEnabled: true,
7. 其他功能
webview_flutter_wkwebview_pagecall 还提供了其他一些功能,例如:
- 自定义 UserAgent: 你可以通过
WebViewController来设置自定义的 UserAgent。 - Cookie 管理: 你可以通过
WebViewController来管理 WebView 中的 Cookie。 - JavaScript 执行: 你可以通过
WebViewController在 WebView 中执行 JavaScript 代码。
8. 注意事项
- iOS 平台: 这个插件是专门为 iOS 平台设计的,因此在 Android 平台上可能无法使用所有功能。
- 权限: 确保在你的
Info.plist文件中添加了必要的权限,例如网络访问权限。
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
9. 示例代码
以下是一个完整的示例代码:
import 'package:flutter/material.dart';
import 'package:webview_flutter_wkwebview_pagecall/webview_flutter_wkwebview_pagecall.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
[@override](/user/override)
Widget build(BuildContext context) {
return MaterialApp(
home: MyWebView(),
);
}
}
class MyWebView extends StatefulWidget {
[@override](/user/override)
_MyWebViewState createState() => _MyWebViewState();
}
class _MyWebViewState extends State<MyWebView> {
late WebViewController _controller;
[@override](/user/override)
void initState() {
super.initState();
_controller = WebViewController()
..setJavaScriptMode(JavaScriptMode.unrestricted)
..addJavaScriptChannel('Flutter', onMessageReceived: (JavaScriptMessage message) {
print('Received message from JavaScript: ${message.message}');
})
..loadRequest(Uri.parse('https://flutter.dev'));
}
[@override](/user/override)
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('WebView Example'),
),
body: WebView(
initialUrl: 'https://flutter.dev',
onWebViewCreated: (WebViewController webViewController) {
_controller = webViewController;
},
javascriptMode: JavascriptMode.unrestricted,
onPageStarted: (String url) {
print('Page started loading: $url');
},
onPageFinished: (String url) {
print('Page finished loading: $url');
},
gestureNavigationEnabled: true,
),
);
}
}

