背景
假设你有两个独立的项目,一个纯
Flutter
项目A
,一个 iOS 项目B
。项目A
开发完后,想集成到B
中。该怎么做?以及如何自定义 engine?
以真机调试为例
首先编译项目 A
在项目A的目录下,执行
// 默认是 -release
$ flutter build ios
这条命令会借助你本地 Flutter
环境进行 build
。所以编译出的 Flutter
版本是和你本地 Flutter
环境版本是一致的
编译后的产物在 .ios
文件夹里。打开这个文件夹,找到 Flutter
文件,它的目录结构大概是这样子的:

我们需要的是 App.framework
和 engine
(引擎)。dart 代码,包括业务代码,三方 package
代码,它们所依赖的 flutter 框架代码,最终将会编译成 App.framework
把编译好的项目资源合到一起
-
打开
.ios
文件夹 --> 找到Flutte
r 文件夹 --> 找到App.framework
-
拷贝出
App.framework
再拷贝出和它同级的 flutter_assets 文件(Flutter V1.2.0
开始flutter_assets
被包含在了App.framework
里面,所以不需要另外拷贝flutter_assets
文件)
3. 修改拷贝出的 App.framework 的名字为 FlutterXX.framework (V1.2.0
开始不要修改名字,会报错:Library not loaded: @rpath/App.framework/App
)
4. 打开 FlutterXX.framework,修改 App 文件的名字为 FlutterXX
- 修改 info.plist 中 Bundle identifier,重命名为和项目 B 类似的 id名称,比如:com.公司名.尾部名字
6. 把 flutter_assets 文件拷贝到 FlutterXX.framework 中
嵌入App.framework
- 把该
App.framework
放入项目 B 的文件目录 - 然后嵌入这个
framework
,目的是把它放入./Frameworks
文件夹,后面会通过bundle
去加载它,然后初始化Flutter Dart
:
Targets --> Build Phases --> Embed Frameworks , add FlutterXX.framework
嵌入engine
接下来,需要把 flutter 项目需要的 engine
也放入项目 B
-
方式一:打开上面
.ios
文件目录 -->Flutter
-->engine
-->Flutter.framework
-
方式二:打开你本地 Flutter 环境所在文件 -->
bin
-->cache
-->artifacts
-->engine
-->ios-release
(release编译) -->Flutter.framework
我们是用 pod 的方式把 Flutter.framework
集成进入,所以根据上面的文件目录,找到 Flutter.framework
, 拷贝到我们的 pod
库。更新 pod
库 就行了。
加载项目B
为了让项目B
生效,首先,要把生成的 App.framework
加载进入项目A
NSString *customBundlePath = [[NSBundle mainBundle] pathForResource:@"App" ofType:@"framework" inDirectory:@"./Frameworks"];
然后初始化项目B
的 Flutter Dart
环境:
NSBundle *customBundle = [NSBundle bundleWithPath:customBundlePath];
FlutterDartProject *project = [FlutterDartProject.alloc initWithPrecompiledDartBundle:customBundle];
最后一步,可以加载 flutter
页面了:
FLTViewController *flutterVC = [[FLTViewController alloc] initWithProject:project nibName:nil bundle:customBundle];
自定义engine
如果自定义 engine
, 我们参考 官方文档 进行以下流程:
-
fork
https://github.com/flutter/engine
到你的github
账户修改 engine 源码的时机有两个: 1. fork 后,在你的 github 账户就多了一个对应的项目,然后 clone 它,进行修改等操作 2. 对 engine 的修改,也可以放到下面的第5步进行
-
根据官方文档,首先找个合适位置,新建文件夹
engine
-
在
engine
文件夹,新建 .gclient 文件并在该文件内写入以下内容:solutions = [ { "managed": False, "name": "src/flutter", "url": "git@github.com:<your_name_here>/engine.git", "custom_deps": {}, "deps_file": "DEPS", "safesync_url": "", }, ]
-
还是在
engine
目录,执行$ gclient sync
-
拉取代码结束后,切换到
src/flutter
目录,并添加upstream
$ cd src/flutter $ git remote add upstream git@github.com:flutter/engine.git $ git fetch upstream
-
对
engine
修改前要明确知道我们flutter
项目使用的是哪一版本的engine
然后针对这一版本进行修改。为了找到对应的版本,在你开发的flutter
项目下执行:$ flutter doctor -v
然后有类似下面的输出:
[✓] Flutter (Channel unknown, v1.2.0, on Mac OS X 10.14 18A391, locale zh-Hans-CN) • Flutter version 1.2.0 at /Users/xx/Documents/iOS/flutter • Framework revision 06b979c4d5 (3 months ago), 2019-01-25 14:27:35 -0500 • Engine revision 36acd02c94 • Dart version 2.1.1 (build 2.1.1-dev.3.2 f4afaee422)
其中
Engine revision 36acd02c94
就是我们要找到的版本 -
找到了版本信息,接下来需要执行代码回退,把
engine
回退到36acd02c94
。我们回到存放.gclient
文件的目录,执行:$ cd src/flutter $ git reset --hard 36acd02c94 ///再次回到 `engine` 根目录,为了再次执行 `gclient sync` $ cd ../.. ///这一步不可缺少。版本回退后,这一步是为了同步该版本所依赖的第三方库版本,比如 `thrid_party` 文件里面的内容。 $ gclient sync --with_branch_heads --with_tags
-
现在可以修改 engine 源码了
编译engine
对 engine
源码做了修改之后,需要重新编译,生成我们自定义的 Flutter.framework
产物
#!env zsh
$ cd src
$ rm -rf ./out/Flutter.framework
// '准备 iOS (device & simulator ) 生成 gen_snapshot (dart 编译器)'
$ ./flutter/tools/gn --ios --runtime-mode release
$ ./flutter/tools/gn --ios --simulator --unoptimized
// 生成i386架构下的gen_snapshot
$ ./flutter/tools/gn --ios --ios-cpu arm --runtime-mode release
$ ./flutter/tools/gn --unoptimized
$ ninja -C out/ios_release
$ ninja -C out/ios_release_arm
$ ninja -C out/ios_debug_sim_unopt
$ ninja -C out/host_debug_unopt
$ cp -r ./out/ios_debug_sim_unopt/Flutter.framework ./out/Flutter.framework
$ lipo ./out/ios_debug_sim_unopt/Flutter.framework/Flutter ./out/ios_release/Flutter.framework/Flutter ./out/ios_release_arm/Flutter.framework/Flutter -output ./out/Flutter -create
$ rm ./out/Flutter.framework/Flutter
$ mv ./out/Flutter ./out/Flutter.framework/
经过漫长的编译期,最后的产物 Flutter.framework
存放在 out
这个文件夹里面。拷贝出来,放到我们的 pod
库里面。
注意
- 如果执行
flutter doctor -v
一直处于:
Waiting for another flutter command to release the startup lock
这个状态需要把 Flutter
环境目录下:bin/cache
里面的 lockfile
删掉。再执行flutter doctor -v
- 执行
flutter build ios
的时候,遇到
The sandbox is not in sync with the Podfile.lock
解决方法,可以参考我这里的回答:
github issue
网友评论