| Hybrid composition refers to the ability of composing native views alongside Flutter widgets. For example, displaying the native Webview inside a Flutter app. | 
 |  | 
 | ## Android | 
 | *Requires API level 19* | 
 |  | 
 | _See also: [Texture Layer Hybrid Composition](./android/Texture-Layer-Hybrid-Composition.md)_ | 
 |  | 
 | Starting from Flutter 1.20.0, hybrid composition can be used on Android. This new feature fixes most of the [issues with the preview platform view approach](./android/Virtual-Display.md#associated-problems-and-workarounds) (Virtual Display); in particular, accessibility and keyboard related issues. See also [Android Platform Views](./android/Android-Platform-Views.md) for an overview of modes. | 
 |  | 
 | To see all known issues specific to this mode, search for the [`hc-only` label](https://github.com/flutter/flutter/labels/hc-only). | 
 |  | 
 | ### Dart side | 
 |  | 
 | To start using this feature, you would need to create a `Widget`, and add the following `build` implementation: | 
 |  | 
 | `native_view_example.dart` | 
 |  | 
 | 1. Add imports: | 
 | ```dart | 
 | import 'package:flutter/foundation.dart'; | 
 | import 'package:flutter/gestures.dart'; | 
 | import 'package:flutter/rendering.dart'; | 
 | import 'package:flutter/services.dart'; | 
 | ``` | 
 |  | 
 | 2. Implement `build` method: | 
 | ```dart | 
 | Widget build(BuildContext context) { | 
 |   // This is used in the platform side to register the view. | 
 |   final String viewType = 'hybrid-view-type'; | 
 |   // Pass parameters to the platform side. | 
 |   final Map<String, dynamic> creationParams = <String, dynamic>{}; | 
 |  | 
 |   return PlatformViewLink( | 
 |     viewType: viewType, | 
 |     surfaceFactory: | 
 |         (BuildContext context, PlatformViewController controller) { | 
 |       return AndroidViewSurface( | 
 |         controller: controller, | 
 |         gestureRecognizers: const <Factory<OneSequenceGestureRecognizer>>{}, | 
 |         hitTestBehavior: PlatformViewHitTestBehavior.opaque, | 
 |       ); | 
 |     }, | 
 |     onCreatePlatformView: (PlatformViewCreationParams params) { | 
 |       return PlatformViewsService.initSurfaceAndroidView( | 
 |         id: params.id, | 
 |         viewType: viewType, | 
 |         layoutDirection: TextDirection.ltr, | 
 |         creationParams: creationParams, | 
 |         creationParamsCodec: StandardMessageCodec(), | 
 |       ) | 
 |         ..addOnPlatformViewCreatedListener(params.onPlatformViewCreated) | 
 |         ..create(); | 
 |     }, | 
 |   ); | 
 | } | 
 | ``` | 
 |  | 
 | For more documentation see: [PlatformViewLink](https://api.flutter.dev/flutter/widgets/PlatformViewLink-class.html), [AndroidViewSurface](https://api.flutter.dev/flutter/widgets/AndroidViewSurface-class.html), [PlatformViewsService](https://api.flutter.dev/flutter/services/PlatformViewsService-class.html). | 
 |  | 
 | ### Platform side | 
 |  | 
 | Finally, on the platform side, you use the standard `io.flutter.plugin.platform` package in Java or Kotlin: | 
 |  | 
 | `NativeView.java` | 
 |  | 
 | ```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; | 
 |  | 
 | 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() {} | 
 | } | 
 | ``` | 
 |  | 
 | `NativeViewFactory.java` | 
 |  | 
 | ```java | 
 | package dev.flutter.example; | 
 |  | 
 | import android.content.Context; | 
 | import android.view.View; | 
 | import androidx.annotation.Nullable; | 
 | import androidx.annotation.NonNull; | 
 | import io.flutter.plugin.common.BinaryMessenger; | 
 | 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 { | 
 |   @NonNull private final BinaryMessenger messenger; | 
 |   @NonNull private final View containerView; | 
 |  | 
 |   NativeViewFactory(@NonNull BinaryMessenger messenger, @NonNull View containerView) { | 
 |     super(StandardMessageCodec.INSTANCE); | 
 |     this.messenger = messenger; | 
 |     this.containerView = containerView; | 
 |   } | 
 |  | 
 |   @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); | 
 |   } | 
 | } | 
 | ``` | 
 |  | 
 | Register the platform view. This can be done in an app or a plugin. | 
 |  | 
 | For app registration, modify the main activity (e.g. `MainActivity.java`): | 
 |  | 
 | ```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()); | 
 |     } | 
 | } | 
 | ``` | 
 |  | 
 | For plugin registration, modify the main plugin file (e.g. `PlatformViewPlugin.java`): | 
 |  | 
 | ```java | 
 | package dev.flutter.plugin.example; | 
 |  | 
 | import androidx.annotation.NonNull; | 
 | import io.flutter.embedding.engine.plugins.FlutterPlugin; | 
 | import io.flutter.plugin.common.BinaryMessenger; | 
 |  | 
 | public class PlatformViewPlugin implements FlutterPlugin { | 
 |   @Override | 
 |   public void onAttachedToEngine(@NonNull FlutterPluginBinding binding) { | 
 |     binding | 
 |         .getFlutterEngine() | 
 |         .getPlatformViewsController() | 
 |         .getRegistry() | 
 |         .registerViewFactory("<platform-view-type>", new NativeViewFactory()); | 
 |   } | 
 | } | 
 | ``` | 
 |  | 
 | For more documentation, see [PlatformViewRegistry](https://api.flutter.dev/javadoc/io/flutter/plugin/platform/PlatformViewRegistry.html), [PlatformViewFactory](https://api.flutter.dev/javadoc/io/flutter/plugin/platform/PlatformViewFactory.html), and [PlatformView](https://api.flutter.dev/javadoc/io/flutter/plugin/platform/PlatformView.html). | 
 |  | 
 | Finally, indicate the minimum API Level required for the application to run in `build.gradle`. | 
 |  | 
 | ```groovy | 
 | android { | 
 |     defaultConfig { | 
 |         minSdkVersion 19 | 
 |     } | 
 | } | 
 | ``` | 
 | ## iOS | 
 |  | 
 | In Flutter 1.22, platform views are enabled by default. This means | 
 | that it's no longer required to add the | 
 | `io.flutter.embedded_views_preview` flag to `Info.plist`. | 
 |  | 
 | To create a platform view on iOS, follow these steps: | 
 |  | 
 | ### On the Dart side | 
 |  | 
 | On the Dart side, create a `Widget` | 
 | and add the following build implementation, | 
 | as shown in the following steps. | 
 |  | 
 | In your Dart file, for example `native_view_example.dart`, | 
 | do the following: | 
 |  | 
 | 1. Add the following imports: | 
 |  | 
 | <!-- skip --> | 
 | ```dart | 
 | import 'package:flutter/widget.dart'; | 
 | ``` | 
 |  | 
 |  | 
 | 2. Implement a `build()` method: | 
 |  | 
 | <!-- skip --> | 
 | ```dart | 
 | Widget build(BuildContext context) { | 
 |   // This is used in the platform side to register the view. | 
 |   final String viewType = '<platform-view-type>'; | 
 |   // Pass parameters to the platform side. | 
 |   final Map<String, dynamic> creationParams = <String, dynamic>{}; | 
 |  | 
 |   return UiKitView( | 
 |     viewType: viewType, | 
 |     layoutDirection: TextDirection.ltr, | 
 |     creationParams: creationParams, | 
 |     creationParamsCodec: const StandardMessageCodec(), | 
 |   ); | 
 | } | 
 | ``` | 
 |  | 
 | For more information, see the API docs for: | 
 | [`UIKitView`](https://api.flutter.dev/flutter/widgets/UiKitView-class.html). | 
 |  | 
 | ### On the platform side | 
 |  | 
 | In your native code, implement the following: | 
 |  | 
 | `FLNativeView.h` | 
 |  | 
 | ```objc | 
 | #import <Flutter/Flutter.h> | 
 |  | 
 | @interface FLNativeViewFactory : NSObject <FlutterPlatformViewFactory> | 
 | - (instancetype)initWithMessenger:(NSObject<FlutterBinaryMessenger>*)messenger; | 
 | @end | 
 |  | 
 | @interface FLNativeView : NSObject <FlutterPlatformView> | 
 |  | 
 | - (instancetype)initWithFrame:(CGRect)frame | 
 |                viewIdentifier:(int64_t)viewId | 
 |                     arguments:(id _Nullable)args | 
 |               binaryMessenger:(NSObject<FlutterBinaryMessenger>*)messenger; | 
 |  | 
 | - (UIView*)view; | 
 | @end | 
 | ``` | 
 |  | 
 | Implement the factory and the platform view in `FLNativeView.m` | 
 |  | 
 | ```objc | 
 | #import "FLNativeView.h" | 
 |  | 
 | @implementation FLNativeViewFactory { | 
 |   NSObject<FlutterBinaryMessenger>* _messenger; | 
 | } | 
 |  | 
 | - (instancetype)initWithMessenger:(NSObject<FlutterBinaryMessenger>*)messenger { | 
 |   self = [super init]; | 
 |   if (self) { | 
 |     _messenger = messenger; | 
 |   } | 
 |   return self; | 
 | } | 
 |  | 
 | - (NSObject<FlutterPlatformView>*)createWithFrame:(CGRect)frame | 
 |                                    viewIdentifier:(int64_t)viewId | 
 |                                         arguments:(id _Nullable)args { | 
 |   return [[FLNativeView alloc] initWithFrame:frame | 
 |                               viewIdentifier:viewId | 
 |                                    arguments:args | 
 |                              binaryMessenger:_messenger]; | 
 | } | 
 |  | 
 | @end | 
 |  | 
 | @implementation FLNativeView { | 
 |    UIView *_view; | 
 | } | 
 |  | 
 | - (instancetype)initWithFrame:(CGRect)frame | 
 |                viewIdentifier:(int64_t)viewId | 
 |                     arguments:(id _Nullable)args | 
 |               binaryMessenger:(NSObject<FlutterBinaryMessenger>*)messenger { | 
 |   if (self = [super init]) { | 
 |     _view = [[UIView alloc] init]; | 
 |   } | 
 |   return self; | 
 | } | 
 |  | 
 | - (UIView*)view { | 
 |   return _view; | 
 | } | 
 |  | 
 | @end | 
 | ``` | 
 |  | 
 | Finally, register the platform view. This can be done in an app or a plugin. | 
 |  | 
 |  | 
 | For app registration, modify the App's `AppDelegate.m`: | 
 |  | 
 | ```objc | 
 | #import "AppDelegate.h" | 
 | #import "FLNativeView.h" | 
 | #import "GeneratedPluginRegistrant.h" | 
 |  | 
 | @implementation AppDelegate | 
 |  | 
 | - (BOOL)application:(UIApplication *)application | 
 |     didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { | 
 |   [GeneratedPluginRegistrant registerWithRegistry:self]; | 
 |  | 
 |    NSObject<FlutterPluginRegistrar>* registrar = | 
 |       [self registrarForPlugin:@"plugin-name"]; | 
 |  | 
 |   FLNativeViewFactory* factory = | 
 |       [[FLNativeViewFactory alloc] initWithMessenger:registrar.messenger]; | 
 |   [[self registrarForPlugin:@"<plugin-name>"] registerViewFactory:factory | 
 |                                                           withId:@"<platform-view-type>"]; | 
 |   return [super application:application didFinishLaunchingWithOptions:launchOptions]; | 
 | } | 
 |  | 
 | @end | 
 | ``` | 
 |  | 
 | For plugin registration, modify the main plugin file (e.g. `FLPlugin.m`): | 
 |  | 
 | ```objc | 
 | #import "FLPlugin.h" | 
 | #import "FLNativeView.h" | 
 |  | 
 | @implementation FLPlugin | 
 |  | 
 | + (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar { | 
 |   FLNativeViewFactory* factory = | 
 |       [[FLNativeViewFactory alloc] initWithMessenger:registrar.messenger]; | 
 |   [registrar registerViewFactory:factory withId:@"<platform-view-type>"]; | 
 | } | 
 |  | 
 | @end | 
 | ``` | 
 |  | 
 | For more information, see the API docs for: | 
 |  | 
 | * [`FlutterPlatformViewFactory`](https://api.flutter.dev/objcdoc/Protocols/FlutterPlatformViewFactory.html) | 
 | * [`FlutterPlatformView`](https://api.flutter.dev/objcdoc/Protocols/FlutterPlatformView.html) | 
 | * [`PlatformView`](https://api.flutter.dev/javadoc/io/flutter/plugin/platform/PlatformView.html) | 
 |  | 
 | By default, the `UIKitView` widget appends the native `UIView` to the view hierarchy. For more documentation, see [UIKitView](https://api.flutter.dev/flutter/widgets/UiKitView-class.html). | 
 |  | 
 | ## 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, etc. | 
 |  | 
 | Prior to Android 10, Hybrid Composition copies each Flutter frame | 
 | out of the graphic memory into main memory and then copied back to | 
 | a GPU texture. As this copy happens per frame, the performance of | 
 | the entire Flutter UI may be impacted. | 
 |  | 
 | On the other hand, Virtual Display 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: | 
 |  | 
 | * [`TextureLayer`](https://api.flutter.dev/flutter/rendering/TextureLayer-class.html) | 
 | * [`TextureRegistry`](https://api.flutter.dev/javadoc/io/flutter/view/TextureRegistry.html) | 
 | * [`FlutterTextureRegistry`](https://api.flutter.dev/objcdoc/Protocols/FlutterTextureRegistry.html) |