将 Flutter module 集成到 iOS 项目
Flutter UI components can be incrementally added into your existing iOS application as embedded frameworks. To embed Flutter in your existing application, consider one of the following three methods.
Embedding Method | Methodology | Benefit |
---|---|---|
Use CocoaPods (Recommended) | Install and use the Flutter SDK and CocoaPods. Flutter compiles the flutter_module from source each time Xcode builds the iOS app. |
Least complicated method to embed Flutter into your app. |
Use iOS frameworks | Create iOS frameworks for Flutter components, embed them into your iOS, and update your existing app's build settings. | Doesn't require every developer to install the Flutter SDK and CocoaPods on their local machines. |
Use iOS frameworks and CocoaPods | Embed the frameworks for your iOS app and the plugins in Xcode, but distribute the Flutter engine as a CocoaPods podspec. | Provides an alternative to distributing the large Flutter engine (Flutter.xcframework ) library. |
When you add Flutter to your existing iOS app, it increases the size of your iOS app.
For examples using an app built with UIKit, see the iOS directories in the add_to_app code samples. For an example using SwiftUI, consult the iOS directory in News Feed App.
Development system requirements
#Your development environment must meet the macOS system requirements for Flutter with Xcode installed. Flutter supports Xcode 15 or later and CocoaPods 1.16 or later.
Create a Flutter module
#To embed Flutter into your existing application with any method, create a Flutter module first. Use the following command to create a Flutter module.
cd /path/to/my_flutter
flutter create --template module my_flutter
Flutter creates module project under /path/to/my_flutter/
.
If you use the CocoaPods method, save the module
in the same parent directory as your existing iOS app.
From the Flutter module directory,
you can run the same flutter
commands you would in any other Flutter project,
like flutter run
or flutter build ios
.
You can also run the module in VS Code or
Android Studio/IntelliJ with the Flutter and Dart plugins.
This project contains a single-view example version of your module
before embedding it in your existing iOS app.
This helps when testing the Flutter-only parts of your code.
Organize your module
#The my_flutter
module directory structure resembles a typical Flutter app.
my_flutter/
├── .ios/
│ ├── Runner.xcworkspace
│ └── Flutter/podhelper.rb
├── lib/
│ └── main.dart
├── test/
└── pubspec.yaml
Your Dart code should be added to the lib/
directory.
Your Flutter dependencies, packages, and plugins must be added to the
pubspec.yaml
file.
The .ios/
hidden subfolder contains an Xcode workspace where
you can run a standalone version of your module.
This wrapper project bootstraps your Flutter code.
It contains helper scripts to facilitate building frameworks or
embedding the module into your existing application with CocoaPods.
Embed a Flutter module in your iOS app
#After you have developed your Flutter module, you can embed it using the methods described in the table at the top of the page.
You can run in Debug mode on a simulator or a real device, and Release mode on a real device.
Use CocoaPods and the Flutter SDK
#Approach
#This first method uses CocoaPods to embed the Flutter modules. CocoaPods manages dependencies for Swift projects, including Flutter code and plugins. Each time Xcode builds the app, CocoaPods embeds the Flutter modules.
This allows rapid iteration with the most up-to-date version of your Flutter module without running additional commands outside of Xcode.
To learn more about CocoaPods, consult the CocoaPods getting started guide.
Watch the video
#If watching a video helps you learn, this video covers adding Flutter to an iOS app:
Step by step on how to add Flutter to an existing iOS app
Requirements
#Every developer working on your project must have a local version of the Flutter SDK and CocoaPods installed.
Example project structure
#This section assumes that your existing app and the Flutter module reside in sibling directories. If you have a different directory structure, adjust the relative paths. The example directory structure resembles the following:
/path/to/MyApp
├── my_flutter/
│ └── .ios/
│ └── Flutter/
│ └── podhelper.rb
└── MyApp/
└── Podfile
Update your Podfile
#Add your Flutter modules to your Podfile configuration file.
This section presumes you called your Swift app MyApp
.
-
(Optional) If your existing app lacks a
Podfile
config file, navigate to the root of your app directory. Use thepod init
command to create thePodfile
file. -
Update your
Podfile
config file.-
Add the following lines after the
platform
declaration.MyApp/Podfilerubyflutter_application_path = '../my_flutter' load File.join(flutter_application_path, '.ios', 'Flutter', 'podhelper.rb')
-
For each Podfile target that needs to embed Flutter, add a call to the
install_all_flutter_pods(flutter_application_path)
method. Add these calls after the settings in the previous step.MyApp/Podfilerubytarget 'MyApp' do install_all_flutter_pods(flutter_application_path) end
-
In the
Podfile
'spost_install
block, add a call toflutter_post_install(installer)
. This block should be the last block in thePodfile
config file.MyApp/Podfilerubypost_install do |installer| flutter_post_install(installer) if defined?(flutter_post_install) end
-
To review an example Podfile
, consult this Flutter Podfile sample.
Embed your frameworks
#At build time, Xcode packages your Dart code, each Flutter plugin,
and the Flutter engine into their own *.xcframework
bundles.
CocoaPod's podhelper.rb
script then embeds these
*.xcframework
bundles into your project.
Flutter.xcframework
contains the Flutter engine.App.xcframework
contains the compiled Dart code for this project.<plugin>.xcframework
contains one Flutter plugin.
To embed the Flutter engine, your Dart code, and your Flutter plugins into your iOS app, complete the following procedure.
-
Refresh your Flutter plugins.
If you change the Flutter dependencies in the
pubspec.yaml
file, runflutter pub get
in your Flutter module directory. This refreshes the list of plugins that thepodhelper.rb
script reads.flutter pub get
-
Embed the plugins and frameworks with CocoaPods.
-
Navigate to your iOS app project at
/path/to/MyApp/MyApp
. -
Use the
pod install
command.pod install
Your iOS app's Debug and Release build configurations embed the corresponding Flutter components for that build mode.
-
-
Build the project.
-
Open
MyApp.xcworkspace
in Xcode.Verify that you're opening
MyApp.xcworkspace
and not openingMyApp.xcodeproj
. The.xcworkspace
file has the CocoaPod dependencies, the.xcodeproj
doesn't. -
Select Product > Build or press Cmd + B.
-
Link and Embed frameworks in Xcode
#Approach
#In this second method, edit your existing Xcode project, generate the necessary frameworks, and embed them in your app. Flutter generates iOS frameworks for Flutter itself, for your compiled Dart code, and for each of your Flutter plugins. Embed these frameworks and update your existing application's build settings.
Requirements
#No additional software or hardware requirements are needed for this method. Use this method in the following use cases:
- Members of your team can't install the Flutter SDK and CocoaPods
- You don't want to use CocoaPods as a dependency manager in existing iOS apps
Limitations
#Flutter can't handle common dependencies with xcframeworks.
If both the host app and the Flutter module's plugin define the
same pod dependency and you integrate Flutter module using this option,
errors result.
These errors include issues like Multiple commands produce 'CommonDependency.framework'
.
To work around this issue, link every plugin source in its podspec
file
from the Flutter module to the host app's Podfile
.
Link the source instead of the plugins' xcframework
framework.
The next section explains how to produce that framework.
To prevent the error that occurs when common dependencies exist,
use flutter build ios-framework
with the --no-plugins
flag.
Example project structure
#The following example assumes that you want to generate the
frameworks to /path/to/MyApp/Flutter/
.
flutter build ios-framework --output=/path/to/MyApp/Flutter/
Run this every time you change code in your Flutter module.
The resulting project structure should resemble this directory tree.
/path/to/MyApp/
└── Flutter/
├── Debug/
│ ├── Flutter.xcframework
│ ├── App.xcframework
│ ├── FlutterPluginRegistrant.xcframework (only if you have plugins with iOS platform code)
│ └── example_plugin.xcframework (each plugin is a separate framework)
├── Profile/
│ ├── Flutter.xcframework
│ ├── App.xcframework
│ ├── FlutterPluginRegistrant.xcframework
│ └── example_plugin.xcframework
└── Release/
├── Flutter.xcframework
├── App.xcframework
├── FlutterPluginRegistrant.xcframework
└── example_plugin.xcframework
Procedures
#How you link, embed, or both the generated frameworks into your existing app in Xcode depends on the type of framework.
- Link and embed dynamic frameworks.
- Link static frameworks. Never embed them.
Flutter plugins might produce static or dynamic frameworks. Link static frameworks, never embed them.
If you embed a static framework into your iOS app,
you can't publish that app to the App Store.
Publishing fails with a
Found an unexpected Mach-O header code
archive error.
Link all frameworks
#To link the necessary frameworks, follow this procedure.
-
Choose the frameworks to link.
-
In the Project Navigator, click on your project.
-
Click the Build Phases tab.
-
Expand Link Binary With Libraries.
Expand the Link Binary With Libraries build phase in Xcode -
Click + (plus sign).
-
Click Add Other... then Add Files....
-
From the Choose frameworks and libraries to add: dialog box, navigate to the
/path/to/MyApp/Flutter/Release/
directory. -
Command-click the frameworks in that directory then click Open.
Choose frameworks to link from the Choose frameworks and libraries to add: dialog box in Xcode
-
-
Update the paths to the libraries to account for build modes.
-
Launch the Finder.
-
Navigate to the
/path/to/MyApp/
directory. -
Right-click on
MyApp.xcodeproj
and select Show Package Contents. -
Open
project.pbxproj
with Xcode. The file opens in Xcode's text editor. This also locks Project Navigator until you close the text editor.
The project-pbxproj
file open in the Xcode text editor -
Find the lines that resemble the following text in the
/* Begin PBXFileReference section */
.text312885572C1A441C009F74FF /* Flutter.xcframework */ = { isa = PBXFileReference; expectedSignature = "AppleDeveloperProgram:S8QB4VV633:FLUTTER.IO LLC"; lastKnownFileType = wrapper.xcframework; name = Flutter.xcframework; path = Flutter/Release/Flutter.xcframework; sourceTree = "<group>"; }; 312885582C1A441C009F74FF /* App.xcframework */ = { isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = App.xcframework; path = Flutter/Release/App.xcframework; sourceTree = "<group>"; };
-
Change the
Release
text highlighted in the prior step and change it to$(CONFIGURATION)
. Also wrap the path in quotation marks.text312885572C1A441C009F74FF /* Flutter.xcframework */ = { isa = PBXFileReference; expectedSignature = "AppleDeveloperProgram:S8QB4VV633:FLUTTER.IO LLC"; lastKnownFileType = wrapper.xcframework; name = Flutter.xcframework; path = "Flutter/$(CONFIGURATION)/Flutter.xcframework"; sourceTree = "<group>"; }; 312885582C1A441C009F74FF /* App.xcframework */ = { isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = App.xcframework; path = "Flutter/$(CONFIGURATION)/App.xcframework"; sourceTree = "<group>"; };
-
-
Update the search paths.
-
Click the Build Settings tab.
-
Navigate to Search Paths
-
Double-click to the right of Framework Search Paths.
-
In the combo box, click + (plus sign).
-
Type
$(inherited)
. and press Enter. -
Click + (plus sign).
-
Type
$(PROJECT_DIR)/Flutter/$(CONFIGURATION)/
and press Enter.
Update Framework Search Paths in Xcode
-
After linking the frameworks, they should display in the Frameworks, Libraries, and Embedded Content section of your target's General settings.
Embed the dynamic frameworks
#To embed your dynamic frameworks, complete the following procedure.
-
Navigate to General > Frameworks, Libraries, and Embedded Content.
-
Click on each of your dynamic frameworks and select Embed & Sign.
Select Embed & Sign for each of your frameworks in Xcode Don't include any static frameworks, including
FlutterPluginRegistrant.xcframework
. -
Click the Build Phases tab.
-
Expand Embed Frameworks. Your dynamic frameworks should display in that section.
The expanded Embed Frameworks build phase in Xcode -
Build the project.
-
Open
MyApp.xcworkspace
in Xcode.Verify that you're opening
MyApp.xcworkspace
and not openingMyApp.xcodeproj
. The.xcworkspace
file has the CocoaPod dependencies, the.xcodeproj
doesn't. -
Select Product > Build or press Cmd + B.
-
Use frameworks in Xcode and Flutter framework as podspec
#Approach
#This method generates Flutter as a CocoaPods podspec instead of
distributing the large Flutter.xcframework
to other developers,
machines, or continuous integration systems.
Flutter still generates iOS frameworks for your compiled Dart code,
and for each of your Flutter plugins.
Embed these frameworks and update your existing application's build settings.
Requirements
#No additional software or hardware requirements are needed for this method. Use this method in the following use cases:
- Members of your team can't install the Flutter SDK and CocoaPods
- You don't want to use CocoaPods as a dependency manager in existing iOS apps
Limitations
#Flutter can't handle common dependencies with xcframeworks.
If both the host app and the Flutter module's plugin define the
same pod dependency and you integrate Flutter module using this option,
errors result.
These errors include issues like Multiple commands produce 'CommonDependency.framework'
.
To work around this issue, link every plugin source in its podspec
file
from the Flutter module to the host app's Podfile
.
Link the source instead of the plugins' xcframework
framework.
The next section explains how to produce that framework.
To prevent the error that occurs when common dependencies exist,
use flutter build ios-framework
with the --no-plugins
flag.
This method only works with the beta
or stable
release channels.
Example project structure
#The following example assumes that you want to generate the
frameworks to /path/to/MyApp/Flutter/
.
flutter build ios-framework --output=/path/to/MyApp/Flutter/
Run this every time you change code in your Flutter module.
The resulting project structure should resemble this directory tree.
/path/to/MyApp/
└── Flutter/
├── Debug/
│ ├── Flutter.xcframework
│ ├── App.xcframework
│ ├── FlutterPluginRegistrant.xcframework (only if you have plugins with iOS platform code)
│ └── example_plugin.xcframework (each plugin is a separate framework)
├── Profile/
│ ├── Flutter.xcframework
│ ├── App.xcframework
│ ├── FlutterPluginRegistrant.xcframework
│ └── example_plugin.xcframework
└── Release/
├── Flutter.xcframework
├── App.xcframework
├── FlutterPluginRegistrant.xcframework
└── example_plugin.xcframework
Add Flutter engine to your Podfile
#Host apps using CocoaPods can add the Flutter engine to their Podfile.
pod 'Flutter', :podspec => '/path/to/MyApp/Flutter/[build mode]/Flutter.podspec'
Link and embed app and plugin frameworks
#Flutter plugins might produce static or dynamic frameworks. Link static frameworks, never embed them.
If you embed a static framework into your iOS app,
you can't publish that app to the App Store.
Publishing fails with a
Found an unexpected Mach-O header code
archive error.
Link all frameworks
#To link the necessary frameworks, follow this procedure.
-
Choose the frameworks to link.
-
In the Project Navigator, click on your project.
-
Click the Build Phases tab.
-
Expand Link Binary With Libraries.
Expand the Link Binary With Libraries build phase in Xcode -
Click + (plus sign).
-
Click Add Other... then Add Files....
-
From the Choose frameworks and libraries to add: dialog box, navigate to the
/path/to/MyApp/Flutter/Release/
directory. -
Command-click the frameworks in that directory then click Open.
Choose frameworks to link from the Choose frameworks and libraries to add: dialog box in Xcode
-
-
Update the paths to the libraries to account for build modes.
-
Launch the Finder.
-
Navigate to the
/path/to/MyApp/
directory. -
Right-click on
MyApp.xcodeproj
and select Show Package Contents. -
Open
project.pbxproj
with Xcode. The file opens in Xcode's text editor. This also locks Project Navigator until you close the text editor.
The project-pbxproj
file open in the Xcode text editor -
Find the lines that resemble the following text in the
/* Begin PBXFileReference section */
.text312885572C1A441C009F74FF /* Flutter.xcframework */ = { isa = PBXFileReference; expectedSignature = "AppleDeveloperProgram:S8QB4VV633:FLUTTER.IO LLC"; lastKnownFileType = wrapper.xcframework; name = Flutter.xcframework; path = Flutter/Release/Flutter.xcframework; sourceTree = "<group>"; }; 312885582C1A441C009F74FF /* App.xcframework */ = { isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = App.xcframework; path = Flutter/Release/App.xcframework; sourceTree = "<group>"; };
-
Change the
Release
text highlighted in the prior step and change it to$(CONFIGURATION)
. Also wrap the path in quotation marks.text312885572C1A441C009F74FF /* Flutter.xcframework */ = { isa = PBXFileReference; expectedSignature = "AppleDeveloperProgram:S8QB4VV633:FLUTTER.IO LLC"; lastKnownFileType = wrapper.xcframework; name = Flutter.xcframework; path = "Flutter/$(CONFIGURATION)/Flutter.xcframework"; sourceTree = "<group>"; }; 312885582C1A441C009F74FF /* App.xcframework */ = { isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = App.xcframework; path = "Flutter/$(CONFIGURATION)/App.xcframework"; sourceTree = "<group>"; };
-
-
Update the search paths.
-
Click the Build Settings tab.
-
Navigate to Search Paths
-
Double-click to the right of Framework Search Paths.
-
In the combo box, click + (plus sign).
-
Type
$(inherited)
. and press Enter. -
Click + (plus sign).
-
Type
$(PROJECT_DIR)/Flutter/$(CONFIGURATION)/
and press Enter.
Update Framework Search Paths in Xcode
-
After linking the frameworks, they should display in the Frameworks, Libraries, and Embedded Content section of your target's General settings.
Embed the dynamic frameworks
#To embed your dynamic frameworks, complete the following procedure.
-
Navigate to General > Frameworks, Libraries, and Embedded Content.
-
Click on each of your dynamic frameworks and select Embed & Sign.
Select Embed & Sign for each of your frameworks in Xcode Don't include any static frameworks, including
FlutterPluginRegistrant.xcframework
. -
Click the Build Phases tab.
-
Expand Embed Frameworks. Your dynamic frameworks should display in that section.
The expanded Embed Frameworks build phase in Xcode -
Build the project.
-
Open
MyApp.xcworkspace
in Xcode.Verify that you're opening
MyApp.xcworkspace
and not openingMyApp.xcodeproj
. The.xcworkspace
file has the CocoaPod dependencies, the.xcodeproj
doesn't. -
Select Product > Build or press Cmd + B.
-
Set local network privacy 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
.
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.
-
Create a new property list.
-
Open your project in Xcode.
-
In the Project Navigator, click on the project name.
-
From the Targets list in the Editor pane, click on your app.
-
Click the Info tab.
-
Expand Custom iOS Target Properties.
-
Right-click on the list and select Add Row.
-
From the dropdown menu, select Bonjour Services. This creates a new property list in the project directory called
Info
. This displays asInfo.plist
in the Finder.
-
-
Rename the
Info.plist
toInfo-Debug.plist
-
Click on Info file in the project list at the left.
-
In the Identity and Type panel at the right, change the Name from
Info.plist
toInfo-Debug.plist
.
-
-
Create a Release property list.
-
In the Project Navigator, click on
Info-Debug.plist
. -
Select File > Duplicate....
You can also press Cmd + Shift + S. -
In the dialog box, set the Save As: field to
Info-Release.plist
and click Save.
-
-
Add the necessary properties to the Debug property list.
-
In the Project Navigator, click on
Info-Debug.plist
. -
Add the String value
_dartVmService._tcp
to the Bonjour Services array. -
(Optional) To set your desired customized permission dialog text, add the key Privacy - Local Network Usage Description.
The Info-Debug
property list with the Bonjour Services and Privacy - Local Network Usage Description keys added
-
-
Set the target to use different property lists for different build modes.
-
In the Project Navigator, click on your project.
-
Click the Build Settings tab.
-
Click All and Combined sub-tabs.
-
In the Search box, type
plist
.
This limits the settings to those that include property lists. -
Scroll through the list until you see Packaging.
-
Click on the Info.plist File setting.
-
Change the Info.plist File value from
path/to/Info.plist
topath/to/Info-$(CONFIGURATION).plist
.
Updating the Info.plist
build setting to use build mode-specific property listsThis resolves to the path Info-Debug.plist in Debug and Info-Release.plist in Release.
The updated Info.plist File build setting displaying the configuration variations
-
-
Remove the Release property list from the Build Phases.
-
In the Project Navigator, click on your project.
-
Click the Build Phases tab.
-
Expand Copy Bundle Resources.
-
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.
The Copy Bundle build phase displaying the Info-Release.plist setting. Remove this setting.
-
-
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.
Mitigate known issue with Apple Silicon Macs
#On Macs running Apple Silicon,
the host app builds for an arm64
simulator.
While Flutter supports arm64
simulators, some plugins might not.
If you use one of these plugins, you might see a compilation error like
Undefined symbols for architecture arm64.
If this occurs,
exclude arm64
from the simulator architectures in your host app.
-
In the Project Navigator, click on your project.
-
Click the Build Settings tab.
-
Click All and Combined sub-tabs.
-
Under Architectures, click on Excluded Architectures.
-
Expand to see the available build configurations.
-
Click Debug.
-
Click the + (plus sign).
-
Select iOS Simulator.
-
Double-click in the value column for Any iOS Simulator SDK.
-
Click the + (plus sign).
-
Type
arm64
in the Debug > Any iOS Simulator SDK dialog box.
Add arm64
as an excluded architecture for your app -
Press Esc to close this dialog box.
-
Repeat these steps for the Release build mode.
-
Repeat for any iOS unit test targets.
Next steps
#除非另有说明,本文档之所提及适用于 Flutter 的最新稳定版本,本页面最后更新时间: 2024-08-06。 查看文档源码 或者 为本页面内容提出建议。