赞
踩
人气很高的flutter_webview_plugin,在打开多个WebView时会出错,而且缺少2个重要的功能:
虽然该插件不够完整,但是使用起来很方便,封装了很多功能,如果交互不多可以用该插件。
本文基于flutter官方webview_flutter实现JsBridge的简单封装,实现在H5页面点击按钮调起flutter弹窗,具体步骤如下:
Add this to your package’s pubspec.yaml file:
dependencies:
webview_flutter: ^0.3.22+1
You can install packages from the command line with Flutter:
$ flutter pub get
Alternatively, your editor might support flutter pub get. Check the docs for your editor to learn more.
Now in your Dart code, you can use:
import 'package:webview_flutter/webview_flutter.dart';
<key>io.flutter.embedded_views_preview</key>
<string>YES</string>
否则报错:
[VERBOSE-2:shell.cc(207)] Dart Error: Unhandled exception:
PlatformException(unregistered_view_type, trying to create a view with an unregistered type, unregistered view type: ‘plugins.flutter.io/webview’)
#0 StandardMethodCodec.decodeEnvelope (package:flutter/src/services/message_codecs.dart:569:7)
#1 MethodChannel.invokeMethod (package:flutter/src/services/platform_channel.dart:321:33)
#2 PlatformViewsService.initUiKitView (package:flutter/src/services/platform_views.dart:168:41)
#3 _UiKitViewState._createNewUiKitView (package:flutter/src/widgets/platform_view.dart:621:71)
#4 _UiKitViewState._initializeOnce (package:flutter/src/widgets/platform_view.dart:571:5)
#5 _UiKitViewState.didChangeDependencies (package:flutter/src/widgets/platform_view.dart:581:5)
#6 StatefulElement._firstBuild (package:flutter/src/widgets/framework.dart:4380:12)
#7 ComponentElement.mount (package:flutter/src/widgets/framework.dart:4208:5)
#8 Element.inf<…>
main.dart
import 'dart:async'; import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:webview_flutter/webview_flutter.dart'; import './JsBridgeUtil.dart'; const String kNavigationExamplePage = ''' <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Navigation Delegate Example</title> <style type="text/css"> .click-button { width: 300px; height: 100px; font-size: 40px; } </style> </head> <body> <p style="color: #161823; font-size: 40px"> The test of method execution from H5 to Flutter </p> <Button class="click-button" onclick="executeMethod()">点我</Button> </body> <script defer type="text/javascript"> function executeMethod() { let paramObject = { method: 'showToast', params: { message: 'User Agent: ' + navigator.userAgent } } ViaBridge.postMessage(JSON.stringify(paramObject)); } </script> </html> '''; void main() => runApp(MaterialApp(home: WebViewExample())); class WebViewExample extends StatefulWidget { @override _WebViewExampleState createState() => _WebViewExampleState(); } class _WebViewExampleState extends State<WebViewExample> { // webview 加载进度设置 final Completer<WebViewController> _controller = Completer<WebViewController>(); final String contentBase64 = base64Encode(const Utf8Encoder().convert(kNavigationExamplePage)); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Flutter WebView example'), ), body: Builder(builder: (BuildContext context) { return WebView( // 要显示的url initialUrl: 'data:text/html;base64,$contentBase64', // JS执行模式 默认是disabled javascriptMode: JavascriptMode.unrestricted, onWebViewCreated: (WebViewController webViewController) { // 在WebView创建完成后会产生一个 webViewController _controller.complete(webViewController); }, // 使用javascriptChannel JS可以调用Flutter // javascriptChannels参数接受Set<JavascriptChannel>一个成员类型为JavascriptChannel的Set集合 javascriptChannels: <JavascriptChannel>[ _toasterJavascriptChannel(context), ].toSet(), // 拦截请求 navigationDelegate: (NavigationRequest request) { if (request.url.startsWith('https://www.youtube.com/')) { print('blocking navigation to $request}'); return NavigationDecision.prevent; } print('allowing navigation to $request'); return NavigationDecision.navigate; }, onPageStarted: (String url) { print('Page started loading: $url'); }, onPageFinished: (String url) { print('Page finished loading: $url'); }, gestureNavigationEnabled: true, ); }), ); } JavascriptChannel _toasterJavascriptChannel(BuildContext context) { return JavascriptChannel( name: 'ViaBridge', onMessageReceived: (JavascriptMessage message) async{ String jsonStr = message.message; JsBridgeUtil.executeMethod(context, JsBridgeUtil.parseJson(jsonStr)); }); } }
JsBridgeUtil.dart
import 'dart:convert'; import './JsBridge.dart'; import 'package:flutter/material.dart'; /* * JsBridge执行类 **/ class JsBridgeUtil { /// 将json字符串转化成对象 static JsBridge parseJson(String jsonStr) { JsBridge jsBridgeModel = JsBridge.fromMap(jsonDecode(jsonStr)); return jsBridgeModel; } /// 向H5暴露接口调用 static executeMethod(BuildContext context, JsBridge jsBridge) async{ if (jsBridge.method == 'showToast') { Scaffold.of(context).showSnackBar( SnackBar(content: Text(jsBridge.params['message'])), ); } } }
JsBridge.dart
/* * 定义JsBridge的基本结构 **/ class JsBridge { String method; // 方法名 Map params; // 传递数据 Function callback; // 执行回调 JsBridge(this.method, this.params, this.callback); // jsonEncode方法中会调用实体类的这个方法。如果实体类中没有这个方法,会报错。 Map toJson() { Map map = new Map(); map["method"] = this.method; map["params"] = this.params; map["callback"] = this.callback; return map; } // jsonDecode(jsonStr)方法返回的是Map<String, dynamic>类型,需要这里将map转换成实体类 static JsBridge fromMap(Map<String, dynamic> map) { JsBridge jsBridgeModel = new JsBridge(map['method'], map['params'], map['callback']); return jsBridgeModel; } @override String toString() { return "JsBridge: {method: $method, params: $params, callback: $callback}"; } }
在H5页面点击按钮“点我“就可以调起flutter弹窗,展示navigator.userAgent信息
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。