Flutter: переименование пакета

Ситуация: при создании приложения было выбрано не то имя для пакета.

Решение: для решения проблемы, в pubspec.yaml добавим пакет change_app_package_name (в секцию dev_depencies), после чего в командной строке в папке приложения выполним:

flutter pub run change_app_package_name:main ru.цву.увцувцу

Flutter: событие с параметрами при использовании BLOC

Зачастую нужно вызвать не просто событие, но и передать ему параметры. Делается это примерно так:

event.dart

abstract class MyStaticEvent {}

class InitEvent extends MyStaticEvent {}
class StartUpdateList extends MyStaticEvent {} // Запущен процесс обновления списка статистики
class UpdateList extends MyStaticEvent {} // Обновить список статистики пользователя
class UpdateListFull extends MyStaticEvent {
  final DateTime startDate;
  final DateTime endDate;
  final int car;
  UpdateListFull(this.startDate,this.endDate,this.car);
} // Обновить список статистики пользователя

В нужном месте дернем вызов UpdateListFull:

            actions: [
              IconButton(
                icon: SvgPicture.asset('lib/images/galka.svg'),
                onPressed: () {
                  print("Нажманули сохранение");
                  BlocProvider.of<MyStaticBloc>(context).add(StartUpdateList());
                  BlocProvider.of<MyStaticBloc>(context).add(UpdateListFull(startDate??DateTime.now(),endDate??DateTime.now(),globals.UserInfo["default_car"]));
                  Navigator.pop(context);
                },
              ),
            ],

Ну и сам bloc.dart:

    on<UpdateListFull>((event, emit) async {
      print("FullList: $event");
      MyStaticState res = MyStaticState();
      print("--обновляем список статистики ");
      TRequests req = new TRequests();
      http.Response response;
      await Future.delayed(Duration(seconds: 2), () async {
        try {
          response=await req.asyncRequest("rfqwrferf", jsonEncode({           
            "offset" : globals.time_offset.toString(),
            "dtfrom" : globals.HumanDateFormat2(event.startDate),
            "dtto"   : globals.HumanDateFormat2(event.endDate),
            "autoes" : "[${event.car.toString()}]"
          }));
          if (response.statusCode==200) {
            Map<String, dynamic> answer = jsonDecode(response.body);
            if (answer["error"]==true){
              EasyLoading.showToast(answer["errortxt"]);
            } else {
              res.StaticList = answer["result"];
              res.loading=true;
              print("--пришел список статистики заправки автомобилей: ${res.StaticList}");
            }
          } else {
            EasyLoading.showToast("Ошибка обращения к API");
          }
          emit(res);
        } catch (e) {
          EasyLoading.showToast("Ошибка обращения к API $e");
        };
        emit(res);
      });
    });

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

Flutter: импорт всех файлов из папки

Как такового способа типа:

import '../bloc/notify/*.dart';

к сожалению нет. Чтобы включить в проект все файлы папки, можно воспользоваться небольшим трюком — создать в корне папки еще один файл с содержимым вида:

library notify;
export 'bloc.dart';
export 'event.dart';
export 'state.dart';

И уже далее, в основном проекте его добавлять как:

import '../bloc/notify/index.dart';

Flutter: архитектура BLOC

Основная идея данной архитектуры — отделить отрисовку от логики. Побочная возможность — еще один способ изменения данных виджета из другого виджета, без использования StreamController (ну на самом деле он таки используется но «внутри») и передергивания SetState

Итак, для использования нужно в pubspec.yaml добавить:

» Читать далее
1 2 3 4 10