1 В избранное 0 Ответвления 0

OSCHINA-MIRROR/CarGuo-GSYFlutterBook

Присоединиться к Gitlife
Откройте для себя и примите участие в публичных проектах с открытым исходным кодом с участием более 10 миллионов разработчиков. Приватные репозитории также полностью бесплатны :)
Присоединиться бесплатно
Клонировать/Скачать
Flutter-HCPP.md 19 КБ
Копировать Редактировать Web IDE Исходные данные Просмотреть построчно История
Отправлено 10.03.2025 00:06 5767d61

Flutter внедряет новую реализацию PlatformView HCPP, используя некоторые продвинутые технологии в Android

Реализация PlatformView в кросс-платформенной разработке всегда была актуальной темой. В предыдущей статье "Глубинное сравнение реализации PlatformView в Flutter и Compose" мы подробно рассмотрели различия между Flutter и Compose в реализации PlatformView, а также причины того, почему Compose имеет преимущество при сравнимых реализациях.

С выходом версии 3.29 Flutter начал внедрять другую реализацию PlatformView для Android, которая обеспечивает лучшую производительность по сравнению с HC и временно называется HCPP.

Перед тем как говорить о HCPP, давайте вспомним модели реализации PlatformView в Flutter для Android:

  • VD: Самая старая модель, использует поддержку вторичного экрана VirtualDisplay, чтобы эмулировать отрисовку нативных компонентов и извлечение текстур в памяти.
  • HC: Прямое добавление нативных компонентов в FlutterView и использование нового FlutterImageView для предоставления поверхности Surface для сложной стековой композиции UI.
  • TLHC: Так же прямое добавление нативных компонентов в FlutterView, но с использованием родительского канваса вместо дочернего, что позволяет нативному компоненту рисовать на surface.lockHardwareCanvas.

Может показаться абстрактным? Но дальше будут простые примеры для наглядности.Каждый из этих подходов имеет свои преимущества и недостатки, например:

  • Модель TLHC не поддерживает компоненты типа SurfaceView, так как они имеют собственные поверхности Surface и канвы Canvas, которые напрямую связаны с SurfaceFlinger.
  • При использовании TLHC вместе с асинхронным обновлением View (например, TextureView или базирующемся на OpenGL рендере), требуется явное вызов invalidate для соответствующего PlatformView при каждом обновлении содержимого, например, вызов mapView.invalidate внутри метода textureView.onSurfaceTextureUpdated.
  • Модель HC может иметь проблемы с синхронностью и дополнительными затратами на производительность из-за различных версий API и проблем с потоками.

Поэтому эти три модели работают совместно, например:

  • initAndroidView: По умолчанию использует последнюю модель, то есть TLHC, и понижается до VD при необходимости! image1
  • initSurfaceAndroidView: По умолчанию использует последнюю модель, то есть TLHC, и понижается до HC при необходимости! image2
  • initExpensiveAndroidView: Принудительно использует режим HC

Теперь, вернувшись к теме нашего обсуждения, в связи с новой реализацией HCPP, Flutter предоставляет новый API initHybridAndroidView. Как видно, он требует среду с поддержкой Vulkan и API 34, поэтому его универсальность относительно низка.

Почему же он требует API 34? Это связано с прямым использованием API SurfaceControl, а также из логики проверки движка можно заметить, что помимо проверки на наличие Vulkan и API, требуется настройка соответствующего EnableSurfaceControl, то есть добавление следующих метаданных в AndroidManifest:

<meta-data
       android:name="io.flutter.embedding.android.EnableSurfaceControl"
       android:value="true" />

Далее давайте рассмотрим различия между HCPP и другими режимами, особенно сравним его с HC и TLHC. В качестве примера создадим контейнер Demo, который будет демонстрировать смешивание Flutter и native компонентов. platformView будет отображаться между двумя Flutter виджетами:

