前言
最近在研究如何在应用程序中嵌入Web视图,发现有两个库不错。
一个是官方维护、一个是第三方维护。因为没说特别的需求,就使用了官方库,实现一些简单功能是完全ok的
webview_flutter
不建议使用,因为效果不怎么样,当然也可能是我太菜不会用,下面这个问题就很难理解为什么会这样?
基本使用
官方文档
https://pub-web.flutter-io.cn/packages/webview_flutter
安装
flutter pub add webview_flutter
加载并显示web
可以加载html字符串,也可以直接加载url链接。官方都提供了对应的方法,这里演示加载url
- 初始化
late WebViewController webViewController;//初始化void initState() {super.initState();webViewController = WebViewController()..setJavaScriptMode(JavaScriptMode.unrestricted);}
- 显示
显示的时候一般需要结合FutureBuilder
,比较这是一个异步的过程
FutureBuilder(// 异步方法future: searchNovelFromWeb(),builder: (context, snapshot) {// 等待状态显示的widgetif (snapshot.connectionState == ConnectionState.waiting) {return const Center(child: CircularProgressIndicator(),);// 错误时显示的widget} else if (snapshot.hasError) {return const Text('Error');} else {return snapshot.data ?? const Text('No data');}}))Future<Widget> searchNovelFromWeb() async {Widget res;try {await webViewController.loadRequest(Uri.parse('https://m.bbxxxxxx.com/s?q=凡人修仙'));res = WebViewWidget(controller: webViewController);} catch (error) {res = Text("加载失败:${error.toString()}");print("加载失败:${error.toString()}");}return res;}
flutter与web之间的交互
flutter通知web,让web执行某些操作
官方提供了两个方法:runJavaScript
、runJavaScriptReturningResult
。后者可以向flutter返回执行结果
比如在网页加载完成后获取到网页源代码
webViewController.setNavigationDelegate(NavigationDelegate(onPageFinished: (url) async {print("页面加载完成:$url");var html = await webViewController.runJavaScriptReturningResult("document.documentElement.innerText;");debugPrint("结果是11:$html", wrapWidth: 1024);}));
web发生变化后,通知flutter
这块也实现了,但是不太稳定,有时候不能够正常运行
await webViewController.loadRequest(Uri.parse('https://m.bbxxxxxxxt.com/s?q=凡人修仙'));webViewController.setNavigationDelegate(NavigationDelegate(onPageFinished: (url) async {print("页面加载完成:$url");// 添加监听await webViewController.addJavaScriptChannel('Report',onMessageReceived: (JavaScriptMessage message) {print("收到了消息,是:${message.message}");});// 注入脚本await webViewController.runJavaScript('''setInterval(() => {let time = new Date().toLocaleTimeString();Report.postMessage(time);},1000)''');}));
flutter_inappwebview
功能更多,这里只会简单介绍一下,具体使用可以查看官方文档、官方案例。
强烈推荐:功能更多,而且原来使用webview_flutter
无法实现的功能,现在轻而易举的实现了。
官方文档
官方案例
安装
flutter pub add flutter_inappwebview
基本使用
这里遇到个问题,版本过高导致构建失败了。我现在用的版本是:5.6.0
// 将html字符串解析为dom的库
import 'package:html/parser.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';late InAppWebViewController inAppWebViewController;
res = InAppWebView(initialUrlRequest:URLRequest(url: Uri.parse('https://onion.inscode.cc/')),onLoadStop: (controller, url) async {// 加载完成inAppWebViewController = controller;print("加载地址:$url");var html = await controller.getHtml();debugPrint("html是:${html.toString().trim()}");var dom = parse(html);print("标题是:${dom.querySelector('.title')?.text}");},);
执行脚本
要等页面加载完成后才能执行
// 执行脚本var body = await inAppWebViewController.evaluateJavascript(source: "document.body.innerHTML");debugPrint("执行结果:${body.toString().trim()}");
遇到的问题
最开始我的想法是执行函数,然后更新要显示的组件,但是resBody
一直没有更新。后来发现好像是onLoadStop
没有执行,仔细思考后应该是InAppWebView
初始化后,没有在页面上显示导致后续方法没有执行。解决方法就是让InAppWebView
在页面上显示,当然可能不想在页面显示,这时给它父容器设置一个高度比如1,这样就可以解决这个问题。
Future searchNovelFromWeb() async {String html = '';InAppWebView(initialUrlRequest:URLRequest(url: Uri.parse('https://onion.inscode.cc/')),onLoadStop: (controller, url) async {inAppWebViewController = controller;print("开始搜索了");html = await inAppWebViewController.getHtml() ?? '1111';debugPrint("查询的值:${html.toString()}");setState(() {resBody = const Text("搜索完成");});},);}