将 Flutter module 集成到 iOS 项目

Flutter 可以以 framework 框架的形式添加到你的既有 iOS 应用中。

Flutter can be incrementaly added into your existing iOS application as embedded frameworks.

系统要求

System requirements

你的开发环境必须满足 Flutter 对 macOS 系统的版本要求已经安装 Xcode,Flutter 支持 iOS 8.0 及以上。

Your development environment must meet the macOS system requirements for Flutter with Xcode installed. Flutter supports iOS 8.0 and later.

创建 Flutter module

Create a Flutter module

为了将 Flutter 集成到你的既有应用里,第一步要创建一个 Flutter module。

To embed Flutter into your existing application, first create a Flutter module.

在命令行中执行:

From the command line, run:

cd some/path/
flutter create --template module my_flutter

Flutter module 会创建在 some/path/my_flutter/ 目录。在这个目录中,你可以像在其它 Flutter 项目中一样,执行 flutter 命令。比如 flutter run --debug 或者 flutter build ios。你也同样可以在 Android Studio/IntelliJ 或者 VS Code 中运行这个模块,并附带 Flutter 和 Dart 插件。在集成到既有应用前,这个项目在 Flutter module 中包含了一个单视图的示例代码,对 Flutter 侧代码的测试会有帮助。

A Flutter module project is created at some/path/my_flutter/. From that directory, you can run the same flutter commands you would in any other Flutter project, like flutter run --debug or flutter build ios. You can also run the module in Android Studio/IntelliJ or VS Code with the Flutter and Dart plugins. This project contains a single-view example version of your module before it’s embedded in your existing application, which is useful for incrementally testing the Flutter-only parts of your code.

模块组织

Module organization

my_flutter 模块,目录结构和普通 Flutter 应用类似:

The my_flutter module directory structure is similar to a normal Flutter application:

my_flutter/
├── .ios/
│   ├── Runner.xcworkspace
│   └── Flutter/podhelper.rb
├── lib/
│   └── main.dart
├── test/
└── pubspec.yaml

添加你的 Dart 代码到 lib/ 目录。

Add your Dart code to the lib/ directory.

添加 Flutter 依赖到 my_flutter/pubspec.yaml,包括 Flutter packages 和 plugins。

Add Flutter dependencies to my_flutter/pubspec.yaml, including Flutter packages and plugins.

.ios/ 隐藏文件夹包含了一个 Xcode workspace,用于单独运行你的 Flutter module。它是一个独立启动 Flutter 代码的壳工程,并且包含了一个帮助脚本,用于编译 framewroks 或者使用 CocoaPods 将 Flutter module 集成到你的既有应用。

The .ios/ hidden subfolder contains an Xcode workspace where you can run a standalone version of your module. It is a wrapper project to bootstrap your Flutter code, and contains helper scripts to facilitate building frameworks or embedding the module into your existing application with CocoaPods.

在你的既有应用中集成 Flutter module

Embed the Flutter module in your existing application

这里有两种方式可以将 Flutter 集成到你的既有应用中。

There are two ways to embed Flutter in your existing application.

  1. 使用 CocoaPods 依赖管理和已安装的 Flutter SDK 。(推荐)

    Use the CocoaPods dependency manager and installed Flutter SDK. (Recommended.)

  2. 把 Flutter engine 、你的 dart 代码和所有 Flutter plugin 编译成 framework 。用 Xcode 手动集成到你的应用中,并更新编译设置。

    Create frameworks for the Flutter engine, your compiled Dart code, and all Flutter plugins. Manually embed the frameworks, and update your existing application’s build settings in Xcode.

使用 Flutter 会 [增加应用体积][increase your app size] 。

Using Flutter increases your app size.

选项 A - 使用 CocoaPods 和 Flutter SDK 集成

Option A - Embed with CocoaPods and the Flutter SDK

这个方法需要你的项目的所有开发者,都在本地安装 Flutter SDK。只需要在 Xcode 中编译应用,就可以自动运行脚本来集成 dart 代码和 plugin。这个方法允许你使用 Flutter module 中的最新代码快速迭代开发,而无需在 Xcode 以外执行额外的命令。