return MaterialApp(
  debugShowCheckedModeBanner: false,
  home: Stack(
    alignment: AlignmentDirectional.center,
    children: <Widget>[
      /// Зелёный Flutter прямоугольник размером 200x200
      TextButton(
        key: const ValueKey<String>('AddOverlay'),
        onPressed: _togglePlatformView,
        child: const SizedBox(width: 190, height: 190, child: ColoredBox(color: Colors.green)),
      ),
      
      /// Контейнер native размером 200x200, здесь используется красный native прямоугольник
      if (showPlatformView) ...<Widget>[
        SizedBox(width: 200, height: 200, child: widget.platformView),
        
        /// Жёлтый Flutter прямоугольник
        TextButton(
          key: const ValueKey<String>('RemoveOverlay'),
          onPressed: _togglePlatformView,
          child: const SizedBox(
            width: 800,
            height: 25,
            child: ColoredBox(color: Colors.yellow),
          ),
        ),
      ],
    ],
  ),
);
```Затем мы можем использовать `initExpensiveAndroidView` для принудительной работы PlatformView в режиме HC. При этом в режиме HC появляется множество типичных слоёв native, включая преобразование `FlutterImageView` и её подкласс `PlatformOverlayView`:

Мы можем видеть это с помощью 3D-рендера: красный нативный `BoxPlatformView` отрисован правильно, а затем над ним находятся Flutter-компоненты (часть желтых полос)  они предоставляются через подкласс `FlutterImageView`, называемый `PlatformOverlayView`, который использует отдельную поверхность для рендера:

![](http://img.cdn.guoshuyu.cn/20250215_HCPP/image7.png)

Затем мы используем метод `initAndroidView` в режиме TLHC и видим, что теперь контейнером является родительская компонента `PlatformViewWrapper`. Эта последняя заменяет Canvas нативного `BoxPlatformView`, чтобы содержимое нативного компонента рисовалось на указанной поверхности:

![](http://img.cdn.guoshuyu.cn/20250215_HCPP/image8.png)

Используя нативный 3D-рендер, можно заметить, что в данный момент `BoxPlatformView` ничего не рисует на уровне натива, так как его Canvas был заменён на `SurfaceTexture` в памяти:

![](http://img.cdn.guoshuyu.cn/20250215_HCPP/image9.png)

Что касается `SurfaceTexture`, то здесь стоит отметить, что при создании текстур для THLC и VD используются различные реализации в зависимости от версии Android API. В частности, `SurfaceProducer` имеет особое значение:

![](https://img.cdn.guoshuyu.cn/WechatIMG1260.jpg)До этого момента движок Flutter на платформе Android поддерживал два внешних источника рендера: `SurfaceTexture` (текстура OpenGLES) и `ImageReader` (буфер, готовый к работе GPU). При этом метод `Image.getHardwareBuffer` требует поддержки API уровня 28.Для совместимости с командой Impeller была введена концепция `SurfaceProducer`, которая позволяет Android выбирать "лучшую" поверхность рендера во время выполнения программы. Это применимо не только к сценариям PlatformView, но и к случаям работы с внешними текстурами:

```diff
- TextureRegistry.SurfaceTextureEntry entry = textureRegistry.createSurfaceTexture();
+ TextureRegistry.SurfaceProducer producer = textureRegistry.createSurfaceProducer();

- Surface surface = new Surface(entry.surfaceTexture());
+ Surface surface = producer.getSurface();

Теперь рассмотрим HCPP. Используя метод initHybridAndroidView, мы активируем режим HCPP, и видим, что структура уровней UI аналогична TLHC, однако родителем служит FlutterMutatorView из режима HC:

При просмотре 3D-рендера становится очевидно, что нативный компонент BoxPlatformView может быть полностью отрисован, что указывает на то, что его Canvas не был заменён. Здесь возникает интересный вопрос: какие механизмы позволяют желтым Flutter-компонентам отображаться поверх красного BoxPlatformView? Необходимо обратиться к PlatformViewsController2, который является временным объектом в контексте HCPP. В его реализации ключевым объектом является SurfaceControl. При завершении транзакций значение z-координаты устанавливается с помощью метода setLayer равным 1000:

image

При рассмотрении изменений можно заметить, что основная логика работы нового PlatformViewsController2 заключается в манипуляциях с объектом SurfaceControl:image

В Android, SurfaceControl представляет собой класс, используемый для управления и выполнения операций над графическими ресурсами, связанными с системой отображения. Проще говоря, это класс, связанный с управлением Surface. SurfaceControl используется для создания и управления Surface, а также для взаимодействия с SurfaceFlinger через Transaction.

В контексте HCPP, Surface создается с использованием нового объекта SurfaceControl, а сам объект SurfaceControl получает свои Transactions из FlutterView:

image

То есть, в режиме HCPP, Flutter использует SurfaceControl.Transaction для создания нового Surface, который затем используется SurfaceFlinger для композиции. Кроме того, с помощью метода setLayer значение координаты Z Surface устанавливается на 1000, что позволяет желтому Flutter-контролю отрисовываться поверх красного нативного прямоугольника.

