# Integrate a Flutter app into your iOS project

> Learn how to integrate a Flutter app into your existing iOS project.



:::note
As of the 3.44 release, Flutter uses [Swift Package Manager][]
to manage iOS and macOS native dependencies.
Flutter continues to support CocoaPods in maintenance mode,
however, the CocoaPods registry permanently becomes
[read-only on December 2, 2026][cocoapods].
:::

[cocoapods]: https://blog.cocoapods.org/CocoaPods-Specs-Repo/
[Swift Package Manager]: https://www.swift.org/documentation/package-manager/

Flutter UI components can be incrementally added
into your existing iOS application using Swift packages.

## Prerequisites

* Flutter 3.44 or later
* Xcode 15.0 or later

### Migrate from legacy integration (if applicable) {: #migrate-legacy-integration}

If you've already integrated Flutter into your iOS app
using CocoaPods or embedded frameworks,
you must first remove that integration
before following the Swift Package Manager instructions below.

<details>
  <summary>Expand to see instructions to migrate from CocoaPods integration</summary>

  If your app was previously integrated using CocoaPods,
  you must first remove the Flutter installation code from your Podfile.

  1. Remove Flutter installation code from your Podfile
      ```ruby title="MyApp/Podfile" diff
      - flutter_application_path = '../my_flutter'
      - load File.join(flutter_application_path, '.ios', 'Flutter', 'podhelper.rb')

      - install_all_flutter_pods(flutter_application_path)

      - flutter_post_install(installer) if defined?(flutter_post_install)
      ```

   1. Run `pod install`.
</details>

<details>
  <summary>Expand to see instructions to migrate from embedded frameworks integration</summary>

  If your app was previously integrated using frameworks
  generated by the `flutter build ios-framework` command,
  you must first remove the frameworks from your Xcode project.

  1. Navigate to your target's General tab
     and remove all Flutter-related frameworks and libraries
     under **Frameworks, Libraries, and Embedded Content**.

       This includes the `App.xcframework`, `Flutter.xcframework`,
       `FlutterPluginRegistrant.xcframework`,
       and any Flutter plugins' `xcframework` files.

  1. Remove the Flutter pod from your Podfile
      ```ruby title="MyApp/Podfile" diff
      - pod 'Flutter', :podspec => '/path/to/MyApp/Flutter/[build mode]/Flutter.podspec'
      ```

   1. Run `pod install`.
</details>

The [legacy integration guide][] is preserved for reference,
but will not receive ongoing maintenance.

### Organize your projects relative to each other {: #organize-projects-relatively}

This guide assumes that your existing iOS app
and your Flutter app or module reside in sibling directories.
If you have a different directory structure,
you will need to adjust the example relative paths accordingly.

:::note

If integrating for the first time,
it's recommended to use a Flutter application (instead of a module).
Run the following command to create a new Flutter application:

```console
flutter create my_flutter_app
```

:::

The example directory structure resembles the following:

<Tabs key="ios-project-type">
<Tab name="Flutter App">

<FileTree>

- my_flutter_app/
  - ios/
  - lib/
    - main.dart
- MyNativeApp/
  - MyNativeApp.xcodeproj/

</FileTree>
</Tab>
<Tab name="Flutter Module">

<FileTree>

- my_flutter_app/
  - .ios/
  - lib/
    - main.dart
- MyNativeApp/
  - MyNativeApp.xcodeproj/

</FileTree>
</Tab>
</Tabs>