This method requires every developer working on your project to have a locally installed version of the Flutter SDK. Simply build your application in Xcode to automatically run the script to embed your Dart and plugin code. This allows rapid iteration with the most up-to-date version of your Flutter module without running additional commands outside of Xcode.

下面的示例假设你的既有应用和 Flutter module 在相邻目录。如果你有不同的目录结构,需要适配到对应的路径。

The following example assumes that your existing application and the Flutter module are in sibling directories. If you have a different directory structure, you may need to adjust the relative paths.

some/path/
├── my_flutter/
│   └── .ios/
│       └── Flutter/
│         └── podhelper.rb
└── MyApp/
    └── Podfile

如果你的应用(MyApp)还没有 Podfile,根据 CocoaPods getting started guide 来在项目中添加 Podfile

If your existing application (MyApp) doesn’t already have a Podfile, follow the CocoaPods getting started guide to add a Podfile to your project.

  1. 在 `Podfile` 中添加下面代码:Add the following lines to your `Podfile`:
    MyApp/Podfile
    flutter_application_path = '../my_flutter'
    load File.join(flutter_application_path, '.ios', 'Flutter', 'podhelper.rb')
  2. 每个需要集成 Flutter 的 [Podfile target][],执行 `install_all_flutter_pods(flutter_application_path)`:For each [Podfile target][] that needs to embed Flutter, call `install_all_flutter_pods(flutter_application_path)`.
    MyApp/Podfile
    target 'MyApp' do
      install_all_flutter_pods(flutter_application_path)
    end
  3. 运行 pod install

    Run pod install.

podhelper.rb 脚本会把你的 plugins, Flutter.framework,和 App.framework 集成到你的项目中。

The podhelper.rb script embeds your plugins, Flutter.framework, and App.framework into your project.

你应用的 Debug 和 Release 编译配置,将会集成相对应的 Debug 或 Release 的 编译产物。可以增加一个 Profile 编译配置用于在 profile 模式下测试应用。

Your app’s Debug and Release build configurations embeds the Debug or Release build modes of Flutter, respectively. Add a Profile build configuration to your app to test in profile mode.

在 Xcode 中打开 MyApp.xcworkspace ,你现在可以使用 ⌘B 编译项目了。

Open MyApp.xcworkspace in Xcode. You can now build the project using ⌘B.

选项 B - 在 Xcode 中集成 frameworks

Option B - Embed frameworks in Xcode

除了上面的方法,你也可以创建必备的 frameworks,手动修改既有 Xcode 项目,将他们集成进去。当你组内其它成员们不能在本地安装 Flutter SDK 和 CocoaPods,或者你不想使用 CocoaPods 作为既有应用的依赖管理时,这种方法会比较合适。但是每当你在 Flutter module 中改变了代码,都必须运行 flutter build ios-framework

Alternatively, you can generate the necessary frameworks and embed them in your application by manually editing your existing Xcode project. You may do this if members of your team can’t locally install Flutter SDK and CocoaPods, or if you don’t want to use CocoaPods as a dependency manager in your existing applications. You must run flutter build ios-framework every time you make code changes in your Flutter module.

如果你使用前面的 使用 CocoaPods 和 Flutter SDK 集成,你可以跳过本步骤。

If you’re using the previous Embed with CocoaPods and Flutter tools method, you can skip these instructions.

下面的示例假设你想在 some/path/MyApp/Flutter/ 目录下创建 frameworks:

The following example assumes that you want to generate the frameworks to some/path/MyApp/Flutter/.

flutter build ios-framework --output=some/path/MyApp/Flutter/
some/path/MyApp/
└── Flutter/
    ├── Debug/
    │   ├── Flutter.framework
    │   ├── App.framework
    │   ├── FlutterPluginRegistrant.framework
    │   └── example_plugin.framework (each plugin with iOS platform code is a separate framework)
    ├── Profile/
    │   ├── Flutter.framework
    │   ├── App.framework
    │   ├── FlutterPluginRegistrant.framework
    │   └── example_plugin.framework
    └── Release/
        ├── Flutter.framework
        ├── App.framework
        ├── FlutterPluginRegistrant.framework
        └── example_plugin.framework

