Flutter 3.41 is live! Check out theFlutter 3.41 blog post!
Hosting native Android views in your Flutter app with Platform Views
Learn how to host native Android views in your Flutter app with Platform Views.
Platform views allow you to embed native views in a Flutter app, so you can apply transforms, clips, and opacity to the native view from Dart.
This allows you, for example, to use the native Google Maps from the Android SDK directly inside your Flutter app.
This page discusses how to host your own native Android views within a Flutter app. If you'd like to embed native iOS views in your Flutter app, seeHosting native iOS views. If you'd like to embed native macOS views in your Flutter app, seeHosting native macOS views.
Platform Views on Android have two implementations. They come with tradeoffs both in terms of performance and fidelity. Platform views require Android API 23+.
Platform Views are rendered as they are normally. Flutter content is rendered into a texture. SurfaceFlinger composes the Flutter content and the platform views.
+best performance and fidelity of Android views.-Flutter performance suffers.-FPS of application will be lower.-Certain transformations that can be applied to Flutter widgets will not work when applied to platform views.
Texture Layer (or Texture Layer Hybrid Composition)
#Platform Views are rendered into a texture. Flutter draws the platform views (via the texture). Flutter content is rendered directly into a Surface.
+good performance for Android Views+best performance for Flutter rendering.+all transformations work correctly.-quick scrolling (e.g. a web view) will be janky-SurfaceViews are problematic in this mode and will be moved into a virtual display (breaking a11y)-Text magnifier will break unless Flutter is rendered into a TextureView.
To create a platform view on Android, use the following steps:
On the Dart side
# On the Dart side, create aWidget and add one of the following build implementations.
Hybrid composition
# In your Dart file, for examplenative_view_example.dart, use the following instructions:
Add the following imports:
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';Implement a
build()method:dartWidgetbuild(BuildContextcontext){// This is used in the platform side to register the view.constStringviewType='<platform-view-type>';// Pass parameters to the platform side.constMap<String,dynamic>creationParams=<String,dynamic>{};returnPlatformViewLink(viewType:viewType,surfaceFactory:(context,controller){returnAndroidViewSurface(controller:controllerasAndroidViewController,gestureRecognizers:const<Factory<OneSequenceGestureRecognizer>>{},hitTestBehavior:PlatformViewHitTestBehavior.opaque,);},onCreatePlatformView:(params){returnPlatformViewsService.initSurfaceAndroidView(id:params.id,viewType:viewType,layoutDirection:TextDirection.ltr,creationParams:creationParams,creationParamsCodec:constStandardMessageCodec(),onFocus:(){params.onFocusChanged(true);},)..addOnPlatformViewCreatedListener(params.onPlatformViewCreated)..create();},);}
For more information, see the API docs for:
TextureLayerHybridComposition
# In your Dart file, for examplenative_view_example.dart, use the following instructions:
Add the following imports:
dartimport'package:flutter/material.dart';import'package:flutter/services.dart';Implement a
build()method:dartWidgetbuild(BuildContextcontext){// This is used in the platform side to register the view.constStringviewType='<platform-view-type>';// Pass parameters to the platform side.finalMap<String,dynamic>creationParams=<String,dynamic>{};returnAndroidView(viewType:viewType,layoutDirection:TextDirection.ltr,creationParams:creationParams,creationParamsCodec:constStandardMessageCodec(),);}
For more information, see the API docs for:
On the platform side
# On the platform side, use the standardio.flutter.plugin.platform package in either Kotlin or Java:
In your native code, implement the following:
Extendio.flutter.plugin.platform.PlatformView to provide a reference to theandroid.view.View (for example,NativeView.kt):
packagedev.flutter.exampleimportandroid.content.Contextimportandroid.graphics.Colorimportandroid.view.Viewimportandroid.widget.TextViewimportio.flutter.plugin.platform.PlatformViewinternalclassNativeView(context:Context,id:Int,creationParams:Map<String?,Any?>?):PlatformView{privatevaltextView:TextViewoverridefungetView():View{returntextView}overridefundispose(){}init{textView=TextView(context)textView.textSize=72ftextView.setBackgroundColor(Color.rgb(255,255,255))textView.text="Rendered on a native Android view (id:$id)"}} Create a factory class that creates an instance of theNativeView created earlier (for example,NativeViewFactory.kt):
packagedev.flutter.exampleimportandroid.content.Contextimportio.flutter.plugin.common.StandardMessageCodecimportio.flutter.plugin.platform.PlatformViewimportio.flutter.plugin.platform.PlatformViewFactoryclassNativeViewFactory:PlatformViewFactory(StandardMessageCodec.INSTANCE){overridefuncreate(context:Context,viewId:Int,args:Any?):PlatformView{valcreationParams=argsasMap<String?,Any?>?returnNativeView(context,viewId,creationParams)}}Finally, register the platform view. You can do this in an app or a plugin.
For app registration, modify the app's main activity (for example,MainActivity.kt):
packagedev.flutter.exampleimportio.flutter.embedding.android.FlutterActivityimportio.flutter.embedding.engine.FlutterEngineclassMainActivity:FlutterActivity(){overridefunconfigureFlutterEngine(flutterEngine:FlutterEngine){super.configureFlutterEngine(flutterEngine)flutterEngine.platformViewsController.registry.registerViewFactory("<platform-view-type>",NativeViewFactory())}} For plugin registration, modify the plugin's main class (for example,PlatformViewPlugin.kt):
packagedev.flutter.plugin.exampleimportio.flutter.embedding.engine.plugins.FlutterPluginimportio.flutter.embedding.engine.plugins.FlutterPlugin.FlutterPluginBindingclassPlatformViewPlugin:FlutterPlugin{overridefunonAttachedToEngine(binding:FlutterPluginBinding){binding.platformViewRegistry.registerViewFactory("<platform-view-type>",NativeViewFactory())}overridefunonDetachedFromEngine(binding:FlutterPluginBinding){}}In your native code, implement the following:
Extendio.flutter.plugin.platform.PlatformView to provide a reference to theandroid.view.View (for example,NativeView.java):
packagedev.flutter.example;importandroid.content.Context;importandroid.graphics.Color;importandroid.view.View;importandroid.widget.TextView;importandroidx.annotation.NonNull;importandroidx.annotation.Nullable;importio.flutter.plugin.platform.PlatformView;importjava.util.Map;classNativeViewimplementsPlatformView{@NonNullprivatefinalTextViewtextView;NativeView(@NonNullContextcontext,intid,@NullableMap<String,Object>creationParams){textView=newTextView(context);textView.setTextSize(72);textView.setBackgroundColor(Color.rgb(255,255,255));textView.setText("Rendered on a native Android view (id:"+id+")");}@NonNull@OverridepublicViewgetView(){returntextView;}@Overridepublicvoiddispose(){}} Create a factory class that creates an instance of theNativeView created earlier (for example,NativeViewFactory.java):
packagedev.flutter.example;importandroid.content.Context;importandroidx.annotation.Nullable;importandroidx.annotation.NonNull;importio.flutter.plugin.common.StandardMessageCodec;importio.flutter.plugin.platform.PlatformView;importio.flutter.plugin.platform.PlatformViewFactory;importjava.util.Map;classNativeViewFactoryextendsPlatformViewFactory{NativeViewFactory(){super(StandardMessageCodec.INSTANCE);}@NonNull@OverridepublicPlatformViewcreate(@NonNullContextcontext,intid,@NullableObjectargs){finalMap<String,Object>creationParams=(Map<String,Object>)args;returnnewNativeView(context,id,creationParams);}}Finally, register the platform view. You can do this in an app or a plugin.
For app registration, modify the app's main activity (for example,MainActivity.java):
packagedev.flutter.example;importandroidx.annotation.NonNull;importio.flutter.embedding.android.FlutterActivity;importio.flutter.embedding.engine.FlutterEngine;publicclassMainActivityextendsFlutterActivity{@OverridepublicvoidconfigureFlutterEngine(@NonNullFlutterEngineflutterEngine){flutterEngine.getPlatformViewsController().getRegistry().registerViewFactory("<platform-view-type>",newNativeViewFactory());}} For plugin registration, modify the plugin's main file (for example,PlatformViewPlugin.java):
packagedev.flutter.plugin.example;importandroidx.annotation.NonNull;importio.flutter.embedding.engine.plugins.FlutterPlugin;publicclassPlatformViewPluginimplementsFlutterPlugin{@OverridepublicvoidonAttachedToEngine(@NonNullFlutterPluginBindingbinding){binding.getPlatformViewRegistry().registerViewFactory("<platform-view-type>",newNativeViewFactory());}@OverridepublicvoidonDetachedFromEngine(@NonNullFlutterPluginBindingbinding){}}For more information, see the API docs for:
Finally, modify yourbuild.gradle file to require one of the minimal Android SDK versions:
android{defaultConfig{minSdk=19// if using hybrid compositionminSdk=20// if using virtual display.}}Surface Views
#Handling SurfaceViews is problematic for Flutter and should be avoided when possible.
Manual view invalidation
# Certain Android Views do not invalidate themselves when their content changes. Some example views includeSurfaceView andSurfaceTexture. When your Platform View includes these views you are required to manually invalidate the view after they have been drawn to (or more specifically: after the swap chain is flipped). Manual view invalidation is done by callinginvalidate on the View or one of its parent views.
Issues
#Performance
#Platform views in Flutter come with performance trade-offs.
For example, in a typical Flutter app, the Flutter UI is composed on a dedicated raster thread. This allows Flutter apps to be fast, as the main platform thread is rarely blocked.
While a platform view is rendered with hybrid composition, the Flutter UI is composed from the platform thread, which competes with other tasks like handling OS or plugin messages.
Prior to Android 10, hybrid composition copied each Flutter frame out of the graphic memory into main memory, and then copied it back to a GPU texture. As this copy happens per frame, the performance of the entire Flutter UI might be impacted. In Android 10 or above, the graphics memory is copied only once.
Virtual display, on the other hand, makes each pixel of the native view flow through additional intermediate graphic buffers, which cost graphic memory and drawing performance.
For complex cases, there are some techniques that can be used to mitigate these issues.
For example, you could use a placeholder texture while an animation is happening in Dart. In other words, if an animation is slow while a platform view is rendered, then consider taking a screenshot of the native view and rendering it as a texture.
For more information, see:
Unless stated otherwise, the documentation on this site reflects Flutter 3.38.6. Page last updated on 2025-10-28.View source orreport an issue.