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. На нём мои поиски и закончились. Ниже минимальный пример для работы с ним:

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('Ожидаем загрузки...'),
          ),
        ),
    );
  }
}

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Этот сайт использует Akismet для борьбы со спамом. Узнайте, как обрабатываются ваши данные комментариев.