LingCode 将你的 Flutter 仓库作为设计规格而非翻译源,从零开始编写地道的 SwiftUI、Jetpack Compose 和 macOS SwiftUI 代码。输出中没有 Dart,也没有"Flutter 风味"的原生代码。分五个阶段规划,防止 LingCode 中途跑偏。
最直觉的做法是将每个 Flutter widget 一一映射到对应的原生组件,然后祈祷它们能组合在一起。但这行不通。有三个问题会接连爆发:
Provider 在 iOS 上变成 @Observable+@Environment,在 Android 上变成 ViewModel+StateFlow。照字面翻译只会产生别扭的混合体。Container 只是一个 widget,在 SwiftUI 中变成三个修饰符,在 Compose 中变成带修饰符的 Box。逐 widget 翻译只会带来层层嵌套的噪音。MethodChannel 都是在各平台手写的原生钩子。伪造它们只会产生运行时的隐性崩溃。读取 Flutter 源码中的意图——有哪些页面、如何跳转、数据怎么流动——然后从头编写原生版本,才能产出原生开发者真正愿意维护的代码。
pubspec.yaml。ios/、android/ 和 macos/。迁移期间 Flutter 应用保持完整。打开聊天面板,让 LingCode 扫描 Flutter 仓库并输出一份转换计划。下面这个提示词很管用:
Read this Flutter repo and write CONVERSION_PLAN.md in
../native-output/. Summarize:
- pubspec.yaml: deps, Flutter SDK constraint, assets, fonts.
- lib/ tree: every screen/route and its purpose.
- State management: Provider / Riverpod / Bloc / GetX / setState.
- Data layer: HTTP client, local DB (sqflite/Hive/Isar), shared prefs.
- Platform channels and native plugins, listed one by one.
- Theme, typography, color tokens, l10n strings.
- Gotchas: BackdropFilter, CustomPainter, ShaderMask, FFI plugins,
native ads SDKs, Firebase Crashlytics — anything without a clean
native mapping.
Don't start porting yet. Stop after the plan.
LingCode 会读取仓库、扫描时建立待办列表,并生成 CONVERSION_PLAN.md。在批准任何代码生成之前,先仔细阅读这份文件。"注意事项"那一节决定了这个项目是两周工作还是两个月工作。
针对每个目标平台,LingCode 需要在生成代码之前确定架构选型。让它在计划中追加各平台的架构章节:
Append to CONVERSION_PLAN.md a section for each of iOS, Android,
macOS that picks:
- Navigation pattern: NavigationStack on Apple, NavHost on Android.
- DI / state container: @Observable+@Environment, or ViewModel+
StateFlow, etc. Match the original Flutter state idiom.
- Networking layer: URLSession + async/await (Apple), OkHttp/Retrofit
(Android), or shared via Ktor if there's a reason to.
- Persistence: SwiftData / Core Data / GRDB (Apple), Room (Android).
- Asset pipeline: where pubspec assets land in each native project.
Where the screen makes sense on macOS, share SwiftUI views between
iOS and macOS — don't duplicate.
这是最后一个廉价的决策点。在这里选错导航模式,意味着之后每个页面都要重写。请像做代码评审一样认真阅读架构章节。
现在让 LingCode 创建空项目:
Scaffold the iOS, Android, and macOS projects in ../native-output/.
Use Xcode's project format for iOS and macOS (don't hand-write
.xcodeproj XML). Use Gradle for Android (don't hand-write
build.gradle). Bundle IDs:
- iOS: com.yourcompany.yourapp
- Android: com.yourcompany.yourapp
- macOS: com.yourcompany.yourapp.mac
LingCode 使用原生脚手架工具完成这一步——生成的结构与 Xcode 和 Android Studio 新建项目时相同。你应该能在 Xcode 中打开 ios/YourApp.xcodeproj,在 Android Studio 中打开 android/,并让两者都能成功构建空模板。
这是最耗时的阶段。让 LingCode 一次迁移一个页面,用待办列表追踪进度:
Port screens from lib/screens/ to the native projects, one screen
per todo item. For each screen:
1. Read the Flutter widget for intent — screen layout, state flow,
navigation in and out.
2. Write the SwiftUI view (iOS + macOS where it makes sense).
3. Write the Compose composable (Android).
4. Wire navigation in both NavigationStack and NavHost.
5. Wire state into the chosen container.
For widgets with no clean native mapping, stub with
// TODO(flutter-to-native): ... and log it in CONVERSION_PLAN.md
under "deferred." Don't fake behavior.
Start with the home screen. Stop after each screen for me to review.
"每个页面后停下来"这条指令很重要。让 LingCode 一口气跑完 20 个页面再做检查,等于把所有问题留到最后才发现,那时架构偏差已经很难纠正了。
如果你想抽查 LingCode 的转换结果,以下是它遵循的映射关系:
Container/Padding/Center → 带 .padding 修饰符的 VStack/HStack/ZStackRow / Column → HStack / VStackListView → ListGridView → LazyVGridNavigator.push → NavigationStack(path:)FutureBuilder → .task + @StateStreamBuilder → AsyncSequence + .taskTextField → TextField + @FocusStateGestureDetector → .onTapGesture / .gestureAnimatedContainer → .animationHero → matched-geometry effectSafeArea → .safeAreaInset / .ignoresSafeAreaContainer → BoxRow / Column → Row / ColumnListView → LazyColumnGridView → LazyVerticalGridNavigator → NavHost + NavControllerFutureBuilder → collectAsStateWithLifecycleTextField → TextField + FocusRequesterAnimatedContainer → animate*AsStateHero → Modifier.sharedElementSafeArea → WindowInsets@Observable + @Environment(Apple)/ ViewModel + StateFlow(Android)ViewModelsetState → @State(Apple)/ remember(Compose)有些 Flutter 功能没有诚实的原生映射。LingCode 会在 CONVERSION_PLAN.md 中为它们生成存根并记录,而不是胡乱猜测——你来决定每一项怎么处理:
MethodChannel 都是在 iOS 和 Android 上手写的原生钩子——你自己写的 Swift 方法和 Kotlin 函数。LingCode 只会为调用点生成存根。AppDelegate(iOS)和 Application(Android)中初始化,不能放在共享层。onKeyPress,Android 有 onKeyEvent——可以用,但不是字面映射。不要让 LingCode 为这些内容编造行为。诚实的存根胜过信心满满却错误的代码。
逐屏迁移完成后,让 LingCode 验证每个平台的构建:
For each target, run the build and report pass/fail:
- iOS: xcodebuild -project ios/YourApp.xcodeproj
-scheme YourApp -destination 'generic/platform=iOS Simulator'
build
- Android: cd android && ./gradlew assembleDebug
- macOS: xcodebuild -project macos/YourApp.xcodeproj
-scheme YourApp build
If a target fails, diagnose and fix before moving on. Don't claim
done until every requested platform builds clean.
这个阶段可以使用 LingCode 的并行智能体——每个平台一个——来压缩整体耗时。各平台互相独立,iOS 的失败不会阻塞 Android。
原生项目能构建,但真正的考验是功能对等。同时在模拟器中打开原始 Flutter 应用和新的 iOS 构建,逐屏对比行为——导航、动画、错误状态、空列表和断网等边缘情况。
LingCode 通过运行目标选择器(⌘R)直接启动 iOS 模拟器和 Android 模拟器——日常测试不需要单独开 Xcode 或 Android Studio 窗口。当你需要 ADB 工具链、性能分析器或 AVD 管理时,再打开 Android Studio。
flutter 嵌入,没有"add-to-app"。如果你想要那种方式,就不需要这篇教程了。pub get,没有 flutter build,没有任何编辑——LingCode 将其视为只读规格。整套工作流已打包为一个技能——将它放入你的 LingCode 技能目录,然后对 LingCode 说"flutter to native"即可自动调用:
---
name: flutter-to-native
description: Convert a Flutter app to native iOS (SwiftUI), Android (Jetpack Compose), and/or macOS (SwiftUI). Reads the Flutter repo as a design spec and writes fresh idiomatic native code — zero Dart in the output. Triggers: 'migrate from Flutter', 'rewrite Flutter app in native', 'flutter to swiftui', 'flutter to compose', 'flutter to native', existing pubspec.yaml, lib/main.dart. Actions: inventory Flutter app, propose native architecture per target, scaffold ios/ android/ macos/, port screen-by-screen, verify each build clean. Anti-pattern: Flutter embed, add-to-app, faked platform channels. Five phases with checkpoints.
---
Convert a Flutter app to native. Treat the Flutter repo as a design
spec, not source to translate. Read it to understand intent
(screens, navigation, state, data), then write idiomatic native
code from scratch.
Phase 1 — Inventory: scan pubspec, lib/, state mgmt, data layer,
platform channels, theme, gotchas. Write CONVERSION_PLAN.md.
Phase 2 — Architecture per target: navigation, DI, networking,
persistence, asset pipeline.
Phase 3 — Scaffold ios/, android/, macos/.
Phase 4 — Port screen by screen, one todo per screen.
Phase 5 — Verify each target builds clean.
Stop after each phase for user review. Stub deferred items with
// TODO(flutter-to-native): ... rather than faking behavior.
保存为 ~/.lingcode/skills/flutter-to-native/SKILL.md——具体位置以及技能如何被发现,请参阅安装技能。