Token导航 LogoToken导航TokenDH.com
前端设计需要联网github未标认证来源可访问许可证需确认审计通过

flutter-platform-viewsFlutter platform views 命令行

Agent Skill

flutter-platform-views 用于处理 GitHub 仓库、Issue、Pull Request 和代码协作信息,适合在 Codex、Claude、Cursor、Gemini CLI 中需要围绕仓库状态、代码变更或协作事项进行整理时使用。可结合来源仓库、安装命令和原始 README 继续核验具体用法。安装前建议确认权限范围、维护状态,以及是否会触发联网、命令执行或文件读写。

总安装

23,837

周安装

955

GitHub Stars

1,323

下载量

7,716
CodexClaudeCursorGemini CLI

安装说明

本站只整理中文说明和来源信息,不托管安装包,也不代用户安装。

GitHub

来源数

2

许可证

unknown

最后核验

2026-05-01

来源状态

来源可访问

安装方式

通过对话安装

复制提示词发给支持本地命令或 Skills 的 AI 助手,先确认命令和权限,再让它执行。

请帮我安装这个 Agent Skill:flutter-platform-views(Flutter platform views 命令行)
来源仓库:https://github.com/flutter/skills
仓库路径:skills/flutter-platform-views
安装命令:
npx skills add https://github.com/flutter/skills --skill flutter-platform-views
安装前请先检查当前环境是否支持对应 CLI,并向我确认将要执行的命令、安装目录、联网范围和文件读写权限;确认后再执行。

命令行安装

复制命令到本机终端执行。该命令会通过 npx skills 从第三方来源获取 Skill;本站只展示命令,不托管安装包,也不自动执行。

skills.shnpx skills
npx skills add https://github.com/flutter/skills --skill flutter-platform-views

简介

将本机视图和 Web 内容嵌入到 Android、iOS、macOS 和 Web 平台上的 Flutter 应用程序中。

  • 支持 Android 混合合成(原生保真度)和纹理层(Flutter 性能)、iOS/macOS 混合合成以及网页全页或嵌入式多视图模式
  • 提供完整的 Dart 和本机代码模板(适用于 Android 的 Kotlin、适用于 iOS/macOS 的 Swift、适用于 Web 的 JavaScript)以及工厂注册模式
  • 在实施之前需要预先决策树来确定目标平台和嵌入策略
  • 包括 Android API 23+ 的验证检查、SurfaceView 的手动视图失效以及多视图 Web 约束(runWidget 而不是 runApp)

SKILL.md

flutter-platform-views-and-web-embedding

Goal

Guides developers through implementing Flutter Platform Views for Android, iOS, and macOS, as well as embedding Flutter into existing web applications. Assumes the user has a configured Flutter environment and is comfortable with Dart, JavaScript, and the relevant native platform languages (Kotlin, Swift).

Instructions

1. Determine the Target Platform and Embedding Strategy (Decision Logic)

Before writing code, you must determine the target platform and the specific embedding strategy required by the user.

STOP AND ASK THE USER: "Which platform are you targeting for native view embedding?

  1. Android (Requires choosing between Hybrid Composition or Texture Layer)
  2. iOS (Hybrid Composition only)
  3. macOS (Hybrid Composition only, gesture support limited)
  4. Web (Requires choosing between Full Page mode or Embedded/Multi-view mode)"

Decision Tree:

  • If Android: Ask the user: "Do you prioritize native Android view fidelity (Hybrid Composition) or Flutter rendering performance (Texture Layer)?"
  • If Web: Ask the user: "Are you taking over the full page, or embedding Flutter into specific HTML elements (Embedded/Multi-view mode)?"

2. Implement Android Platform Views

Based on the user's choice in Step 1, implement the Dart and Kotlin sides.

Dart Implementation: If the user chose Hybrid Composition (Best fidelity, lower Flutter FPS):

import 'package:flutter/foundation.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart';

Widget buildHybridAndroidView(BuildContext context, String viewType, Map<String, dynamic> creationParams) {
  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();
    },
  );
}

If the user chose Texture Layer (Best Flutter FPS, janky quick scrolling):

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

Widget buildTextureAndroidView(BuildContext context, String viewType, Map<String, dynamic> creationParams) {
  return AndroidView(
    viewType: viewType,
    layoutDirection: TextDirection.ltr,
    creationParams: creationParams,
    creationParamsCodec: const StandardMessageCodec(),
  );
}

Kotlin Implementation (Platform Side): Create the View, the Factory, and register it in the MainActivity.

