Flutter: отображение веб страницы в виджете
Работа с webview во Flutter не так проста как на «чистом» Java/Kotlin. В основном из-за того что, на pub.dev есть большое разнообразие собственно вапперов к webview, а потому выбрать рабочую и полноценную реализацию не так просто. Я например потратил с полдня, чтобы выяснить, что:
webview_flutter — не отображает страницы с «плохими» сертификатами SSL. Например самоподписанными, или с сертификатами с истёкшим сроком действия, или с сертификатом к которому нет доверия (теперь это все сайты госучреждений и некоторых банков). И нет никакого способа (или не нашел), заставить это сделать.
flutter_inappwebview — та же самая проблема что и в вышеуказанном плагине. Да, там есть ключ «игнорировать ошибки SSL», но он не работает
flutter_webview_plugin — выпущен 21 месяц назад, и при компиляции уже ругается на отсутствие поддержки Android 12. Хотя как раз этот плагин, работает со страницами с плохим SSL именно так как нужно
flutter_webview_plugin_ios_android — а вот этот плагин, это как я понял «подхваченый из ослабеших» рук разработчиков flutter_webview_plugin, и доработаный уже под Android 12. На нём мои поиски и закончились. Ниже минимальный пример для работы с ним:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 |
import 'package:flutter/material.dart'; import 'package:flutter_webview_plugin_ios_android/flutter_webview_plugin_ios_android.dart'; import 'dart:async'; void main() { WidgetsFlutterBinding.ensureInitialized(); runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Demo', theme: ThemeData( primarySwatch: Colors.blue, ), routes: { '/': (_) => const MyHomePage(), } ); } } class MyHomePage extends StatefulWidget { const MyHomePage({super.key}); @override State<MyHomePage> createState() => _MyHomePageState(); } class _MyHomePageState extends State<MyHomePage> { String selectedUrl = 'https://грибовы.рф'; final flutterWebViewPlugin = FlutterWebviewPlugin(); // при изменении url late StreamSubscription<String> _onUrlChanged; // при ошибке late StreamSubscription<WebViewHttpError> _onHttpError; // изменение процента загрузки страницы late StreamSubscription<double> _onProgressChanged; // поскролили вверх-вниз late StreamSubscription<double> _onScrollYChanged; // поскролили вправо-влево late StreamSubscription<double> _onScrollXChanged; @override void dispose() { _onUrlChanged.cancel(); _onHttpError.cancel(); _onProgressChanged.cancel(); _onScrollXChanged.cancel(); _onScrollYChanged.cancel(); flutterWebViewPlugin.dispose(); super.dispose(); } @override void initState() { super.initState(); flutterWebViewPlugin.close(); // Слушатель изменения url страницы _onUrlChanged = flutterWebViewPlugin.onUrlChanged.listen((String url) { print("URL: $url"); }); // изменение прогресса загрузки _onProgressChanged = flutterWebViewPlugin.onProgressChanged.listen((double progress) { setState(() { print('onProgressChanged: $progress'); }); }); _onScrollYChanged = flutterWebViewPlugin.onScrollYChanged.listen((double y) { }); _onScrollXChanged = flutterWebViewPlugin.onScrollXChanged.listen((double x) { }); _onHttpError = flutterWebViewPlugin.onHttpError.listen((WebViewHttpError error) { print("Ошибка загрузки: ${error.code} ${error.url}"); }); } // перехват вызовов Javascript final Set<JavascriptChannel> jsChannels = [ JavascriptChannel( name: 'Print', onMessageReceived: (JavascriptMessage message) { print(message.message); }), ].toSet(); @override Widget build(BuildContext context) { return WebviewScaffold( ignoreSSLErrors: true, url: selectedUrl, javascriptChannels: jsChannels, mediaPlaybackRequiresUserGesture: false, appBar: AppBar( title: const Text('Widget WebView'), ), withZoom: true, withLocalStorage: true, hidden: false, initialChild: Container( color: Colors.redAccent, child: const Center( child: Text('Ожидаем загрузки...'), ), ), ); } } |