Saltar al contenido principal

Alojar vistas nativas de macOS en tu aplicación de Flutter con Platform Views

Aprende cómo alojar vistas nativas de macOS en tu aplicación de Flutter con Platform Views.

Las vistas de plataforma (platform views) te permiten incrustar vistas nativas en una aplicación de Flutter, de modo que puedas aplicar transformaciones, recortes y opacidad a la vista nativa desde Dart.

Esto te permite, por ejemplo, utilizar las vistas web nativas directamente dentro de tu aplicación de Flutter.

macOS utiliza composición híbrida (Hybrid composition), lo que significa que el NSView nativo se añade a la jerarquía de vistas.

Para crear una vista de plataforma en macOS, sigue estas instrucciones:

En el lado de Dart

#

En el lado de Dart, crea un Widget y añade la implementación de build, como se muestra en los siguientes pasos:

En el archivo de Widget de Dart, realiza cambios similares a los mostrados en native_view_example.dart:

  1. Añade las siguientes importaciones:

    dart
    import 'package:flutter/foundation.dart';
    import 'package:flutter/services.dart';
    
  2. Implementa un método build():

    dart
    Widget 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 AppKitView(
        viewType: viewType,
        layoutDirection: TextDirection.ltr,
        creationParams: creationParams,
        creationParamsCodec: const StandardMessageCodec(),
      );
    }
    

Para obtener más información, consulta la documentación de la API de AppKitView.

En el lado de la plataforma

#

Implementa la fábrica (factory) y la vista de plataforma. El NativeViewFactory crea la vista de plataforma, y la vista de plataforma proporciona una referencia al NSView. Por ejemplo, NativeView.swift:

NativeView.swift
swift
import Cocoa
import FlutterMacOS

class NativeViewFactory: NSObject, FlutterPlatformViewFactory {
  private var messenger: FlutterBinaryMessenger

  init(messenger: FlutterBinaryMessenger) {
    self.messenger = messenger
    super.init()
  }

  func create(
    withViewIdentifier viewId: Int64,
    arguments args: Any?
  ) -> NSView {
    return NativeView(
      viewIdentifier: viewId,
      arguments: args,
      binaryMessenger: messenger)
  }

  /// Implementing this method is only necessary when
  /// the `arguments` in `createWithFrame` is not `nil`.
  public func createArgsCodec() -> (FlutterMessageCodec & NSObjectProtocol)? {
    return FlutterStandardMessageCodec.sharedInstance()
  }
}

class NativeView: NSView {

  init(
    viewIdentifier viewId: Int64,
    arguments args: Any?,
    binaryMessenger messenger: FlutterBinaryMessenger?
  ) {
    super.init(frame: CGRect(x: 0, y: 0, width: 200, height: 200))
    wantsLayer = true
    layer?.backgroundColor = NSColor.systemBlue.cgColor
    // macOS views can be created here
    createNativeView(view: self)
  }

    required init?(coder nsCoder: NSCoder) {
        super.init(coder: nsCoder)
    }

  func createNativeView(view _view: NSView) {
    let nativeLabel = NSTextField()
    nativeLabel.frame = CGRect(x: 0, y: 0, width: 180, height: 48.0)
    nativeLabel.stringValue = "Native text from macOS"
    nativeLabel.textColor = NSColor.black
    nativeLabel.font = NSFont.systemFont(ofSize: 14)
    nativeLabel.isBezeled = false
    nativeLabel.focusRingType = .none
    nativeLabel.isEditable = true
    nativeLabel.sizeToFit()
    _view.addSubview(nativeLabel)
  }
}

Finalmente, registra la vista de plataforma. Esto se puede hacer en una aplicación o en un plugin.

Para el registro de la aplicación, modifica el MainFlutterWindow.swift de la aplicación:

MainFlutterWindow.swift
swift
import Cocoa
import FlutterMacOS

class MainFlutterWindow: NSWindow {
  override func awakeFromNib() {
    // ...

    let registrar = flutterViewController.registrar(forPlugin: "plugin-name")
    let factory = NativeViewFactory(messenger: registrar.messenger)
    registrar.register(
      factory,
      withId: "<platform-view-type>")
  }
}

Para el registro de plugins, modifica el archivo principal del plugin:

Plugin.swift
swift
import Cocoa
import FlutterMacOS

public class Plugin: NSObject, FlutterPlugin {
  public static func register(with registrar: FlutterPluginRegistrar) {
    let factory = NativeViewFactory(messenger: registrar.messenger)
    registrar.register(factory, withId: "<platform-view-type>")
  }
}

Para obtener más información, consulta la documentación de la API de:

Juntando todo

#

When implementing the build() method in Dart, you can use defaultTargetPlatform to detect the platform, and decide which widget to use:

dart
Widget 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>{};

  switch (defaultTargetPlatform) {
    case TargetPlatform.android:
    // return widget on Android.
    case TargetPlatform.iOS:
    // return widget on iOS.
    case TargetPlatform.macOS:
    // return widget on macOS.
    default:
      throw UnsupportedError('Unsupported platform view');
  }
}

Rendimiento

#

Platform Views en Flutter conllevan compromisos de rendimiento.

Por ejemplo, en una aplicación de Flutter típica, la interfaz de usuario de Flutter se compone en un hilo de rasterización dedicado. Esto permite que las aplicaciones de Flutter sean rápidas, ya que este hilo rara vez se bloquea.

Cuando una vista de plataforma se renderiza con composición híbrida, la interfaz de usuario de Flutter se sigue componiendo desde el hilo de rasterización dedicado, pero la vista de plataforma realiza operaciones gráficas en el hilo de la plataforma. Para rasterizar el contenido combinado, Flutter realiza una sincronización entre su hilo de rasterización y el hilo de la plataforma. Como tal, cualquier operación lenta o bloqueante en el hilo de la plataforma puede afectar negativamente al rendimiento gráfico de Flutter.