package dev.flutter.example

import android.content.Context
import android.graphics.Color
import android.view.View
import android.widget.TextView
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.StandardMessageCodec
import io.flutter.plugin.platform.PlatformView
import io.flutter.plugin.platform.PlatformViewFactory

// 1. Define the View
internal class NativeView(context: Context, id: Int, creationParams: Map<String?, Any?>?) : PlatformView {
    private val textView: TextView = TextView(context).apply {
        textSize = 72f
        setBackgroundColor(Color.rgb(255, 255, 255))
        text = "Rendered on a native Android view (id: $id)"
    }
    override fun getView(): View = textView
    override fun dispose() {}
}

// 2. Define the Factory
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)
    }
}

// 3. Register in MainActivity
class MainActivity : FlutterActivity() {
    override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
        super.configureFlutterEngine(flutterEngine)
        flutterEngine
            .platformViewsController
            .registry
            .registerViewFactory("<platform-view-type>", NativeViewFactory())
    }
}

*Validate-and-Fix:* If the user is embedding a SurfaceView or SurfaceTexture, instruct them to manually call invalidate() on the view when content changes, as they do not invalidate themselves automatically.

3. Implement iOS Platform Views

iOS uses Hybrid Composition exclusively.

Dart Implementation:

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

Widget buildIosView(BuildContext context, String viewType, Map<String, dynamic> creationParams) {
  return UiKitView(
    viewType: viewType,
    layoutDirection: TextDirection.ltr,
    creationParams: creationParams,
    creationParamsCodec: const StandardMessageCodec(),
  );
}

Swift Implementation (Platform Side):

import Flutter
import UIKit

// 1. Define the View
class FLNativeView: NSObject, FlutterPlatformView {
    private var _view: UIView

    init(frame: CGRect, viewIdentifier viewId: Int64, arguments args: Any?, binaryMessenger messenger: FlutterBinaryMessenger?) {
        _view = UIView()
        super.init()
        createNativeView(view: _view)
    }

    func view() -> UIView { return _view }

    func createNativeView(view _view: UIView){
        _view.backgroundColor = UIColor.blue
        let nativeLabel = UILabel()
        nativeLabel.text = "Native text from iOS"
        nativeLabel.textColor = UIColor.white
        nativeLabel.textAlignment = .center
        nativeLabel.frame = CGRect(x: 0, y: 0, width: 180, height: 48.0)
        _view.addSubview(nativeLabel)
    }
}

// 2. Define the Factory
class FLNativeViewFactory: NSObject, FlutterPlatformViewFactory {
    private var messenger: FlutterBinaryMessenger

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

    func create(withFrame frame: CGRect, viewIdentifier viewId: Int64, arguments args: Any?) -> FlutterPlatformView {
        return FLNativeView(frame: frame, viewIdentifier: viewId, arguments: args, binaryMessenger: messenger)
    }

    public func createArgsCodec() -> FlutterMessageCodec & NSObjectProtocol {
          return FlutterStandardMessageCodec.sharedInstance()
    }
}

// 3. Register in AppDelegate
@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
    override func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]?
    ) -> Bool {
        GeneratedPluginRegistrant.register(with: self)
        guard let pluginRegistrar = self.registrar(forPlugin: "plugin-name") else { return false }

        let factory = FLNativeViewFactory(messenger: pluginRegistrar.messenger())
        pluginRegistrar.register(factory, withId: "<platform-view-type>")

        return super.application(application, didFinishLaunchingWithOptions: launchOptions)
    }
}

4. Implement macOS Platform Views

macOS uses Hybrid Composition. Note that gesture support is currently limited.

Dart Implementation:

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

Widget buildMacOsView(BuildContext context, String viewType, Map<String, dynamic> creationParams) {
  return AppKitView(
    viewType: viewType,
    layoutDirection: TextDirection.ltr,
    creationParams: creationParams,
    creationParamsCodec: const StandardMessageCodec(),
  );
}

Swift Implementation (Platform Side):

import Cocoa
import FlutterMacOS

// 1. Define the View
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
    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.isEditable = false
    nativeLabel.sizeToFit()
    _view.addSubview(nativeLabel)
  }
}

// 2. Define the Factory
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)
  }
  public func createArgsCodec() -> (FlutterMessageCodec & NSObjectProtocol)? {
    return FlutterStandardMessageCodec.sharedInstance()
  }
}

// 3. Register in MainFlutterWindow.swift
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>")
    super.awakeFromNib()
  }
}

5. Implement Web Embedding

