Alojar vistas nativas de Android en tu aplicación de Flutter con Platform Views
Aprende a alojar vistas nativas de Android en tu aplicación de Flutter con Platform Views.
Las Platform Views te permiten incrustar vistas nativas en una aplicación de Flutter, de modo que puedes aplicar transformaciones, recortes y opacidad a la vista nativa desde Dart.
Esto te permite, por ejemplo, utilizar Google Maps nativo desde el SDK de Android directamente dentro de tu aplicación de Flutter.
Las Platform Views en Android tienen varias implementaciones. Conllevan compromisos (trade-offs) tanto en términos de rendimiento como de fidelidad.
Elegir una implementación
#La siguiente matriz resume las diferentes implementaciones y sus ventajas y desventajas:
| Modo | Beneficios | Consideraciones | Habilitador |
|---|---|---|---|
| Texture layer | • Buen rendimiento de Flutter • Funcionan todas las transformaciones de widgets |
• Tirones durante el desplazamiento rápido • Las SurfaceViews pierden accesibilidad y la lupa de texto se rompe |
Comportamiento por defecto o AndroidView estándar |
| Hybrid composition | • Fidelidad nativa completa • Accesibilidad correcta y soporte de SurfaceView |
• Provoca la fusión de hilos de renderizado (raster) y plataforma, lo que degrada los FPS de Flutter • Platform View -> Se renderiza a una textura -> Se sube a Impeller -> Impeller compone el contenido de Flutter y el contenido de la Platform View |
•
PlatformViewLink
con
AndroidViewSurface
• AndroidViewController compila una Platform View de tipo TLHC o HC |
| HCPP (Experimental) | • Fidelidad y rendimiento completos • Resuelve la sobrecarga de sincronización original |
• Requiere la API 34+ de Android, soporte para Vulkan y el uso del motor de renderizado Impeller
• Platform View -> Se renderiza en una Surface de Android nativa, Impeller renderiza en una Surface de Android nativa, SurfaceFlinger compone ambas juntas |
•
<meta-data>
en
AndroidManifest.xml
• --enable-hcpp
flag local
• AndroidViewController compila una Platform View de tipo TLHC o HC |
Composición híbrida
#Las Platform Views se renderizan de manera normal. El contenido de Flutter se renderiza en una textura. SurfaceFlinger compone el contenido de Flutter y las platform views.
Composición híbrida++ (HCPP)
#HCPP es la última estrategia de composición híbrida, diseñada para resolver los problemas de rendimiento de composición y sincronización observados en el modo original de composición híbrida (Hybrid Composition). Actualmente está disponible como una característica opcional.
Requisitos
#- API 34 de Android o posterior: Requerida para las capacidades nativas de sincronización de transacciones.
- Renderizado con Vulkan: El dispositivo debe ser capaz de renderizar con Vulkan. Requerido para poder habilitar Impeller.
Si no se cumplen estos requisitos en el dispositivo del usuario final, Flutter recurrirá automáticamente a la estrategia de platform view existente configurada para la aplicación.
Activar (Opt-in)
#Debido a que HCPP actúa como una actualización global del soporte de las platform views,
se habilita mediante configuración en lugar de usar los
métodos estándar de inicialización de Dart (initAndroidView, etc.).
Puedes habilitar HCPP utilizando uno de los siguientes métodos:
-
Flag de línea de comandos (run/test): Pasa el flag
--enable-hcppa tu comandoflutter runoflutter test:flutter run --enable-hcpp -
AndroidManifest.xml: Incluye una etiqueta
<meta-data>dentro del bloque<application>de tuAndroidManifest.xml:xml<meta-data android:name="io.flutter.embedding.android.EnableHcpp" android:value="true" />
Limitaciones y problemas conocidos
#- Apilamiento de superposiciones complejas: Las platform views transparentes no se mostrarán correctamente en pilas de diseño estructuradas como: Flutter canvas -> Platform View -> Overlay -> Transparent Platform View, cuando estas cuatro capas se cruzan.
Capa de textura
#Las Platform Views se renderizan en una textura. Flutter dibuja las platform views (utilizando la textura). El contenido de Flutter se renderiza directamente en una Surface.
Este enfoque proporciona:
- buen rendimiento para Android Views
- buen rendimiento para el renderizado de Flutter
- todas las transformaciones funcionan correctamente
Sin embargo, este enfoque podría causar:
- tirones al desplazarse rápidamente (como en una vista web)
- accesibilidad rota para las
SurfaceViews - lupa de texto rota a menos que Flutter se renderice
en una
TextureView
En el lado de Dart
#Para crear una platform view en Android, sigue los siguientes pasos.
Primero, en el lado de Dart, crea un Widget y añade una de las
siguientes implementaciones de construcción según la estrategia elegida.
Composición híbrida
#En tu archivo Dart,
por ejemplo native_view_example.dart,
utiliza las siguientes instrucciones:
-
Añade las siguientes importaciones:
dartimport 'package:flutter/foundation.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart'; -
Implementa un método
build:dartWidget build(BuildContext context) { // This is used in the platform side to register the view. const String viewType = '<platform-view-type>'; // Pass parameters to the platform side. const Map<String, dynamic> creationParams = <String, dynamic>{}; return PlatformViewLink( viewType: viewType, surfaceFactory: (context, controller) { return AndroidViewSurface( controller: controller as AndroidViewController, gestureRecognizers: const <Factory<OneSequenceGestureRecognizer>>{}, hitTestBehavior: PlatformViewHitTestBehavior.opaque, ); }, onCreatePlatformView: (params) { return PlatformViewsService.initSurfaceAndroidView( id: params.id, viewType: viewType, layoutDirection: TextDirection.ltr, creationParams: creationParams, creationParamsCodec: const StandardMessageCodec(), onFocus: () { params.onFocusChanged(true); }, ) ..addOnPlatformViewCreatedListener(params.onPlatformViewCreated) ..create(); }, ); }
Para obtener más información, visita la siguiente documentación de la API:
TextureLayerHybridComposition
#En tu archivo Dart,
por ejemplo native_view_example.dart,
utiliza las siguientes instrucciones:
-
Añade las siguientes importaciones:
dartimport 'package:flutter/material.dart'; import 'package:flutter/services.dart'; -
Implementa un método
build:dartWidget build(BuildContext context) { // This is used in the platform side to register the view. const String viewType = '<platform-view-type>'; // Pass parameters to the platform side. final Map<String, dynamic> creationParams = <String, dynamic>{}; return AndroidView( viewType: viewType, layoutDirection: TextDirection.ltr, creationParams: creationParams, creationParamsCodec: const StandardMessageCodec(), ); }
Para obtener más información, visita la página de la API de AndroidView.
En el lado de la plataforma
#En el lado de la plataforma, utiliza el paquete estándar
io.flutter.plugin.platform ya sea en Kotlin o Java:
En tu código nativo, implementa lo siguiente:
Extiende io.flutter.plugin.platform.PlatformView
para proporcionar una referencia a android.view.View
(por ejemplo, NativeView.kt):
package dev.flutter.example
import android.content.Context
import android.graphics.Color
import android.view.View
import android.widget.TextView
import io.flutter.plugin.platform.PlatformView
internal class NativeView(context: Context, id: Int, creationParams: Map<String?, Any?>?) : PlatformView {
private val textView: TextView
override fun getView(): View {
return textView
}
override fun dispose() {}
init {
textView = TextView(context)
textView.textSize = 72f
textView.setBackgroundColor(Color.rgb(255, 255, 255))
textView.text = "Rendered on a native Android view (id: $id)"
}
}
Crea una clase factory que genere una instancia de la
NativeView creada anteriormente
(por ejemplo, NativeViewFactory.kt):
package dev.flutter.example
import android.content.Context
import io.flutter.plugin.common.StandardMessageCodec
import io.flutter.plugin.platform.PlatformView
import io.flutter.plugin.platform.PlatformViewFactory
class NativeViewFactory : PlatformViewFactory(StandardMessageCodec.INSTANCE) {
override fun create(context: Context, viewId: Int, args: Any?): PlatformView {
val creationParams = args as Map<String?, Any?>?
return NativeView(context, viewId, creationParams)
}
}
Por último, registra la platform view. Puedes hacer esto en una aplicación o en un plugin.
Para registrar la aplicación,
modifica la actividad principal de la aplicación
(por ejemplo, MainActivity.kt):
package dev.flutter.example
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
class MainActivity : FlutterActivity() {
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
flutterEngine
.platformViewsController
.registry
.registerViewFactory("<platform-view-type>",
NativeViewFactory())
}
}
Para registrar el plugin,
modifica la clase principal del plugin
(por ejemplo, PlatformViewPlugin.kt):
package dev.flutter.plugin.example
import io.flutter.embedding.engine.plugins.FlutterPlugin
import io.flutter.embedding.engine.plugins.FlutterPlugin.FlutterPluginBinding
class PlatformViewPlugin : FlutterPlugin {
override fun onAttachedToEngine(binding: FlutterPluginBinding) {
binding
.platformViewRegistry
.registerViewFactory("<platform-view-type>", NativeViewFactory())
}
override fun onDetachedFromEngine(binding: FlutterPluginBinding) {}
}
En tu código nativo, implementa lo siguiente:
Extiende io.flutter.plugin.platform.PlatformView
para proporcionar una referencia a android.view.View
(por ejemplo, NativeView.java):
package dev.flutter.example;
import android.content.Context;
import android.graphics.Color;
import android.view.View;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import io.flutter.plugin.platform.PlatformView;
import java.util.Map;
class NativeView implements PlatformView {
@NonNull private final TextView textView;
NativeView(@NonNull Context context, int id, @Nullable Map<String, Object> creationParams) {
textView = new TextView(context);
textView.setTextSize(72);
textView.setBackgroundColor(Color.rgb(255, 255, 255));
textView.setText("Rendered on a native Android view (id: " + id + ")");
}
@NonNull
@Override
public View getView() {
return textView;
}
@Override
public void dispose() {}
}
Crea una clase factory que genere una
instancia de la NativeView creada anteriormente
(por ejemplo, NativeViewFactory.java):
package dev.flutter.example;
import android.content.Context;
import androidx.annotation.Nullable;
import androidx.annotation.NonNull;
import io.flutter.plugin.common.StandardMessageCodec;
import io.flutter.plugin.platform.PlatformView;
import io.flutter.plugin.platform.PlatformViewFactory;
import java.util.Map;
class NativeViewFactory extends PlatformViewFactory {
NativeViewFactory() {
super(StandardMessageCodec.INSTANCE);
}
@NonNull
@Override
public PlatformView create(@NonNull Context context, int id, @Nullable Object args) {
final Map<String, Object> creationParams = (Map<String, Object>) args;
return new NativeView(context, id, creationParams);
}
}
Por último, registra la platform view. Puedes hacer esto en una aplicación o en un plugin.
Para registrar la aplicación, modifica la actividad principal de la aplicación
(por ejemplo, MainActivity.java):
package dev.flutter.example;
import androidx.annotation.NonNull;
import io.flutter.embedding.android.FlutterActivity;
import io.flutter.embedding.engine.FlutterEngine;
public class MainActivity extends FlutterActivity {
@Override
public void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) {
flutterEngine
.getPlatformViewsController()
.getRegistry()
.registerViewFactory("<platform-view-type>", new NativeViewFactory());
}
}
Para registrar el plugin,
modifica el archivo principal del plugin
(por ejemplo, PlatformViewPlugin.java):
package dev.flutter.plugin.example;
import androidx.annotation.NonNull;
import io.flutter.embedding.engine.plugins.FlutterPlugin;
public class PlatformViewPlugin implements FlutterPlugin {
@Override
public void onAttachedToEngine(@NonNull FlutterPluginBinding binding) {
binding
.getPlatformViewRegistry()
.registerViewFactory("<platform-view-type>", new NativeViewFactory());
}
@Override
public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) {}
}
Para obtener más información, visita la documentación de la API para:
Finalmente, modifica tu archivo build.gradle
para requerir una de las versiones mínimas del SDK de Android:
android {
defaultConfig {
minSdk = 19 // if using hybrid composition
minSdk = 20 // if using virtual display.
}
}
Invalidación manual de la vista
#Ciertas vistas de Android (Android Views) no se invalidan a sí mismas cuando cambia su contenido.
Algunos ejemplos incluyen SurfaceView y SurfaceTexture.
Cuando tu Platform View incluye estas vistas,
debes invalidarla manualmente después de que se haya dibujado
(o, más concretamente, después de que se intercambie la cadena de intercambio (swap chain)).
Invalida la vista llamando a invalidate en ella o en uno de sus padres.
Problemas
#Consulta los problemas existentes de Platform Views en GitHub.
Rendimiento
#Platform Views en Flutter conllevan compromisos de rendimiento.
En una aplicación típica de Flutter, la UI de Flutter se compone en un hilo raster dedicado, mientras que el código de la plataforma se ejecuta en el hilo de la UI/plataforma. Esta separación mantiene el renderizado de Flutter rápido y fluido.
Sin embargo, cuando una platform view se renderiza en Android mediante composición híbrida (hybrid composition), Flutter fusiona los hilos raster y de UI en un único hilo para garantizar la correcta sincronización entre las vistas nativas de Android y el canvas de Flutter. Debido a esta fusión de hilos, la renderización de widgets complejos de Flutter junto a una platform view puede competir con los mensajes del sistema operativo y las interacciones de los plugins, lo que podría causar un menor número de FPS en la aplicación y caídas de fotogramas.
Además, antes de Android 10, la composición híbrida copiaba cada fotograma de Flutter de la memoria gráfica a la memoria principal, y luego lo volvía a copiar a una textura de GPU. Dado que esta copia se realiza por fotograma, el rendimiento de toda la UI de Flutter podría verse afectado. En Android 10 o superior, la memoria gráfica se copia una sola vez.
Hybrid Composition++ (HCPP) minimiza esta sobrecarga al utilizar la sincronización de transacciones nativas en dispositivos compatibles (API 34 de Android o superior con Vulkan), lo que permite un rendimiento superior sin los altos costos de la composición híbrida original.
Por otro lado, Virtual Display hace que cada píxel de la vista nativa fluya a través de búferes gráficos intermedios adicionales, lo que cuesta memoria gráfica y rendimiento de dibujo. Esto puede provocar tirones durante actualizaciones de alta frecuencia como el desplazamiento rápido.
Para casos complejos, existen algunas técnicas que pueden utilizarse para mitigar estos problemas.
Por ejemplo, puedes utilizar una textura de marcador de posición (placeholder) mientras ocurre una animación en Dart. En otras palabras, si una animación es lenta mientras se renderiza una platform view, entonces considera tomar una captura de pantalla de la vista nativa y renderizarla como una textura.
Para obtener más información, visita las siguientes páginas de la API:
A menos que se indique lo contrario, la documentación en este sitio refleja Flutter 3.44.0. Página actualizada por última vez el 2026-07-17. Ver código fuente oreportar un problema.