Например, если мы скопируем часть кода, связанную с SurfaceControl, в простое нативное приложение и установим значение координаты Z Surface равным 1000, а также нарисуем красный цвет:```java protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);

    FrameLayout rootView = findViewById(R.id.container);
    rootView.postDelayed(new Runnable() {
        @Override
        public void run() {
            final SurfaceControl.Builder surfaceControlBuilder = new SurfaceControl.Builder();
            surfaceControlBuilder.setBufferSize(500, 500);
            surfaceControlBuilder.setFormat(PixelFormat.RGBA_8888);
            surfaceControlBuilder.setName("Flutter Overlay Surface");
            surfaceControlBuilder.setOpaque(false);
            surfaceControlBuilder.setHidden(false);
            final SurfaceControl surfaceControl = surfaceControlBuilder.build();
            final SurfaceControl.Transaction tx =
                    binding.container.getRootSurfaceControl().buildReparentTransaction(surfaceControl);
            tx.setLayer(surfaceControl, 1000);
            tx.apply();
            surface1 = new Surface(surfaceControl);
            surfaceControl1 = surfaceControl;
        }
    }, 0);
}
```### Отрисовка содержимого на SurfaceView
```java
// Отрисовываем некоторые данные на SurfaceView
drawOnSurface(surface1, Color.RED);

Затем мы можем рассмотреть конечный результат отрисовки. Мы видим, что фоновый FrameLayout зелёного цвета находится ниже WebView, но созданный поверхность с помощью container.getRootSurfaceControl(), имеющая ось Z равной 1000, приводит к тому, что красный прямоугольник будет отрисован поверх WebView.

Кроме того, в текущей логике, если движок Engine определяет, что текущий кадр не имеет PlatformView, а предыдущий кадр имел PlatformView, то он вызывает метод hideOverlaySurface2. Это приводит к вызову platformViewsController2.hideOverlaySurface() на уровне Java и скрывает ненужные слои:

if (!FrameHasPlatformLayers()) {
    frame->Submit();
    // Если предыдущий кадр содержал PlatformView, скрываем поверхность.
    if (previous_frame_view_count_ > 0) {
        jni_facade_->hideOverlaySurface2();
    }
    jni_facade_->applyTransaction();
    return;
}

Таким образом, можно заметить, что HCPP использует SurfaceControl для создания высокого уровня поверхности (Surface), чтобы обеспечить смешивание и покрытие при окончательной отрисовке, что аналогично тому, как Compose может использовать SurfaceView внутри PlatformView, когда SurfaceFlinger выполняет композицию на основе уровней.

Что касается необходимости использования API 34, это связано с тем, что некоторые API, связанные с SurfaceControl, требуют более поздних версий. Также стоит отметить, что Android 14 лучше поддерживает низкую задержку рисования через SurfaceControl, позволяя(Canvas API) ускорять отрисовку на HardwareBuffer:

Если вас интересует логика Engine, вы можете также посмотреть на логику external_view_embedder_2#SubmitFlutterView, где используется метод GetLayer для создания FlutterOverlaySurface. В настоящее время HCPP находится в бета-версии в главной ветке. В случае успешного внедрения, это приведёт к четырем возможным вариантам реализации для Android PlatformView. В отличие от множества режимов синтеза CALayer на iOS, путь развития Android PlatformView был сложным.Наконец, как вы считаете, станет ли HCPP основой для нового варианта поддержки PlatformView?

PS: io.flutter.embedding.android.EnableSurfaceControl используется для управления внутренним использованием Vulkan swapchain или Android SurfaceControl (AHB swapchain) внутри Impeller. В режиме Android SurfaceControl Java-часть создает транзакцию, которая связывается с AHB swapchain.

Конечно, реализация AHBSwapchainVK доступна не во всех версиях Android, и при её недоступности система переходит на использование KHR swapchain.

Ссылки для справки

Опубликовать ( 0 )

Вы можете оставить комментарий после Вход в систему

1
https://api.gitlife.ru/oschina-mirror/CarGuo-GSYFlutterBook.git
git@api.gitlife.ru:oschina-mirror/CarGuo-GSYFlutterBook.git
oschina-mirror
CarGuo-GSYFlutterBook
CarGuo-GSYFlutterBook
master