Skip to content
Blog

flutter build swift-package: Embedding Flutter in an iOS App the CocoaPods-Free Way

The flutter build swift-package command packages your Flutter app or module as a Swift Package for add-to-app. Here's the full workflow.

Published on • October 19, 2026

AI Assistant

Starting with Flutter 3.44 (May 2026), Swift Package Manager replaced CocoaPods as the default dependency manager for iOS and macOS apps, and the Flutter CLI migrates your Xcode project automatically when you build. What got less attention is the add-to-app side of that shift: the same release introduced a new command, flutter build swift-package, that packages your Flutter application or add-to-app module as a Swift Package your native iOS project can consume directly.

If you maintain an existing UIKit or SwiftUI app and embed Flutter screens in it, this command is the new front door. Here’s the complete workflow as documented in What’s new in Flutter 3.44 and the current add-to-app iOS setup guide.

What the command does

flutter build swift-package --platform ios

Run inside your Flutter app or module, it produces two directories under build/ios/SwiftPackages/:

  • FlutterNativeIntegration/ — the Swift package containing your Flutter app’s artifacts, ready to be added to an Xcode project.
  • Scripts/ — the helper scripts and file lists your Xcode build phases call (flutter_integration.sh, FlutterAssembleInputs.xcfilelist, flutter_lldbinit).

You can redirect the output with --output if your repository layout doesn’t match the default. Prerequisites are modest: Flutter 3.44 or later and Xcode 15.0 or later.

The output location matters for how you structure repos. The docs assume your Flutter project and native app are sibling directories:

my_flutter_app/          # your Flutter app
  ios/
  lib/main.dart
MyNativeApp/             # your existing native iOS app
  MyNativeApp.xcodeproj/

From command to working Xcode build

The command is one step; the integration is a handful of Xcode settings that the docs walk through in full. The shape of it:

1. Add the generated package. In Xcode, right-click your project → Add Files to “MyNativeApp”…, select the generated FlutterNativeIntegration package, choose Reference files in place, and confirm its location is Relative to Project. Then add it under your target’s Frameworks, Libraries, and Embedded Content.

2. Point Xcode at the output. In Build Settings:

FLUTTER_SWIFT_PACKAGE_OUTPUT = $SRCROOT/../my_flutter_app/build/ios/SwiftPackages

If you use custom configurations, also map them to a Flutter build mode with FLUTTER_BUILD_MODE (debug, profile, or release), since build mode is otherwise derived from CONFIGURATION.

3. Let Xcode rebuild Flutter for you (optional but recommended). Two build settings make Xcode re-run your Flutter build as part of its own build, so you don’t shell out to flutter build after every Dart change:

FLUTTER_APPLICATION_PATH = $SRCROOT/../my_flutter_app
ENABLE_USER_SCRIPT_SANDBOXING = NO

Caveat from the docs: this rebuilds your Flutter code. If you add new dependencies (a new plugin, a new asset), you still need to re-run flutter build swift-package.

4. Wire up the scripts. Add a Pre-action Run Script to your scheme’s Build phase:

/bin/sh $FLUTTER_SWIFT_PACKAGE_OUTPUT/Scripts/flutter_integration.sh prebuild

and a Run Script Build Phase on your target:

/bin/sh $FLUTTER_SWIFT_PACKAGE_OUTPUT/Scripts/flutter_integration.sh assemble

with $(FLUTTER_SWIFT_PACKAGE_OUTPUT)/Scripts/FlutterAssembleInputs.xcfilelist as an input file list, and Based on dependency analysis unchecked.

5. Fix debugging. Setting your scheme’s LLDB Init File to $(FLUTTER_SWIFT_PACKAGE_OUTPUT)/Scripts/flutter_lldbinit improves debugging performance on physical iOS 26+ devices.

Migrating from an existing CocoaPods or framework integration

If you integrated Flutter before SwiftPM — via CocoaPods or embedded frameworks — you must remove that integration first; the legacy guide is preserved read-only at add-to-app/ios/project-setup-legacy. Two facts make the migration time-sensitive:

  • Flutter supports CocoaPods in maintenance mode only.
  • The CocoaPods specs registry becomes read-only on December 2, 2026, per the CocoaPods announcement.

Plugins that still require CocoaPods trigger a CLI warning and a temporary fallback, and they’re the long pole in any migration — nudging their maintainers (or forking) is part of the job. SwiftPM-supporting packages also earn extra points in pub.dev scoring, so the ecosystem incentive is aligned.

Two more integration details worth remembering:

  • Local network privacy. Enable the Dart multicast DNS service (Bonjour Services) only in your Debug configuration — never in Release, or Apple may reject the app. The docs show how to split Info.plist per build configuration.
  • There’s a patch release that matters here. Flutter 3.47.1 fixed a race condition in SwiftPM integration that could throw FileSystemException when building multi-target applications in parallel (#188446). If your add-to-app CI builds concurrently, be on at least that patch.

Day-to-day workflow

Once wired up, the loop looks like this:

# Iterate on Flutter code
cd my_flutter_app
flutter run                 # or build from Xcode after setting FLUTTER_APPLICATION_PATH

# After adding a dependency or changing native plugin configuration
flutter build swift-package --platform ios

Your native team keeps working in Xcode with no Ruby, no pod install, and no CocoaPods trunk in the build path — the exact pitch Flutter made in 3.44, now applied to embedded Flutter as well as full apps.

Troubleshooting the integration

A few failure modes show up repeatedly with this workflow:

  • Package not found in Xcode. The FlutterNativeIntegration package must be referenced in place with location Relative to Project. If the location resolves differently after a move or rename, rebuild the package and re-add it.
  • Stale Flutter code in Release builds. If you didn’t set FLUTTER_APPLICATION_PATH, Xcode won’t re-run your Flutter build — run flutter build swift-package manually after every Dart change, and definitely before archiving.
  • New plugin not visible to the app. Adding a dependency requires re-running flutter build swift-package; code-only changes don’t.
  • pod install-era leftovers. A stray Podfile or embedded framework reference from a legacy integration will fight the SwiftPM path — complete the legacy removal steps first rather than debugging the new setup against old artifacts.

None of these are exotic, and the project-setup doc covers each one with screenshots. The command itself is deliberately boring — it generates a package and scripts; the integration stays visible in Xcode’s build settings where your iOS team already works.

Sources