## Integrate with Swift Package Manager {: #integrate-with-swiftpm}

 1. <h3>Build the FlutterNativeIntegration Swift package</h3>

    Within your Flutter application or module, run the following command:

    ```console
    flutter build swift-package --platform ios
    ```

    This will generate the following directories:

    <FileTree>

    - my_flutter_app/build/ios/SwiftPackages/
      - FlutterNativeIntegration/ (A Swift package)
      - Scripts/ (Directory of scripts and other files needed)

    </FileTree>

    You can optionally change the location of this output
    with the `--output` flag.

 1. <h3>Add FlutterNativeIntegration to your Xcode project</h3>

    1. Open your existing iOS app in Xcode.
    1. In the Project navigator, right click on your project
       and select **Add Files to "MyNativeApp"...**
    1. Navigate to and select the generated
       `FlutterNativeIntegration` Swift package and click **Add**.
    1. Select **Reference files in place** and click **Finish**.
    1. In the File inspector,
       verify the **Location** is **Relative to Project**.
       If it is not, you'll need to move the Flutter output directory
       to be a sibling directory of your native app.

       <DashImage image="development/add-to-app/ios/project-setup-swiftpm/flutternativeintegration-relative-location.png" caption="Relative location of FlutterNativeIntegration shown in Xcode's File inspector." />

    1. Navigate to your target's **General** tab
       and add `FlutterNativeIntegration` under
       **Frameworks, Libraries, and Embedded Content**.
       <DashImage image="development/add-to-app/ios/project-setup-swiftpm/flutternativeintegration-library.png" caption="FlutterNativeIntegration under Frameworks, Libraries, and Embedded Content." />

 1. <h3>Add build settings</h3>

    1. In the **Build Settings** tab,
       set the location of the Flutter app's Swift package output directory:
       ```
       FLUTTER_SWIFT_PACKAGE_OUTPUT=$SRCROOT/../my_flutter_app/build/ios/SwiftPackages
       ```

    1. For custom configurations, set the Flutter build mode.

       Flutter supports three [build modes][]: Debug, Profile, and Release.
       The build mode is determined using the `CONFIGURATION`.
       If your configuration does not match one of these,
       you can set the `FLUTTER_BUILD_MODE` build setting
       to one of these values.

       <DashImage image="development/add-to-app/ios/project-setup-swiftpm/flutter-build-mode.png" caption="Setting `FLUTTER_BUILD_MODE` for custom configurations under **Build Settings**." />

    1. (Optional) Allow Xcode to re-build your Flutter app.

       Add the below build settings to your target
       to allow Xcode to re-build your Flutter app as part of its build.
       This allows you to make changes to your Flutter application
       without needing to re-run `flutter build swift-package`.
       This requires Flutter to be installed on the machine.

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

       :::tip
       This only re-builds the Flutter app's code.
       If you add new dependencies,
       you’ll need to re-run `flutter build swift-package`.
       :::

 1. <h3>Add Pre-action Run Script to Scheme</h3>

    1. Open **Product** &gt; **Scheme** &gt; **Edit Scheme...**
       &gt; **Build** (in left side bar) &gt; **Pre-action** &gt; **+**
       &gt; **New Run Script Action**

    1. Select your project in the **Provide build settings from** dropdown.

    1. Set the script to the following:
       ```
       /bin/sh $FLUTTER_SWIFT_PACKAGE_OUTPUT/Scripts/flutter_integration.sh prebuild
       ```

    <DashImage image="development/add-to-app/ios/project-setup-swiftpm/pre-action.png" caption="Pre-action Run Script in scheme editor." />

 1. <h3>Add New Run Script Build Phase to Target</h3>

    1. Navigate to your target's **Build Phases**
       &gt; **+** &gt; **New Run Script Phase**

    1. Set the script to the following:
       ```
       /bin/sh $FLUTTER_SWIFT_PACKAGE_OUTPUT/Scripts/flutter_integration.sh assemble
       ```
    1. Uncheck **Based on dependency analysis**
    1. Add the following to **Input File Lists**:
       ```
       $(FLUTTER_SWIFT_PACKAGE_OUTPUT)/Scripts/FlutterAssembleInputs.xcfilelist
       ```

    <DashImage image="development/add-to-app/ios/project-setup-swiftpm/build-phase-run-script.png" caption="New Run Script Build Phase under Build Phases." />

 1. <h3>(Optional) Set LLDB Init File</h3>

    Using Flutter's LLDB Init File improves performance
    when debugging on physical iOS 26+ devices.

    1. Open **Product** &gt; **Scheme** &gt; **Edit Scheme...** &gt; **Run** (in left side bar).
    1. Set the **LLDB Init File** to the following path:
       ```
       $(FLUTTER_SWIFT_PACKAGE_OUTPUT)/Scripts/flutter_lldbinit
       ```

       Alternatively, if your scheme already has an LLDB Init File,
       you can add Flutter's LLDB file to it.
       The path to Flutter's LLDB Init File must be relative
       to the location of your project's LLDB Init File.

       ```
       command source --relative-to-command-file "../my_flutter_app/build/ios/SwiftPackages/Scripts/flutter_lldbinit"
       ```

{:.steps}