在 Xcode 中将生成的 frameworks 集成到你的既有应用中。例如,你可以在 some/path/MyApp/Flutter/Release/ 目录拖拽 frameworks 到你的应用 target 编译设置的 General > Frameworks, Libraries, and Embedded Content 下,然后在 Embed 下拉列表中选择 “Embed & Sign”。

Embed and link the generated frameworks into your existing application in Xcode. There are multiple ways to do this—use the method that is best for your project.

Link on the frameworks

例如,你可以将框架从 Finder 的 some/path/MyApp/Flutter/Release/ 拖到你的目标项目中,然后点击以下步骤 build settings > Build Phases > Link Binary With Libraries。

For example, you can drag the frameworks from some/path/MyApp/Flutter/Release/ in Finder into your targets’ build settings > Build Phases > Link Binary With Libraries.

在 target 的编译设置中的 Framework Search Paths (FRAMEWORK_SEARCH_PATHS) 增加 $(PROJECT_DIR)/Flutter/Release/

In the target’s build settings, add $(PROJECT_DIR)/Flutter/Release/ to the Framework Search Paths (FRAMEWORK_SEARCH_PATHS).

Update Framework Search Paths in Xcode

内嵌框架

Embed the frameworks

生成的动态框架必须嵌入你的应用并且在运行时被加载。

The generated dynamic frameworks must be embedded into your app to be loaded at runtime.

例如,你可以从应用框架组中拖拽框架(除了 FlutterPluginRegistrant 以及其他的静态框架)到你的目标 ‘ build settings > Build Phases > Embed Frameworks。然后从下拉菜单中选择 “Embed & Sign”。

For example, you can drag the framework (except for FlutterPluginRegistrant and any other static frameworks) from your application’s Frameworks group into your targets’ build settings > Build Phases > Embed Frameworks. Then, select Embed & Sign from the drop-down list.

Embed frameworks in Xcode

你现在可以在 Xcode中使用 ⌘B 编译项目。

You should now be able to build the project in Xcode using ⌘B.

选项 C - 使用 CocoaPods 在 Xcode 和 Flutter 框架中内嵌应用和插件框架

Option C - Embed application and plugin frameworks in Xcode and Flutter framework with CocoaPods

除了将一个很大的 Flutter.framework 分发给其他开发者、机器或者持续集成 (CI) 系统之外,你可以加入一个参数 --cocoapods 将 Flutter 框架作为一个 CocoaPods 的 podspec 文件分发。这将会生成一个 Flutter.podspec 文件而不再生成 Flutter.framework 引擎文件。如选项 B 中所说的那样,它将会生成 App.framework 和插件框架。

Alternatively, instead of distributing the large Flutter.framework to other developers, machines, or continuous integration systems, you can instead generate Flutter as CocoaPods podspec by adding the flag --cocoapods. This produces a Flutter.podspec instead of an engine Flutter.framework. The App.framework and plugin frameworks will be generated as described in Option B.

flutter build ios-framework --cocoapods --output=some/path/MyApp/Flutter/
some/path/MyApp/
└── Flutter/
    ├── Debug/
    │   ├── Flutter.podspec
    │   ├── App.framework
    │   ├── FlutterPluginRegistrant.framework
    │   └── example_plugin.framework (each plugin with iOS platform code is a separate framework)
    ├── Profile/
    │   ├── Flutter.podspec
    │   ├── App.framework
    │   ├── FlutterPluginRegistrant.framework
    │   └── example_plugin.framework
    └── Release/
        ├── Flutter.podspec
        ├── App.framework
        ├── FlutterPluginRegistrant.framework
        └── example_plugin.framework

Host apps using CocoaPods can add Flutter to their Podfile:

MyApp/Podfile
pod 'Flutter', :podspec => 'some/path/MyApp/Flutter/{build_mode}/Flutter.podspec'

Embed and link the generated App.framework, FlutterPluginRegistrant.framework, and any plugin frameworks into your existing application as described in Option B.

开发

Development

你现在可以 添加一个 Flutter 页面 到你的既有应用中。

You can now add a Flutter screen to your existing application.