С выходом Flutter 2.0 одной из самых ожидаемых новинок стало обновление, связанное с Add-to-App
. Вместе с горячими обновлениями Flutter наиболее часто критиковался за плохое качество гибридной разработки, то есть совмещение Flutter приложений с нативными.
Почему это плохо? Потому что компоненты Flutter отрисовываются вне контекста платформы, то есть стек страниц и дерево отрисовки работают независимо от платформы. Это обеспечивает хорошее кросс-платформенное взаимодействие, но создаёт проблемы высокой стоимости при работе с нативными платформами.
Не говоря уже о том, чтобы интегрировать Flutter в существующий нативный проект, даже в текущей версии Flutter, когда мы пытаемся интегрировать нативные компоненты в Flutter через PlatformView и Hybrid Composition, опыт использования этих технологий требует улучшения. Конечно же, наличие поддержки и возможность использования — уже значительный шаг вперёд.
Поэтому Flutter 2.0 был выпущен с FlutterEngineGroup
, который официально поддерживает решение "Добавьте Flutter в существующее приложение".
Перед появлением этого решения были различные сторонние реализации, такие как flutter_boost
, mix_stack
, flutter_thrio
и так далее. Здесь не будем обсуждать, насколько они хороши, но эти решения сталкиваются с проблемой:> Несоответствие между официальной поддержкой и каждым выпуском может привести к необходимости адаптации каждого нового выпуска. Учитывая скорость закрытия issues
и слияния pull requests
в Flutter, каждый новый выпуск может содержать значительные изменения. Если разработчики не будут своевременно поддерживать эти фреймворки, они могут стать бутылочным neck'ом для проекта.
Имеют ли недостатки официальное решение FlutterEngineGroup
? Безусловно, оно пока выглядит скоропостижно созданным решением, и некоторые проблемы все еще остаются, например, некоторые объекты не могут быть удалены (destroy
). (Конечно, эта проблема была решена и слита в основной ветке.)
Однако предоставляемое официальным путем решение означает, что этот дизайн получил одобрение со стороны команды Flutter, что обеспечит обратную совместимость в будущих версиях.
Решение FlutterEngineGroup
использует многоконтекстную модель, где официально заявлено, что каждый последующий контекст занимает всего 180 kB на Android и iOS помимо первого контекста.
По сравнению с предыдущими решениями, каждый дополнительный контекст мог увеличивать использование памяти до 19 MB на Android и 13 MB на iOS.На основе примеров, предоставленных официальными представителями Flutter, можно сказать, что API
FlutterEngineGroup
очень просты, каждый контекст Flutter поддерживает свой внутренний стек навигации, поэтому каждый контекст может представлять собой независимую часть приложения. ИспользованиеFlutterEngineGroup
позволяет генерироватьFlutterEngine
, который может независимо использоваться вFlutterActivity
/FlutterViewController
, а также вFlutterFragment
.> Таким образом, как показано в примере, вы можете отображать два независимых FlutterView на одном Activity.
Это возможно благодаря тому, что созданные с помощью FlutterEngineGroup
объекты FlutterEngine
могут поддерживать общую контекстную среду GPU, метрики шрифтов и снимок группы изолированных процессов, что обеспечивает более быстрое время старта и меньшее потребление памяти.
Ниже приведены данные использования памяти после открытия 16 страниц с использованием официального примера, при этом каждая страница успешно открывается без черного экрана.
Для начала работы с FlutterEngineGroup
необходимо создать единственный экземпляр этого класса. Затем каждый раз, когда требуется создать новый FlutterEngine
, используется метод createAndRunEngine(activity, dartEntrypoint)
.
val app = activity.applicationContext as App
// Это должно быть ленивым, чтобы избежать создания до FlutterEngineGroup.
val dartEntrypoint = DartExecutor.DartEntrypoint(FlutterInjector.instance().flutterLoader().findAppBundlePath(), entrypoint)
engine = app.engines.createAndRunEngine(activity, dartEntrypoint)
this.delegate = delegate
channel = MethodChannel(engine.dartExecutor.binaryMessenger, "multiple-flutters")
Пример кода из официального демонстрационного примера:1. Вначале через findAppBundlePath
и entrypoint
создаётся объект DartEntrypoint
. Здесь findAppBundlePath
обычно указывает на директорию flutter_assets
, а entrypoint
представляет собой имя метода запуска в Dart-коде, то есть это метод, связанный с вызовом runApp
.```dart
/// Kotlin
app.engines.createAndRunEngine(pathToBundle, "topMain")
/// Dart @pragma('vm:entry-point') void topMain() => runApp(MyApp());
2. Используя созданный выше `dartEntrypoint` и `context`, можно создать соответствующий `FlutterEngine` с помощью `FlutterEngineGroup`. На самом деле внутри происходит взаимодействие через `FlutterJNI.nativeSpawn` с существующими двигателями, чтобы получить новый Long адрес ID. Аналогично методу `RunBundleAndSnapshotFromLibrary` в C++, но он не может изменять пути к пакетам или assets, поэтому может загружать только один AOT файл. В результате получаем указатель на новый объект `AndroidShellHolder`.
3. Наконец, используем `binaryMessenger`, созданный с помощью `FlutterEngine`, чтобы получить канал `MethodChannel` для взаимодействия между нативной частью и Dart.
Полученный таким образом движок можно использовать для отрисовки нового интерфейса Flutter, например, путем наследования от `FlutterActivity` и переопределения метода `provideFlutterEngine`.
```kotlin
class SingleFlutterActivity : FlutterActivity() {
...
override fun provideFlutterEngine(context: Context?): FlutterEngine? {
return engine
}
}
Не сложно ли это было сделать? После такой простой интеграции:
MethodChannel
для открытия первоначальных страниц;FlutterEngine
для открытия новых страниц Flutter;FlutterView
из нативной части;Конечно, вы могли заметить, что каждый интерфейс Flutter представляет собой отдельный движок (Engine
). Из-за концепции дизайна Dart isolates, память каждого отдельного интерфейса Flutter не может быть совместно использована.Это значит, что при необходимости передачи данных вам придется хранить данные в нативной части и затем внедрять или передавать их в каждый интерфейс Flutter. Как говорится в официальной документации, каждый интерфейс Flutter больше похож на отдельный модуль Flutter.Конечно, это также приводит к некоторым неудобствам, например: один и тот же изображение будет загружаться несколько раз в разных Flutter Engines, что требует использования внешних текстур для управления памятью в нативной части.
Кроме того, я столкнулся с проблемами, такими как: Проблема ARM TBI на Android 11.
Однако после этой попытки我相信 FlutterEngineGroup
的进展将会越来越明朗,并且会更早地应用于实际生产环境。
Это значит, что при необходимости передачи данных вам придется хранить данные в нативной части и затем внедрять или передавать их в каждый интерфейс Flutter. Как говорится в официальной документации, каждый интерфейс Flutter больше похож на отдельный модуль Flutter.
Конечно, это также приводит к некоторым неудобствам, например: один и тот же изображение будет загружаться несколько раз в разных Flutter Engines, что требует использования внешних текстур для управления памятью в нативной части.
Кроме того, я столкнулся с проблемами, такими как: Проблема ARM TBI на Android 11.
Однако после этой попытки我相信 FlutterEngineGroup
的进展将会越来越明朗,并且会更早地应用于实际生产环境。
Это значит, что при необходимости передачи данных вам придется хранить данные в нативной части и затем внедрять или передавать их в каждый интерфейс Flutter. Как говорится в официальной документации, каждый интерфейс Flutter больше похож на отдельный модуль Flutter.
Конечно, это также приводит к некоторым неудобствам, например: один и тот же изображение будет загружаться несколько раз в разных Flutter Engines, что требует использования внешних текстур для управления памятью в нативной части.
Кроме того, я столкнулся с проблемами, такими как: Проблема ARM TBI на Android 11.
Однако после этой попытки我相信 FlutterEngineGroup
的进展将会越来越明朗,并且会更早地应用于实际生产环境。
Это значит, что при необходимости передачи данных вам придется хранить данные в нативной части и затем внедрять или передавать их в каждый интерфейс Flutter. Как говорится в официальной документации, каждый интерфейс Flutter больше похож на отдельный модуль Flutter.
Конечно, это также приводит к некоторым неудобствам, например: один и тот же изображение будет загружаться несколько раз в разных Flutter Engines, что требует использования внешних текстур для управления памятью в нативной части.
Кроме того, я столкнулся с проблемами, такими как: Проблема ARM TBI на Android 11.
Однако после этой попытки我相信 FlutterEngineGroup
的进展将会越来越明朗,并且会更早地应用于实际生产环境。
Вы можете оставить комментарий после Вход в систему
Неприемлемый контент может быть отображен здесь и не будет показан на странице. Вы можете проверить и изменить его с помощью соответствующей функции редактирования.
Если вы подтверждаете, что содержание не содержит непристойной лексики/перенаправления на рекламу/насилия/вульгарной порнографии/нарушений/пиратства/ложного/незначительного или незаконного контента, связанного с национальными законами и предписаниями, вы можете нажать «Отправить» для подачи апелляции, и мы обработаем ее как можно скорее.
Опубликовать ( 0 )