If the user chose Embedded/Multi-view mode, implement the JS and Dart configurations.

JavaScript Implementation (flutter_bootstrap.js or HTML script):

_flutter.loader.load({
  onEntrypointLoaded: async function onEntrypointLoaded(engineInitializer) {
    let engine = await engineInitializer.initializeEngine({
      multiViewEnabled: true, // Enables embedded mode.
    });
    let app = await engine.runApp();

    // Add a view to a specific host element
    let viewId = app.addView({
      hostElement: document.querySelector('#flutter-host-element'),
      initialData: { greeting: 'Hello from JS!' }
    });
  }
});

Dart Implementation (main.dart): *Validate-and-Fix:* Ensure runWidget is used instead of runApp. runApp will fail with a null implicitView error in multi-view mode.

import 'dart:ui' show FlutterView;
import 'package:flutter/widgets.dart';

void main() {
  // MUST use runWidget, not runApp, for multi-view web embedding.
  runWidget(
    MultiViewApp(
      viewBuilder: (BuildContext context) => const MyEmbeddedWidget(),
    ),
  );
}

class MultiViewApp extends StatefulWidget {
  const MultiViewApp({super.key, required this.viewBuilder});
  final WidgetBuilder viewBuilder;

  @override
  State<MultiViewApp> createState() => _MultiViewAppState();
}

class _MultiViewAppState extends State<MultiViewApp> with WidgetsBindingObserver {
  Map<Object, Widget> _views = <Object, Widget>{};

  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance.addObserver(this);
    _updateViews();
  }

  @override
  void didChangeMetrics() {
    _updateViews();
  }

  void _updateViews() {
    final Map<Object, Widget> newViews = <Object, Widget>{};
    for (final FlutterView view in WidgetsBinding.instance.platformDispatcher.views) {
      final Widget viewWidget = _views[view.viewId] ?? _createViewWidget(view);
      newViews[view.viewId] = viewWidget;
    }
    setState(() {
      _views = newViews;
    });
  }

  Widget _createViewWidget(FlutterView view) {
    return View(
      view: view,
      child: Builder(builder: widget.viewBuilder),
    );
  }

  @override
  void dispose() {
    WidgetsBinding.instance.removeObserver(this);
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return ViewCollection(views: _views.values.toList(growable: false));
  }
}

class MyEmbeddedWidget extends StatelessWidget {
  const MyEmbeddedWidget({super.key});

  @override
  Widget build(BuildContext context) {
    // Retrieve the viewId to handle specific logic if needed
    final int viewId = View.of(context).viewId;
    return Directionality(
      textDirection: TextDirection.ltr,
      child: Center(child: Text('Rendered in View ID: $viewId')),
    );
  }
}

Constraints

  • Do not use runApp when configuring Flutter Web for multi-view embedding. You must use runWidget and manage the FlutterView lifecycle via WidgetsBindingObserver.
  • Do not use ShaderMask or ColorFiltered widgets over iOS Platform Views, as they are unsupported. BackdropFilter has strict limitations.
  • Do not assume Android SurfaceView or SurfaceTexture will automatically invalidate when their content changes. You must manually call invalidate() on the view or its parent.
  • Do not wrap the entire output in a markdown code block. Return raw markdown text.
  • Always verify the Android API level is 23+ before implementing Platform Views.

适合场景

01

用户想查找某类 Agent Skill 时

02

需要根据任务场景推荐可安装能力包时

03

需要对比不同来源的安装命令和来源信息时

能力概览

能力 1

按任务关键词查找相关 Skills

能力 2

展示可复制的安装命令

能力 3

保留来源站点、仓库和原始说明,方便继续核验

能力 4

展示第三方安全扫描或审计结果

安装后应在对应宿主中按原始 README 的触发条件使用;具体调用方式请以来源页面和 README 为准。

平台分布

Codex

33.39%
按下载量换算2,576

Claude

32.78%
按下载量换算2,529

Cursor

17.33%
按下载量换算1,337

Gemini CLI

9.88%
按下载量换算762

安全审计

Gen Agent Trust Hub

通过

Socket

通过

Snyk

通过

权限和风险

需要联网

该 Skill 可能需要联网访问来源站点、仓库或外部 API;具体网络访问范围需要结合源码和 README 复核。

安装前确认

本站仅展示第三方公开信息,不托管安装包,不提供自动安装或运行环境。安装前应自行审查源码、依赖和命令行为。当前只有一个来源,正式发布前建议补源仓库或其他目录站核验。

来源信息

继续浏览同类 Skills