由于flutter官方引擎有时候会有一些问题,但是又不好直接大范围升级flutter版本。且flutter引擎是相对独立的版块,所以定制引擎就有了市场。
背景
2.8.1flutter引擎层在iOS的platform view层,shell调用时机有问题。导致线上会有相应的引擎层crash。 官方已经修复,但是需要升级至2.10.3+,我们暂时不升级,采用iOS自定义引擎的方式解决。
官方issue 官方已经修复了改问题,并已经合并代码到master
修复的pull request:https://github.com/flutter/engine/pull/30835/commits
bufix的描述:https://github.com/flutter/flutter/issues/95844
合并到引擎commit记录:https://github.com/flutter/engine/commit/fb3ee7f2b5e6e537a2a83c9fe2cf733cd9c6ec06
在高版本,2.10.2(2.10.3+)以上此类问题已修复。
2.8.1 Cherrypicks:https://github.com/flutter/engine/pull/30355
一 环境准备
- git
- Python
- Xcode
- depot_tools
depot_tools 安装(需要全局VPN否则很慢)
创建目录 /Users/xx/Desktop/flutter-engine
cd /Users/xx/Desktop/flutter-engine git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git
配置环境 (~/.zshrc或者~/.bashrc)
export PATH=/Users/xx/Desktop/flutter-engine/depot_tools:$PATH
depot_tools安装后的几个工具,gclient、gn和ninja工具介绍
| 工具 | 描述 | 作用 | | — | — | — | | gclient | 可以理解为代码以及依赖管理工具 | 它的作用类似 git 的 submodule,用来将多个git仓库组成一个solution进行管理。 | | gn和ninja | 构建工具,类似(make+makefile,这个我们也接触很少) | gn元构建系统(meta build system),只输出 Ninja 构建文件。ninja需要gn输出NinjaBuild files。 |
二 环境配置
gclient 配置
在/Users/xxx/Desktop/flutter-engine目录engine文件夹创建.gclient文件
solutions = [
{
"managed": False,
"name": "src/flutter",
"url": "git@gitlab.xxx.cn:Group/xx_flutter_engine.git@hash-adafbaaf",
"custom_deps": {},
"deps_file": "DEPS",
"safesync_url": "",
},
]
url字段是你需要的引擎commit。
同步依赖
cd /Users/xxx/Desktop/flutter-engine/engine
gclient sync
执行这一步,国内很多用户会很慢,所以建议先下从flutter引擎的git仓库下载好项目,然后把内容(不包括名称)复制到src/flutter下面,再执行gclient sync,而且建议开全局代理,在zsh文件中(笔者使用的是zsh)添加:
#export http_proxy=http://127.0.0.1:9999
#export https_proxy=http://127.0.0.1:9999
这里的9999是vpn全局的端口号,#是笔者使用完注释回去。否则会影响其他网络
三 编译产物
执行gn,生成源码工程
cd到src目录下:
cd /Users/xxx/Desktop/flutter-engine/engine/src
# --simulator就是模拟器
# --ios-cpu=arm就是armv7,不指定默认就是arm64
flutter/tools/gn --ios --unoptimized
在src/out/ios_debug_unopt目录下,会生成一个 Xcode 项目,用于debug时候使用引擎源代码。
flutter/tools/gn --unoptimized
会生成src/out/host_debug_unopt,我在debug引擎时候发现需要里面的dart-sdk,所以这个也需要编译一下。如果没有修改dart层代码就不需要执行这一步。
不同命令的组合:
gn | mode & arch | out |
---|---|---|
flutter/tools/gn –unoptimized | src/out/host_debug_unopt | |
flutter/tools/gn –ios –unoptimized | debug arm64 | src/out/ios_debug_unopt |
flutter/tools/gn | src/out/host_debug | |
flutter/tools/gn –ios –simulator | debug simulator | src/out/ios_debug_sim |
flutter/tools/gn –ios –ios-cpu arm | debug armv7 | src/out/ios_debug_arm |
flutter/tools/gn –ios | debug arm64 | src/out/ios_debug |
flutter/tools/gn –ios –ios-cpu arm –runtime-mode profile | profile armv7 | src/out/ios_profile_arm |
flutter/tools/gn –ios –runtime-mode profile | profile arm64 | src/out/ios_profile |
flutter/tools/gn –ios –ios-cpu arm –runtime-mode release | release armv7 | src/out/ios_release_arm |
flutter/tools/gn –ios –runtime-mode release | release arm64 | src/out/ios_release |
执行ninja,生成framework产物
ninja -C out/ios_debug_unopt && ninja -C out/host_debug_unopt
编译过程很漫长,可以在ninja后面加上参数-j 2,避免编译占用过多的电脑资源,影响你开发。
四 创建xcframework和gen_snapshots
编译完成之后,就要创建最后的Flutter.xcframework 官方也有提供python脚本工具,src/flutter/sky/tools目录下的:create_ios_framework.py和create_macos_gen_snapshots.py
创建Flutter.xcframework:release版本加–dsym参数会生成dysm符号表
cd ~/Desktop/flutter-engine/engine/src/flutter/sky/tools
# debug版本Flutter.xcframework
python create_ios_framework.py --dst ~/Desktop/flutter-engine/engine/src/out/vd/ios --arm64-out-dir ~/Desktop/flutter-engine/engine/src/out/ios_debug --armv7-out-dir ~/Desktop/flutter-engine/engine/src/out/ios_debug_arm --simulator-out-dir ~/Desktop/flutter-engine/engine/src/out/ios_debug_sim
# profile版本Flutter.xcframework
python create_ios_framework.py --dst ~/Desktop/flutter-engine/engine/src/out/vd/ios-profile --arm64-out-dir ~/Desktop/flutter-engine/engine/src/out/ios_profile --armv7-out-dir ~/Desktop/flutter-engine/engine/src/out/ios_profile_arm --simulator-out-dir ~/Desktop/flutter-engine/engine/src/out/ios_debug_sim
# release版本Flutter.xcframework
python create_ios_framework.py --dst ~/Desktop/flutter-engine/engine/src/out/vd/ios-release --arm64-out-dir ~/Desktop/flutter-engine/engine/src/out/ios_release --armv7-out-dir ~/Desktop/flutter-engine/engine/src/out/ios_release_arm --simulator-out-dir ~/Desktop/flutter-engine/engine/src/out/ios_debug_sim --dsym
# 每个版本都加上了模拟器的部分,便于使用方模拟器调试
创建gen_snapshots
cd ~/Desktop/flutter-engine/engine/src/flutter/sky/tools
# debug版本gen_snapshot_arm64和gen_snapshot_armv7
python create_macos_gen_snapshots.py --dst ~/Desktop/flutter-engine/engine/src/out/vd/ios --arm64-out-dir ~/Desktop/flutter-engine/engine/src/out/ios_debug --armv7-out-dir ~/Desktop/flutter-engine/engine/src/out/ios_debug_arm
# profile版本gen_snapshot_arm64和gen_snapshot_armv7
python create_macos_gen_snapshots.py --dst ~/Desktop/flutter-engine/engine/src/out/vd/ios-profile --arm64-out-dir ~/Desktop/flutter-engine/engine/src/out/ios_profile --armv7-out-dir ~/Desktop/flutter-engine/engine/src/out/ios_profile_arm
# release版本gen_snapshot_arm64和gen_snapshot_armv7
python create_macos_gen_snapshots.py --dst ~/Desktop/flutter-engine/engine/src/out/vd/ios-release --arm64-out-dir ~/Desktop/flutter-engine/engine/src/out/ios_release --armv7-out-dir ~/Desktop/flutter-engine/engine/src/out/ios_release_arm
# 模拟器是JIT的,不需要gen_snapshot
五 总结
最终我们需要armv7、arm64、x86-64的产物,组合命令如下:
//1 执行这一部分命令生成不同架构的产物
cd ~/Desktop/flutter-engine/engine/src
./flutter/tools/gn --unoptimized
./flutter/tools/gn --ios --runtime-mode=debug --simulator
./flutter/tools/gn --ios --runtime-mode=release
./flutter/tools/gn --ios --runtime-mode=release --ios-cpu=arm
ninja -C out/host_debug_unopt && ninja -C out/ios_debug_sim && ninja -C out/ios_release && ninja -C out/ios_release_arm
//2 执行这一部分命令生成包含所有架构的产物
cd ~/Desktop/flutter-engine/engine/src/flutter/sky/tools
python3 create_ios_framework.py \
--dst ~/Desktop/flutter-engine/engine/src/out/vd/ios-release \
--arm64-out-dir ~/Desktop/flutter-engine/engine/src/out/ios_release \
--armv7-out-dir ~/Desktop/flutter-engine/engine/src/out/ios_release_arm \
--simulator-out-dir ~/Desktop/flutter-engine/engine/src/out/ios_debug_sim \
--dsym
//2 执行这一部分命令生成gen_snapshots文件
python3 create_macos_gen_snapshots.py \
--dst ~/Desktop/flutter-engine/engine/src/out/vd/ios-release \
--arm64-out-dir ~/Desktop/flutter-engine/engine/src/out/ios_release \
--armv7-out-dir ~/Desktop/flutter-engine/engine/src/out/ios_release_arm
整个编译过程工程目录结构:

/flutter-engine:自己创建的引擎目录 /flutter-engine/depot_tools:depot_tools工具目录 /flutter-engine/engine:引擎目录 /flutter-engine/engine/.gclient:gclient配置文件 /flutter-engine/engine/src:https://github.com/flutter/engine代码存放目录 /flutter-engine/engine/src/out:不同架构源码工程目录 /flutter-engine/engine/src/out/vd/ios-release:聚合产物目录
参考文档
【官方】Compiling the engine: https://github.com/flutter/flutter/wiki/Compiling-the-engine#compiling-for-ios-from-macos
【官方】Creating an iOS Bitcode enabled app: https://github.com/flutter/flutter/wiki/Creating-an-iOS-Bitcode-enabled-app