native_webviewは、WebViewの機能をWebで提供するのは難しいのでWebには今の所対応していない。だが、対応していないプラットフォームでも自前で実装すれば一応動かせるようにはなっている。(というか0.28.0から動かせるようにした)
// Webのときのみsetする
WebView.platform = AppWebView();
HtmlElementView を使って AppWebView()
をつくる。
import 'dart:html'; import 'dart:ui' as ui; import 'package:flutter/foundation.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/services.dart'; import 'package:flutter/widgets.dart'; import 'package:native_webview/native_webview.dart'; import 'package:native_webview/platform_interface.dart'; class AppWebView extends PlatformWebView { @override Widget build({ @required BuildContext context, @required CreationParams creationParams, @required String viewType, @required PlatformViewCreatedCallback onPlatformViewCreated, @required Set<Factory<OneSequenceGestureRecognizer>> gestureRecognizers, bool useHybridComposition = true, }) { if (creationParams.widget.initialData.data.isNotEmpty) { return _DataWebView(data: creationParams.widget.initialData.data); } return _UrlWebView(url: creationParams.widget.initialUrl); } } class _UrlWebView extends StatefulWidget { final String url; const _UrlWebView({Key key, this.url}) : super(key: key); @override State<StatefulWidget> createState() => _UrlWebViewState(); } class _UrlWebViewState extends State<_UrlWebView> { @override void initState() { ui.platformViewRegistry.registerViewFactory( "${WebView.viewType}-iframe-${widget.url}", (int viewId) { // ignore: unsafe_html return IFrameElement()..src = widget.url; }, ); super.initState(); } @override Widget build(BuildContext context) { return HtmlElementView( viewType: "${WebView.viewType}-iframe-${widget.url}", ); } } class _DataWebView extends StatefulWidget { final String data; const _DataWebView({Key key, this.data}) : super(key: key); @override State<StatefulWidget> createState() => _DataWebViewState(); } class _DataWebViewState extends State<_DataWebView> { @override void initState() { ui.platformViewRegistry.registerViewFactory( "${WebView.viewType}-data-${widget.data.hashCode}", (int viewId) { // ignore: unsafe_html return DivElement()..innerHtml = widget.data; }, ); super.initState(); } @override Widget build(BuildContext context) { return HtmlElementView( viewType: "${WebView.viewType}-data-${widget.data.hashCode}", ); } }
このように差し込める形にしておくと対応していないプラットフォームでもライブラリ利用者が対応しようと思えば出来るので便利。
ちなみに dart:ui の platformViewRegistry は mobile でビルドするとエラーになる。import の部分で if (dart.library.html)
などを使って出し分けるとビルド時のエラーにはならない。
// app_webview.dart import 'mobile_app_webview.dart' if (dart.library.html) "web_app_webview.dart";
// mobile_app_webview.dart import 'package:flutter/src/foundation/basic_types.dart'; import 'package:flutter/src/gestures/recognizer.dart'; import 'package:flutter/src/widgets/framework.dart'; import 'package:native_webview/platform_interface.dart'; import 'package:native_webview/src/webview.dart'; class AppWebView extends PlatformWebView { @override Widget build({ BuildContext context, CreationParams creationParams, String viewType, onPlatformViewCreated, Set<Factory<OneSequenceGestureRecognizer>> gestureRecognizers, bool useHybridComposition = true, }) { throw UnimplementedError("not support"); } }
しかし、これだとIDEやLintではエラーが出っぱなしなのでignoreする必要がある。Dart 2.12では unsafe_htmlやundefined_prefixed_nameは行単位のignoreができないので、全体でignoreするかファイルをlintの対象外から外す必要がある。
Dart 2.13以降ではどうにか出来るようになりそうなので、それを待ちたい。
analyzer: Introduce cannot-ignore analysis option. · dart-lang/sdk@97cd131 · GitHub
またそもそもpackageに分ける方法もあるがめんどいのでやっていない。 ちなみに universal_ui | Flutter Package というのがあるがメンテナンスされていなさそう+リポジトリが消えているので使えるかは不明。
個人的にはunivarsalではなく dart:ui の web特有のものを切り出したpackageを作るのが一番筋がいい気がしている。誰か頼む。