向 macOS 应用添加 Flutter 屏幕
了解如何向你现有的 macOS 应用添加单个 Flutter 屏幕。
本指南介绍如何向现有 macOS 应用添加单个 Flutter 屏幕。
启动 FlutterEngine 与 FlutterViewController
#
要从现有 macOS 应用启动 Flutter 屏幕,需要启动 FlutterEngine
与 FlutterViewController。
FlutterEngine 的生命周期可能与 FlutterViewController 相同,也可能更长。
有关预热引擎在延迟与内存方面的权衡,请参阅 加载顺序与性能。
创建 FlutterEngine
#创建 FlutterEngine 的位置取决于宿主应用。
本示例在名为 FlutterDependencies 的 SwiftUI Observable
对象内创建 FlutterEngine,通过调用 run() 预热引擎,再使用 environment() 视图修饰符将其注入
ContentView。
import SwiftUI
import FlutterMacOS
// The following library connects plugins with macOS platform code to this app.
import FlutterPluginRegistrant
@Observable
class FlutterDependencies {
let flutterEngine = FlutterEngine(name: "my flutter engine", project: nil)
init() {
// Runs the default Dart entrypoint with a default Flutter route.
flutterEngine.run(withEntrypoint: nil)
// Connects plugins with macOS platform code to this app.
RegisterGeneratedPlugins(registry: self.flutterEngine)
}
}
@main
struct MyApp: App {
// flutterDependencies will be injected through the view environment.
@State var flutterDependencies = FlutterDependencies()
var body: some Scene {
WindowGroup {
ContentView()
.environment(flutterDependencies)
}
}
}
作为示例,我们在应用委托的应用启动时创建并暴露为属性的 FlutterEngine。
import Cocoa
import FlutterMacOS
// The following library connects plugins with macOS platform code to this app.
import FlutterPluginRegistrant
@main
class AppDelegate: FlutterAppDelegate {
lazy var flutterEngine = FlutterEngine(name: "my flutter engine", project: nil)
override func applicationDidFinishLaunching(_ aNotification: Notification) {
flutterEngine.run(withEntrypoint: nil)
RegisterGeneratedPlugins(registry: self.flutterEngine)
}
}
使用 FlutterEngine 显示 FlutterViewController
#
以下示例展示带有连接到 Flutter 屏幕的 NavigationLink
的通用 ContentView。首先创建 FlutterViewControllerRepresentable 表示 FlutterViewController。FlutterViewController
构造函数接收预热的 FlutterEngine 作为参数,通过视图环境注入。
import SwiftUI
import FlutterMacOS
struct FlutterViewControllerRepresentable: NSViewControllerRepresentable {
// Flutter dependencies are passed in through the view environment.
@Environment(FlutterDependencies.self) var flutterDependencies
func makeNSViewController(context: Context) -> FlutterViewController {
return FlutterViewController(
engine: flutterDependencies.flutterEngine,
nibName: nil,
bundle: nil
)
}
func updateNSViewController(_ nsViewController: FlutterViewController, context: Context) {}
}
struct ContentView: View {
var body: some View {
NavigationStack {
NavigationLink("My Flutter Feature") {
FlutterViewControllerRepresentable()
}
}
}
}
现在,你已在 macOS 应用中嵌入了 Flutter 屏幕。
以下示例展示带有 NSButton 的通用 ViewController,用于呈现 FlutterViewController。FlutterViewController
使用在 AppDelegate 中创建的 FlutterEngine 实例。
import Cocoa
import FlutterMacOS
class ViewController: NSViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Make a button to call the showFlutter function when pressed.
let button = NSButton(title: "Show Flutter!", target: self, action: #selector(showFlutter))
button.frame = CGRect(x: 202, y: 187, width: 160.0, height: 40.0)
self.view.addSubview(button)
}
@objc func showFlutter() {
let flutterEngine = (NSApplication.shared.delegate as! AppDelegate).flutterEngine
let flutterViewController =
FlutterViewController(engine: flutterEngine, nibName: nil, bundle: nil)
self.addChild(flutterViewController)
flutterViewController.view.frame = self.view.bounds
presentAsModalWindow(flutterViewController)
}
}
现在,你已在 macOS 应用中嵌入了 Flutter 屏幕。
另一种方式 — 使用隐式 FlutterEngine 创建 FlutterViewController
#作为上一示例的替代,可让 FlutterViewController 隐式创建自己的 FlutterEngine,而无需事先预热。
通常不推荐这样做,因为按需创建 FlutterEngine 可能在呈现 FlutterViewController 与渲染首帧之间引入明显延迟。但若 Flutter 屏幕很少显示、难以判断何时应启动 Dart VM,且 Flutter 无需在 view controller 之间保持状态时,这种方式可能有用。
要让 FlutterViewController 在没有现有 FlutterEngine 的情况下呈现,省略 FlutterEngine
的构建,并创建不带引擎引用的 FlutterViewController。
// Existing code omitted.
func makeNSViewController(context: Context) -> FlutterViewController {
return FlutterViewController()
}
// Existing code omitted.
func showFlutter() {
let flutterViewController = FlutterViewController()
self.addChild(flutterViewController)
flutterViewController.view.frame = self.view.bounds
presentAsModalWindow(flutterViewController)
}
有关延迟与内存使用的更多探讨,请参阅 加载顺序与性能。
使用 FlutterAppDelegate
#建议(但非必须)让应用的 UIApplicationDelegate 子类化 FlutterAppDelegate。
FlutterAppDelegate 执行的功能包括:
-
Forwarding application callbacks such as
openURLsto plugins such as google_sign_in. -
将
openURLs等应用回调转发给 google_sign_in 等插件。
创建 FlutterAppDelegate 子类
#
在 UIKit 应用中创建 FlutterAppDelegate 子类的方法见 启动 FlutterEngine 与 FlutterViewController 一节。在 SwiftUI 应用中,可创建
FlutterAppDelegate 子类并用 Observable()
宏标注,如下所示:
import SwiftUI
import FlutterMacOS
@Observable
class AppDelegate: FlutterAppDelegate {
let flutterEngine = FlutterEngine(name: "my flutter engine", project: nil)
override func applicationDidFinishLaunching(_ aNotification: Notification) {
// Runs the default Dart entrypoint with a default Flutter route.
flutterEngine.run(withEntrypoint: nil)
// Used to connect plugins (only if you have plugins
// with macOS platform code).
RegisterGeneratedPlugins(registry: self.flutterEngine)
}
}
@main
struct MyApp: App {
// Use this property wrapper to tell SwiftUI
// it should use the AppDelegate class for the application delegate
@NSApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
随后,在视图中可通过视图环境访问 AppDelegate。
import SwiftUI
import FlutterMacOS
struct FlutterViewControllerRepresentable: NSViewControllerRepresentable {
// Access the AppDelegate through the view environment.
@Environment(AppDelegate.self) var appDelegate
func makeNSViewController(context: Context) -> FlutterViewController {
return FlutterViewController(
engine: appDelegate.flutterEngine,
nibName: nil,
bundle: nil
)
}
func updateNSViewController(_ nsViewController: FlutterViewController, context: Context) {}
}
struct ContentView: View {
var body: some View {
NavigationStack {
NavigationLink("My Flutter Feature") {
FlutterViewControllerRepresentable()
}
}
}
}
除非另有说明,本文档之所提及适用于 Flutter 3.44.0 版本。本页面最后更新时间:2026-06-04。查看文档源码 或者 为本页面内容提出建议。