## Set local network privacy permissions {: #local-network-permissions}

On iOS 14 and later, enable the Dart multicast DNS service in the
**Debug** version of your iOS app.
This adds [debugging functionalities such as hot-reload and DevTools][]
using `flutter attach`.

:::warning
Never enable this service in the **Release** version of your app.
The Apple App Store might reject your app.
:::

To set local network privacy permissions only in the Debug version of your app,
create a separate `Info.plist` per build configuration.
SwiftUI projects start without an `Info.plist` file.
If you need to create a property list,
you can do so through Xcode or text editor.
The following instructions assume the default **Debug** and **Release**.
Adjust the names as needed depending on your app's build configurations.

1. Create a new property list.

   1. Open your project in Xcode.

   1. In the **Project Navigator**, click on the project name.

   1. From the **Targets** list in the Editor pane, click on your app.

   1. Click the **Info** tab.

   1. Expand **Custom iOS Target Properties**.

   1. Right-click on the list and select **Add Row**.

   1. From the dropdown menu, select **Bonjour Services**.
      This creates a new property list in the project directory
      called `Info`. This displays as `Info.plist` in the Finder.

1. Rename the `Info.plist` to `Info-Debug.plist`

   1. Click on **Info** file in the project list at the left.

   1. In the **Identity and Type** panel at the right,
      change the **Name** from `Info.plist` to `Info-Debug.plist`.

1. Create a Release property list.

   1. In the **Project Navigator**, click on `Info-Debug.plist`.

   1. Select **File** > **Duplicate...**.
      You can also press <kbd>Cmd</kbd> + <kbd>Shift</kbd> + <kbd>S</kbd>.

   1. In the dialog box, set the **Save As:** field to
      `Info-Release.plist` and click **Save**.

1. Add the necessary properties to the **Debug** property list.

   1. In the **Project Navigator**, click on `Info-Debug.plist`.

   1. Add the String value `_dartVmService._tcp`
      to the **Bonjour Services** array.

   1. _(Optional)_ To set your desired customized permission dialog text,
      add the key **Privacy - Local Network Usage Description**.

      <DashImage image="development/add-to-app/ios/project-setup/debug-plist.png" caption="The `Info-Debug` property list with the **Bonjour Services** and **Privacy - Local Network Usage Description** keys added" />

1. Set the target to use different property lists for different build modes.

   1. In the **Project Navigator**, click on your project.

   1. Click the **Build Settings** tab.

   1. Click **All** and **Combined** sub-tabs.

   1. In the Search box, type `plist`.
      This limits the settings to those that include property lists.

   1. Scroll through the list until you see **Packaging**.

   1. Click on the **Info.plist File** setting.

   1. Change the **Info.plist File** value
      from `path/to/Info.plist` to `path/to/Info-$(CONFIGURATION).plist`.

      <DashImage image="development/add-to-app/ios/project-setup/set-plist-build-setting.png" caption="Updating the `Info.plist` build setting to use build mode-specific property lists" />

      This resolves to the path **Info-Debug.plist** in **Debug** and
      **Info-Release.plist** in **Release**.

      <DashImage image="development/add-to-app/ios/project-setup/plist-build-setting.png" caption="The updated **Info.plist File** build setting displaying the configuration variations" />

1. Remove the **Release** property list from the **Build Phases**.

   1. In the **Project Navigator**, click on your project.

   1. Click the **Build Phases** tab.

   1. Expand **Copy Bundle Resources**.

   1. If this list includes `Info-Release.plist`,
      click on it and then click the **-** (minus sign) under it
      to remove the property list from the resources list.

      <DashImage image="development/add-to-app/ios/project-setup/copy-bundle.png" caption="The **Copy Bundle** build phase displaying the **Info-Release.plist** setting. Remove this setting." />

1. The first Flutter screen your Debug app loads prompts
   for local network permission.

   Click **OK**.

   _(Optional)_ To grant permission before the app loads, enable
   **Settings > Privacy > Local Network > Your App**.

[debugging functionalities such as hot-reload and DevTools]: /add-to-app/debugging



## Next steps

You can now [add a Flutter screen][] to your existing iOS app.

[add a Flutter screen]: /add-to-app/ios/add-flutter-screen
[legacy integration guide]: /add-to-app/ios/project-setup-legacy
[build modes]: /testing/build-modes

