概述
对于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获取:
1 | $ git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git |
并配置到环境变量中:
1 | $ export PATH=$PATH:/path/to/depot_tools |
构建Flutter Engine产物使用的构建系统是Ninja
,Chromium的构建也是使用它,它是一个专注于速度的小型构建系统,即它的输入文件是由更高级别的构建系统生成的产物,而GN
就是一个专门生成Ninja构建文件的元构建系统,所以构建Flutter Engine的步骤是先用GN构建Ninja的输入文件,再由Ninja构建最终产物,即:
1 | $ ./flutter/tools/gn |
检出Flutter Engine源码
Fork并检出Flutter Engine源码,并重新命名为engine
,这里需要Fork是因为后续可能会对Flutter Engine进行一些定制化
1 | $ git clone https://github.com/Sunzxyong/flutter |
配置代理
在检出Flutter Engine所有源码的过程中,往往会出现如下或其它一些类似异常:
1 | [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"} |
这些异常的导致几乎都是网络环境被墙问题,所以需要配置下代理,主要配置的地方有两个,一是github的代理,二是终端的http(s)代理
1、配置Github的代理
通过编辑hosts配置文件进行配置:
1 | MacBook-Pro-3:~ Sunzxyong$ sudo vim /etc/hosts |
然后添加github.com域名与其ip地址的对应关系
2、配置终端的代理
终端的代理,我们通过export环境变量的方式,这样只对当前终端进程有效,而不影响后续终端的使用,然后在当前终端切换到Flutter Engine目录便可准备编译,即:
1 | MacBook-Pro-3:~ Sunzxyong$ export http_proxy=http://127.0.0.1:1087 |
配置gclient依赖与编译分支
在engine
目录中,新建一个.gclient
文件,内容如下:
1 | solutions = [ |
这里对应的url的值修改为上述自己Fork的Flutter Engine的Git地址即可,其它保持不变
先确保当前目录是Engine目录,然后执行下面命令进行同步Flutter Engine所依赖的所有代码:
1 | MacBook-Pro-3:~ Sunzxyong$ cd /path/to/engine |
接下来即是切换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
目录,然后依次执行:
1 | MacBook-Pro-3:~ Sunzxyong$ cd /path/to/engine/src/flutter |
其中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
的编译选项:
1 | usage: gn [-h] [--unoptimized] [--runtime-mode {debug,profile,release}] |
上述的编译选项可以自由组合成非常多种的编译组合,其中--target-os
指定编译产物的平台与--android
或--ios
是等价的,通过GN进行的预编译生成Ninja的构建文件,除了预编译指定平台的构建文件之外,还需要预编译Host的构建文件(即PC编译平台的),当通过Ninja进行最终产物的编译时,会用到指定平台的构建文件和Host的构建文件进行编译
开始进行编译,需要把目录切换到engine的src
目录,然后进行编译:
1 | MacBook-Pro-3:~ Sunzxyong$ cd /path/to/engine/src |
其中x86的编译产物,在MacOS上需要XCode版本在9.4以下版本才能进行编译,如果需要x86的产物,可以看官方的编译x86产物的兼容编译配置:Supporting-legacy-platforms
如下是常用的编译组合,包含Android和IOS两个平台以及对应cpu架构类型,分别为:未优化的Debug、未优化的Profile、未优化的Release、优化的Debug、优化的Profile、优化的Release,更多的编译组合请看Flutter’s modes
编译Android产物
1 | # unopt-debug |
编译IOS产物
其中IOS编译选项中,有个--simulator
编译选项,是编译IOS模拟器的产物,如有需要可在下属编译命令中加上该选项
1 | # unopt-debug |
编译产物输出路径
编译后的产物输出路径在/path/to/engine/src/out
目录下,在对应的构建选项目录下分别有flutter.jar
和Flutter.framework
编译产物,如下所示:
对于编译产物的应用,可以通过--local-engine
进行配置引擎的路径或替换Flutter SDK中对应engine
Flutter SDK编译
通常情况下,对于Flutter SDK的定制化场景可能会相对多些,如定制Flutter工程结构,添加flutterw包装器脚本:
1 | Creating project test_module... |
如上是通过修改后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
源码集传入而生效,如下:
1 | "$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
文件,代码如下:
1 | import 'package:flutter_tools/executable.dart' as executable; |
对应的会通过executable.dart
调用main函数执行,也就是进行一系列Command的配置以及执行
所以,进行修改后代码的调试,我们可以直接修改flutter_tools.dart
中的args
入参进行调试,在flutter_tools.dart
中右键直接运行,或者想改变当前运行的Configurations配置,可以新添加一个Configurations
,添加一个Dart Command Line App
,然后指定flutter_tools.dart
以及工作目录,接着就可以直接运行