Flutter Engine与SDK的定制化与编译
概述
对于Flutter SDK相关的定制化,也就是两个地方,分别为Flutter Engine与Flutter SDK,对于定制化后的应用,则需要我们重新编译相关的代码产物,主要为Flutter Engine的编译和Flutter Tools的编译
Flutter Engine编译
编译配置
配置Depot_tools脚本工具集
获取Chromium的depot_tools
脚本工具集,depot_tools
是Google用来管理Chromium源码的工具集,它包含了一系列实用脚本,如:gclient、ninja、repo等。gclient和repo都是用来检出项目源码的脚本,主要区别是gclient主要依赖于.gclient
与DEPS
这两个配置文件进行多项目模块源码的依赖检出,而repo主要依赖于一个manifest.xml
配置文件来进行多项目模块源码检出,gclient定制性相对高些,也更复杂些
获取depot_tools
脚本工具集可以通过Git获取:
$ git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git
并配置到环境变量中:
$ export PATH=$PATH:/path/to/depot_tools
构建Flutter Engine产物使用的构建系统是Ninja
,Chromium的构建也是使用它,它是一个专注于速度的小型构建系统,即它的输入文件是由更高级别的构建系统生成的产物,而GN
就是一个专门生成Ninja构建文件的元构建系统,所以构建Flutter Engine的步骤是先用GN构建Ninja的输入文件,再由Ninja构建最终产物,即:
$ ./flutter/tools/gn
gn gen --check in out/path
$ ninja -C out/path
检出Flutter Engine源码
Fork并检出Flutter Engine源码,并重新命名为engine
,这里需要Fork是因为后续可能会对Flutter Engine进行一些定制化
$ git clone https://github.com/Sunzxyong/flutter
配置代理
在检出Flutter Engine所有源码的过程中,往往会出现如下或其它一些类似异常:
[P27678 17:18:58.373 client.go:311 W] RPC failed transiently. Will retry in 1m4s {"error":"failed to send request: Post https://chrome-infra-packages.appspot.com/prpc/cipd.Repository/GetInstanceURL: EOF", "host":"chrome-infra-packages.appspot.com", "method":"GetInstanceURL", "service":"cipd.Repository", "sleepTime":"1m4s"}
Error: failed to update packages, see the log.
Error: Command '/usr/local/Cellar/python@2/2.7.15_3/Frameworks/Python.framework/Versions/2.7/Resources/Python.app/Contents/MacOS/Python src/tools/buildtools/update.py' returned non-zero exit status 1 in /Users/Sunzxyong/Library/Flutter/engine
Hook '/usr/local/Cellar/python@2/2.7.15_3/Frameworks/Python.framework/Versions/2.7/Resources/Python.app/Contents/MacOS/Python src/tools/buildtools/update.py' took 307.37 secs
这些异常的导致几乎都是网络环境被墙问题,所以需要配置下代理,主要配置的地方有两个,一是github的代理,二是终端的http(s)代理
1、配置Github的代理
通过编辑hosts配置文件进行配置:
MacBook-Pro-3:~ Sunzxyong$ sudo vim /etc/hosts
然后添加github.com域名与其ip地址的对应关系
2、配置终端的代理
终端的代理,我们通过export环境变量的方式,这样只对当前终端进程有效,而不影响后续终端的使用,然后在当前终端切换到Flutter Engine目录便可准备编译,即:
MacBook-Pro-3:~ Sunzxyong$ export http_proxy=http://127.0.0.1:1087
MacBook-Pro-3:~ Sunzxyong$ export https_proxy=http://127.0.0.1:1087
MacBook-Pro-3:~ Sunzxyong$ cd /Users/Sunzxyong/Library/Flutter/engine
配置gclient依赖与编译分支
在engine
目录中,新建一个.gclient
文件,内容如下:
solutions = [
{
"managed": False,
"name": "src/flutter",
"url": "git@github.com:Sunzxyong/engine.git",
"custom_deps": {},
"deps_file": "DEPS",
"safesync_url": "",
},
]
这里对应的url的值修改为上述自己Fork的Flutter Engine的Git地址即可,其它保持不变
先确保当前目录是Engine目录,然后执行下面命令进行同步Flutter Engine所依赖的所有代码:
MacBook-Pro-3:~ Sunzxyong$ cd /path/to/engine
MacBook-Pro-3:engine Sunzxyong$ gclient sync
接下来即是切换Flutter Engine对应的编译分支,因为默认拉下来的是master分支,如果我们对Flutter Engine进行了定制化,肯定不能在master分支上直接进行编译,所以需要切换成我们进行了定制化的分支或当前工程中所使用的Flutter SDK对应的Engine的分支,查看当前Flutter SDK使用的是哪个版本的Engine,在Flutter SDK中的位置为:
bin/internal/engine.version
这个值是无论我们进不进行定制化都得拿到,不进行定制化我们可以直接切换到这个值所对应的版本,而进行定制化的话,因为定制化肯定得基于当前使用的版本作为基线版本进行定制化,所以定制化后要切换分支即是我们自己commit id的值
如下是我获取到v1.2.2版本的Flutter SDK依赖的Engine的commit id的值:
f1f19bba8f0089490962316867bd222727510ac5
接下来进行分支切换,首先切换到engine/src/flutter
目录,然后依次执行:
MacBook-Pro-3:~ Sunzxyong$ cd /path/to/engine/src/flutter
MacBook-Pro-3:flutter Sunzxyong$ git reset --hard f1f19bba8f0089490962316867bd222727510ac5
MacBook-Pro-3:flutter Sunzxyong$ gclient sync --with_branch_heads --with_tags
其中gclient sync --with_branch_heads --with_tags这段命令含义为:
Checkout all the submodules at their branch DEPS revisions.
编译Engine
编译Flutter Engine使用的是GN
和Ninja
进行编译,GN编译后生成Ninja的构建文件,Ninja将输入文件进行编译成最终产物,如下是GN
的编译选项:
usage: gn [-h] [--unoptimized] [--runtime-mode {debug,profile,release}]
[--dynamic] [--interpreter] [--dart-debug]
[--target-os {android,ios,linux}] [--android]
[--android-cpu {arm,x64,x86,arm64}] [--ios] [--ios-cpu {arm,arm64}]
[--simulator] [--linux-cpu {x64,x86,arm64,arm}]
[--arm-float-abi {hard,soft,softfp}] [--goma] [--no-goma] [--lto]
[--no-lto] [--clang] [--no-clang] [--target-sysroot TARGET_SYSROOT]
[--target-toolchain TARGET_TOOLCHAIN]
[--target-triple TARGET_TRIPLE]
[--toolchain-prefix TOOLCHAIN_PREFIX]
[--operator-new-alignment OPERATOR_NEW_ALIGNMENT] [--enable-vulkan]
[--embedder-for-target] [--coverage] [--out-dir OUT_DIR]
上述的编译选项可以自由组合成非常多种的编译组合,其中--target-os
指定编译产物的平台与--android
或--ios
是等价的,通过GN进行的预编译生成Ninja的构建文件,除了预编译指定平台的构建文件之外,还需要预编译Host的构建文件(即PC编译平台的),当通过Ninja进行最终产物的编译时,会用到指定平台的构建文件和Host的构建文件进行编译
开始进行编译,需要把目录切换到engine的src
目录,然后进行编译:
MacBook-Pro-3:~ Sunzxyong$ cd /path/to/engine/src
MacBook-Pro-3:src Sunzxyong$ ./flutter/tools/gn ...
MacBook-Pro-3:src Sunzxyong$ ninja -C out/...
其中x86的编译产物,在MacOS上需要XCode版本在9.4以下版本才能进行编译,如果需要x86的产物,可以看官方的编译x86产物的兼容编译配置:Supporting-legacy-platforms
如下是常用的编译组合,包含Android和IOS两个平台以及对应cpu架构类型,分别为:未优化的Debug、未优化的Profile、未优化的Release、优化的Debug、优化的Profile、优化的Release,更多的编译组合请看Flutter's modes
编译Android产物
# unopt-debug
# prepare build files for device-side executables.
./flutter/tools/gn --unoptimized --android --runtime-mode debug --android-cpu arm
./flutter/tools/gn --unoptimized --android --runtime-mode debug --android-cpu arm64
./flutter/tools/gn --unoptimized --android --runtime-mode debug --android-cpu x64
# prepare the build files for host-side executables.
./flutter/tools/gn --unoptimized --runtime-mode debug --android-cpu arm
./flutter/tools/gn --unoptimized --runtime-mode debug --android-cpu arm64
./flutter/tools/gn --unoptimized --runtime-mode debug --android-cpu x64
ninja -C out/android_debug_unopt
ninja -C out/android_debug_unopt_arm64
ninja -C out/android_debug_unopt_x64
ninja -C out/host_debug_unopt
ninja -C out/host_debug_unopt_arm64
ninja -C out/host_debug_unopt_x64
# unopt-profile
./flutter/tools/gn --unoptimized --android --runtime-mode profile --android-cpu arm
./flutter/tools/gn --unoptimized --android --runtime-mode profile --android-cpu arm64
./flutter/tools/gn --unoptimized --android --runtime-mode profile --android-cpu x64
./flutter/tools/gn --unoptimized --runtime-mode profile --android-cpu arm
./flutter/tools/gn --unoptimized --runtime-mode profile --android-cpu arm64
./flutter/tools/gn --unoptimized --runtime-mode profile --android-cpu x64
ninja -C out/android_profile_unopt
ninja -C out/android_profile_unopt_arm64
ninja -C out/android_profile_unopt_x64
ninja -C out/host_profile_unopt
ninja -C out/host_profile_unopt_arm64
ninja -C out/host_profile_unopt_x64
# unopt-release
./flutter/tools/gn --unoptimized --android --runtime-mode release --android-cpu arm
./flutter/tools/gn --unoptimized --android --runtime-mode release --android-cpu arm64
./flutter/tools/gn --unoptimized --android --runtime-mode release --android-cpu x64
./flutter/tools/gn --unoptimized --runtime-mode release --android-cpu arm
./flutter/tools/gn --unoptimized --runtime-mode release --android-cpu arm64
./flutter/tools/gn --unoptimized --runtime-mode release --android-cpu x64
ninja -C out/android_release_unopt
ninja -C out/android_release_unopt_arm64
ninja -C out/android_release_unopt_x64
ninja -C out/host_release_unopt
ninja -C out/host_release_unopt_arm64
ninja -C out/host_release_unopt_x64
# opt-debug
./flutter/tools/gn --android --runtime-mode debug --android-cpu arm
./flutter/tools/gn --android --runtime-mode debug --android-cpu arm64
./flutter/tools/gn --android --runtime-mode debug --android-cpu x64
./flutter/tools/gn --runtime-mode debug --android-cpu arm
./flutter/tools/gn --runtime-mode debug --android-cpu arm64
./flutter/tools/gn --runtime-mode debug --android-cpu x64
ninja -C out/android_debug
ninja -C out/android_debug_arm64
ninja -C out/android_debug_x64
ninja -C out/host_debug
ninja -C out/host_debug_arm64
ninja -C out/host_debug_x64
# opt-profile
./flutter/tools/gn --android --runtime-mode profile --android-cpu arm
./flutter/tools/gn --android --runtime-mode profile --android-cpu arm64
./flutter/tools/gn --android --runtime-mode profile --android-cpu x64
./flutter/tools/gn --runtime-mode profile --android-cpu arm
./flutter/tools/gn --runtime-mode profile --android-cpu arm64
./flutter/tools/gn --runtime-mode profile --android-cpu x64
ninja -C out/android_profile
ninja -C out/android_profile_arm64
ninja -C out/android_profile_x64
ninja -C out/host_profile
ninja -C out/host_profile_arm64
ninja -C out/host_profile_x64
# opt-release
./flutter/tools/gn --android --runtime-mode release --android-cpu arm
./flutter/tools/gn --android --runtime-mode release --android-cpu arm64
./flutter/tools/gn --android --runtime-mode release --android-cpu x64
./flutter/tools/gn --runtime-mode release --android-cpu arm
./flutter/tools/gn --runtime-mode release --android-cpu arm64
./flutter/tools/gn --runtime-mode release --android-cpu x64
ninja -C out/android_release
ninja -C out/android_release_arm64
ninja -C out/android_release_x64
ninja -C out/host_release
ninja -C out/host_release_arm64
ninja -C out/host_release_x64
编译IOS产物
其中IOS编译选项中,有个--simulator
编译选项,是编译IOS模拟器的产物,如有需要可在下属编译命令中加上该选项
# unopt-debug
# prepare build files for device-side executables.
./flutter/tools/gn --unoptimized --ios --runtime-mode debug --ios-cpu arm
./flutter/tools/gn --unoptimized --ios --runtime-mode debug --ios-cpu arm64
# prepare the build files for host-side executables.
./flutter/tools/gn --unoptimized --runtime-mode debug --ios-cpu arm
./flutter/tools/gn --unoptimized --runtime-mode debug --ios-cpu arm64
ninja -C out/ios_debug_unopt_arm
ninja -C out/ios_debug_unopt
ninja -C out/host_debug_unopt_arm
ninja -C out/host_debug_unopt
# unopt-profile
./flutter/tools/gn --unoptimized --ios --runtime-mode profile --ios-cpu arm
./flutter/tools/gn --unoptimized --ios --runtime-mode profile --ios-cpu arm64
./flutter/tools/gn --unoptimized --runtime-mode profile --ios-cpu arm
./flutter/tools/gn --unoptimized --runtime-mode profile --ios-cpu arm64
ninja -C out/ios_profile_unopt_arm
ninja -C out/ios_profile_unopt
ninja -C out/host_profile_unopt_arm
ninja -C out/host_profile_unopt
# unopt-release
./flutter/tools/gn --unoptimized --ios --runtime-mode release --ios-cpu arm
./flutter/tools/gn --unoptimized --ios --runtime-mode release --ios-cpu arm64
./flutter/tools/gn --unoptimized --runtime-mode release --ios-cpu arm
./flutter/tools/gn --unoptimized --runtime-mode release --ios-cpu arm64
ninja -C out/ios_release_unopt_arm
ninja -C out/ios_release_unopt
ninja -C out/host_release_unopt_arm
ninja -C out/host_release_unopt
# opt-debug
./flutter/tools/gn --ios --runtime-mode debug --ios-cpu arm
./flutter/tools/gn --ios --runtime-mode debug --ios-cpu arm64
./flutter/tools/gn --runtime-mode debug --ios-cpu arm
./flutter/tools/gn --runtime-mode debug --ios-cpu arm64
ninja -C out/ios_debug_arm
ninja -C out/ios_debug
ninja -C out/host_debug_arm
ninja -C out/host_debug
# opt-profile
./flutter/tools/gn --ios --runtime-mode profile --ios-cpu arm
./flutter/tools/gn --ios --runtime-mode profile --ios-cpu arm64
./flutter/tools/gn --runtime-mode profile --ios-cpu arm
./flutter/tools/gn --runtime-mode profile --ios-cpu arm64
ninja -C out/ios_profile_arm
ninja -C out/ios_profile
ninja -C out/host_profile_arm
ninja -C out/host_profile
# opt-release
./flutter/tools/gn --ios --runtime-mode release --ios-cpu arm
./flutter/tools/gn --ios --runtime-mode release --ios-cpu arm64
./flutter/tools/gn --runtime-mode release --ios-cpu arm
./flutter/tools/gn --runtime-mode release --ios-cpu arm64
ninja -C out/ios_release_arm
ninja -C out/ios_release
ninja -C out/host_release_arm
ninja -C out/host_release
编译产物输出路径
编译后的产物输出路径在/path/to/engine/src/out
目录下,在对应的构建选项目录下分别有flutter.jar
和Flutter.framework
编译产物,如下所示:
对于编译产物的应用,可以通过--local-engine
进行配置引擎的路径或替换Flutter SDK中对应engine
Flutter SDK编译
通常情况下,对于Flutter SDK的定制化场景可能会相对多些,如定制Flutter工程结构,添加flutterw包装器脚本:
Creating project test_module...
test_module/.gitignore (created)
test_module/.idea/libraries/Dart_SDK.xml (created)
test_module/.idea/libraries/Flutter_for_Android.xml (created)
test_module/.idea/modules.xml (created)
test_module/.idea/workspace.xml (created)
test_module/.metadata (created)
test_module/lib/main.dart (created)
test_module/test_module.iml (created)
test_module/test_module_android.iml (created)
test_module/pubspec.yaml (created)
test_module/README.md (created)
test_module/test/widget_test.dart (created)
test_module/flutter/.DS_Store (created)
test_module/flutter/wrapper/flutter-wrapper.properties (created)
test_module/flutterw.bat (created)
test_module/flutterw (created)
Running "flutter packages get" in test_module... 7.2s
Wrote 16 files.
All done!
如上是通过修改后Flutter SDK后通过flutter命令创建的一个module工程,自动包含了flutterw脚本
而如何让修改后的Flutter SDK代码生效,主要有两种方式:
1、删除/path/to/flutter/bin/cache/flutter_tools.snapshot文件
2、删除/path/to/flutter/bin/cache/flutter_tools.stamp文件
其中文件含义为:
1、flutter_tools.snapshot:当前Flutter SDK的Dart代码的源码集.
2、flutter_tools.stamp:当前Flutter SDK的commit id.
而当我们每次运行flutter
命令时候,都会校验这两个文件,不存在则会基于当前的Flutter SDK代码重新构建/path/to/flutter/packages/flutter_tools
代码生成flutter_tools.snapshot
,最终会通过dart
命令,把flutter_tools.snapshot
源码集传入而生效,如下:
"$DART" $FLUTTER_TOOL_ARGS "$SNAPSHOT_PATH" "$@"
Flutter Tools调试
对于修改后Flutter Tools的调试,使用AS直接打开:
/path/to/flutter/packages/flutter_tools
工程,该工程是一个packages
工程
而对于我们构建的入口,是在:
/path/to/flutter/packages/flutter_tools/bin/flutter_tools.dart
文件,代码如下:
import 'package:flutter_tools/executable.dart' as executable;
void main(List<String> args) {
executable.main(args);
}
对应的会通过executable.dart
调用main函数执行,也就是进行一系列Command的配置以及执行
所以,进行修改后代码的调试,我们可以直接修改flutter_tools.dart
中的args
入参进行调试,在flutter_tools.dart
中右键直接运行,或者想改变当前运行的Configurations配置,可以新添加一个Configurations
,添加一个Dart Command Line App
,然后指定flutter_tools.dart
以及工作目录,接着就可以直接运行