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,
      ),
    );
  }
}
        
      
            
            
            
