Flutter源码剖析(一):源码获取与构建
概述
本文介绍了Flutter源码的获取与构建,后面会另有文章介绍Flutter源码的版本管理、开发环境搭建等主题。
准备工作
Flutter源码分为两个部分:
- flutter/flutter是框架层,为开发者提供各种接口,主要是dart代码。
- flutter/engine是引擎层,负责Flutter的渲染以及宿主的交互。
相关依赖的安装可参考官方文档:Setting up the Engine development environment · flutter/flutter Wiki。以我的Mac为例,如JDK等一般都已经安装,无需担心。
源码下载
flutter/flutter
可以直接通过git下载,但是flutter/engine
需要通过gclient
工具获取,因为engine
有很多依赖,gclient
可以很好地处理这些依赖,简化源码管理流程。
首先,新建一个目录,下载flutter
框架代码:
$ mkdir flutter_source_code
$ cd flutter_source_code
$ git clone https://github.com/flutter/flutter.git
Cloning into 'flutter'...
remote: Enumerating objects: 12, done.
remote: Counting objects: 100% (12/12), done.
remote: Compressing objects: 100% (12/12), done.
remote: Total 272396 (delta 0), reused 6 (delta 0), pack-reused 272384
Receiving objects: 100% (272396/272396), 116.98 MiB | 2.48 MiB/s, done.
Resolving deltas: 100% (210440/210440), done.
获取depot_tools
工具(这个一开始是用来管理chromium
源码的):
$ git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git
Cloning into 'depot_tools'...
remote: Sending approximately 34.14 MiB ...
remote: Total 40539 (delta 27803), reused 40539 (delta 27803)
Receiving objects: 100% (40539/40539), 34.14 MiB | 5.04 MiB/s, done.
Resolving deltas: 100% (27803/27803), done.
设置环境变量(每次构建之前都要设置,也可以写入系统配置):
export PATH=$PATH:`pwd`/depot_tools
开始拉取代码(这一步比较耗时)
$ gclient sync [18:04:43]
......
remote: Enumerating objects: 25, done.
remote: Counting objects: 100% (25/25), done.
remote: Compressing objects: 100% (22/22), done.
remote: Total 209672 (delta 10), reused 13 (delta 3), pack-reused 209647
Receiving objects: 100% (209672/209672), 196.61 MiB | 3.74 MiB/s, done.
Resolving deltas: 100% (153791/153791), done.
Syncing projects: 31% (33/104) src/third_party/vulkan
[0:03:59] Still working on:
[0:03:59] src/ios_tools
[0:03:59] src/third_party/angle
[0:03:59] src/third_party/dart
[0:03:59] src/third_party/icu
......
[0:12:48] Still working on:
[0:12:48] src/third_party/dart
Syncing projects: 100% (104/104), done.
Running hooks: 100% ( 9/ 9) dart package config
________ running 'vpython src/flutter/tools/run_third_party_dart.py' in '/Users/vimerzhao/WorkProject/flutter_source_code'
Resolving dependencies... (1.7s)
+ charcode 1.1.3
+ collection 1.14.13
+ meta 1.2.3
+ package_config 1.9.3
+ path 1.7.0
+ pub_semver 1.4.4
+ source_span 1.7.0
+ string_scanner 1.0.5
+ term_glyph 1.1.0
+ yaml 2.2.1
Changed 10 dependencies!
需要注意的是,Syncing projects: 100% (104/104), done
之后,会继续下载一些大文件,可能命令行没有输出,一定不能强制退出,可以通过资源管理器查看网络的流量,确定cipd
是否在下载:
(因为git不是很擅长下载大文件,所以产生了cipd这个程序来做这些工作)
此时的目录结构:
$ tree -L 1
.
├── depot_tools # 源码管理工具
├── flutter # flutter framework目录
└── src # flutter engine以及相关依赖所在目录
framework的版本和engine的版本是一一对应的,framework的分支规则如下:
stable
是当前的稳定分支,无特殊情况,推荐开发者使用该分支作为flutter sdkmaster
包含最新的特性,但是不稳定- 每个版本会打上对应的tag
截止到 2020-10-29 ,最新的较稳定版本是 1.22.0,于是我们也先切到这个版本(不是必选的,但是个人认为:基于一个明确的版本编译和修改源代码似乎更合适)。
$ cd flutter
$ git checkout 1.22.0
$ cat bin/internal/engine.version
5babba6c4d25fa237bbf755ab85c9a0c50b3c6ec
engine.version
这个文件指定了framework对应的engine版本,接下来,我们进入engine目录切换到这次commit。
$ cd ../src/flutter
$ git reset --hard 5babba6c4d25fa237bbf755ab85c9a0c50b3c6ec
HEAD is now at 5babba6c4 Flutter 1.22.0-12.3.pre engine cherrypicks (#21466)
此时,我们需要执行以下命令:
$ gclient sync --with_branch_heads --with_tags
Syncing projects: 100% (104/104), done.
......
Running hooks: 100% ( 8/ 8) dart package config
......
Running hooks: 100% (8/8), done.
后面这两个参数的含义比较晦涩,参考Chromium的说明,其含义是:
Checkout all the submodules at their branch DEPS revisions
因为切换分支之后,某些依赖的版本可能有更改,所以需要再次sync一下,直接在src/flutter
目录执行即可。
以上就完成了源码环境的搭建,下面正式开始编译。
源码编译
首先我们退回到src目录,然后通过gn
生成ninja
需要的元数据:
$ cd ..
$ pwd
/Users/vimerzhao/WorkProject/flutter_source_code/src
$ ./flutter/tools/gn --unoptimized --android --runtime-mode debug --android-cpu arm
Generating GN files in: out/android_debug_unopt
Generating Xcode projects took 75ms
Done. Made 438 targets from 197 files in 1960ms
对于编译参数,Compiling the engine · flutter/flutter Wiki有详细介绍,在此不做赘述,这里我构建的是一个未优化、Android平台、debug版本、arm 32位的 engine。
此时,查看out目录,可以看到:
$ ls out/
android_debug_unopt compile_commands.json
compile_commands.json
可以作为IDE的索引文件,提供类/函数/变量的跳转等能力,后面会说到。
然后就可以开始正式的编译了:
$ ninja -C out/android_debug_unopt
ninja: Entering directory `out/android_debug_unopt'
[38/3844] ACTION //flutter/shell/platform/android:flutter_shell_java(//build/toolchain/android:clang_arm)
警告: ../../third_party/android_tools/sdk/build-tools/30.0.1/core-lambda-stubs.jar(java/lang/invoke/LambdaMetafactory.class): 主版本 53 比 52 新, 此编译器
支持最新的主版本。
建议升级此编译器。
注: 某些输入文件使用或覆盖了已过时的 API。
注: 有关详细信息, 请使用 -Xlint:deprecation 重新编译。
1 个警告
[3844/3844] STAMP obj/default.stamp
$ ls out/android_debug_unopt [19:35:15]
all.xcodeproj flutter_embedding_debug-sources.jar.md5.stamp lib.stripped
args.gn flutter_embedding_debug.jar libflutter.so
armeabi_v7a_debug.jar flutter_embedding_debug.jar.md5.stamp libflutter.so.TOC
armeabi_v7a_debug.pom flutter_embedding_debug.pom obj
build.ninja flutter_icu toolchain.ninja
build.ninja.d flutter_patched_sdk vm_outline_strong.dill
clang_x64 gen vm_platform_strong.dill
flutter.jar gyp-mac-tool vm_platform_strong.dill.d
flutter_embedding_debug-sources.jar icudtl.dat zip_archives
其中,flutter_embedding_debug.jar
是Android嵌入层代码,libflutter.so
是flutter的引擎层代码,通过这两个文件,可以在Android工程混合接入Flutter代码。
源码使用
创建一个工程:
$ pwd
/Users/vimerzhao/WorkProject/flutter_source_code
$ ls
depot_tools flutter src
$ ./flutter/bin/flutter create flutter_demo
Downloading Dart SDK from Flutter engine 5babba6c4d25fa237bbf755ab85c9a0c50b3c6ec...
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 172M 100 172M 0 0 4381k 0 0:00:40 0:00:40 --:--:-- 4723k
Building flutter tool...
Downloading Material fonts... 0.5s
Downloading Gradle Wrapper... 0.1s
Downloading package sky_engine... 0.3s
Downloading flutter_patched_sdk tools... 2.7s
Downloading flutter_patched_sdk_product tools... 2.1s
Downloading darwin-x64 tools... 8.2s
Downloading libimobiledevice... 0.0s
Downloading usbmuxd... 0.7s
Downloading libplist... 0.0s
Downloading openssl... 0.2s
......
Creating project flutter_demo...
flutter_demo/ios/Runner.xcworkspace/contents.xcworkspacedata (created)
flutter_demo/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist (created)
......
flutter_demo/.idea/runConfigurations/main_dart.xml (created)
flutter_demo/.idea/libraries/Dart_SDK.xml (created)
flutter_demo/.idea/libraries/KotlinJavaRuntime.xml (created)
flutter_demo/.idea/modules.xml (created)
flutter_demo/.idea/workspace.xml (created)
Running "flutter pub get" in flutter_demo... 2.3s
Wrote 71 files.
All done!
......
Run "flutter doctor" for information about installing additional components.
In order to run your application, type:
$ cd flutter_demo
$ flutter run
使用flutter并指定本地engine运行(不指定则会拉远程的、已经构建好的engine)。
$ ../flutter/bin/flutter run --local-engine-src-path ~/WorkProject/flutter_source_code/src --local-engine=android_debug_unopt
No Flutter engine build found at /Users/vimerzhao/WorkProject/flutter_source_code/src/out/host_debug_unopt.
$ ../flutter/bin/flutter run --local-engine-src-path ~/WorkProject/flutter_source_code/src --local-engine=host_debug_unopt
Launching lib/main.dart on DUK AL20 in debug mode...
Oops; flutter has exited unexpectedly: "Invalid argument(s): Cannot find executable for
/Users/vimerzhao/WorkProject/flutter_source_code/src/out/host_debug_unopt/dart-sdk/bin/dart.".
A crash report has been written to /Users/vimerzhao/WorkProject/flutter_source_code/flutter_demo/flutter_02.log.
...
FAILURE: Build failed with an exception
* Where:
Script '/Users/vimerzhao/WorkProject/flutter_source_code/flutter/packages/flutter_tools/gradle/flutter.gradle' line: 904
* What went wrong:
Execution failed for task ':app:compileFlutterBuildDebug'.
> Process 'command '/Users/vimerzhao/WorkProject/flutter_source_code/flutter/bin/flutter'' finished with non-zero exit value 1
* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.
* Get more help at https://help.gradle.org
BUILD FAILED in 1s
Running Gradle task 'assembleDebug'...
Running Gradle task 'assembleDebug'... Done 1.8s
https://git.io/JTDf0
$../flutter/bin/flutter run --local-engine-src-path ~/WorkProject/flutter_source_code/src --local-engine=h
ost_debug_unopt
Launching lib/main.dart on DUK AL20 in debug mode...
Error: Error when reading '../src/out/host_debug_unopt/gen/frontend_server.dart.snapshot': No such file or directory
the Dart compiler exited unexpectedly.
the Dart compiler exited unexpectedly.
Running Gradle task 'assembleDebug'...
总的来说,遇到一些官方文档上没有提到的问题:
- 输入
android_debug_unopt
却提示找不到host_debug_unopt
,这个莫名其妙,只能先改一下之前构建的文件夹名称了。 - 找不到
dart-sdk
,flutter会下载到bin/cache
目录,只能自己手动copy一份到报错的目录。 - 找不到
frontend_server.dart.snapshot
,在flutter目录用find . -name "frontend_server.dart.snapshot"
找到,然后手动copy一份。
解决这三个问题之后,终于可以运行了。
$ ../flutter/bin/flutter run --local-engine-src-path ~/WorkProject/flutter_source_code/src --local-engine=host_debug_unopt
Launching lib/main.dart on DUK AL20 in debug mode...
Running Gradle task 'assembleDebug'...
Running Gradle task 'assembleDebug'... Done 18.1s
✓ Built build/app/outputs/flutter-apk/app-debug.apk.
Installing build/app/outputs/flutter-apk/app.apk... 3.5s
Waiting for DUK AL20 to report its views... 8ms
Syncing files to device DUK AL20... 210ms
Flutter run key commands.
r Hot reload.
R Hot restart.
h Repeat this help message.
d Detach (terminate "flutter run" but leave application running).
c Clear the screen
q Quit (terminate the application on the device).
An Observatory debugger and profiler on DUK AL20 is available at: http://127.0.0.1:63146/LE7Uc6cshds=/
D/AwareBitmapCacher(24977): handleInit switch not opened pid=24977
Application finished.
总结
以上完成源码的获取与构建,那么:
- 如何高效率的编辑源码?用Vim/VS Code还是Android Studio?
- 如何构建自己的版本?同时,如何保持和官方代码保持同步?
- 如何修改框架层代码并重新编译?
等等。
其实问题还有很多,后面再一一讲解。
参考
- 搭建Flutter Engine源码编译环境
- Flutter Engine 编译指北
- Flutter Engine与SDK的定制化与编译
- Setting up the Engine development environment · flutter/flutter Wiki
- Compiling the engine · flutter/flutter Wiki
- The flutter tool · flutter/flutter Wiki
- Using depot_tools - The Chromium Projects
- Working with Release Branches - The Chromium Projects
- CIPD for chromium dependencies
- Ninja, a small build system with a focus on speed
- gn - Git at Google
更多相关内容可访问我的博客:http://vimerzhao.top/
或
关注我的公众号:
V大师在一号线
Flutter源码剖析(一):源码获取与构建的更多相关文章
- Java集合源码剖析——ArrayList源码剖析
ArrayList简介 ArrayList是基于数组实现的,是一个动态数组,其容量能自动增长,类似于C语言中的动态申请内存,动态增长内存. ArrayList不是线程安全的,只能用在单线程环境下,多线 ...
- 转:【Java集合源码剖析】LinkedHashmap源码剖析
转载请注明出处:http://blog.csdn.net/ns_code/article/details/37867985 前言:有网友建议分析下LinkedHashMap的源码,于是花了一晚上时 ...
- 并发编程之 ThreadLocal 源码剖析
前言 首先看看 JDK 文档的描述: 该类提供了线程局部 (thread-local) 变量.这些变量不同于它们的普通对应物,因为访问某个变量(通过其 get 或 set 方法)的每个线程都有自己的局 ...
- 源码剖析Springboot自定义异常
博主看到新服务是封装的自定义异常,准备入手剖析一下,自定义的异常是如何进行抓住我们请求的方法的异常,并进行封装返回到.废话不多说,先看看如何才能实现封装异常,先来一个示例: @ControllerAd ...
- 08.ElementUI 2.X 源码学习:源码剖析之工程化(三)
0x.00 前言 项目工程化系列文章链接如下,推荐按照顺序阅读文章 . 1️⃣ 源码剖析之工程化(一):项目概览.package.json.npm script 2️⃣ 源码剖析之工程化(二):项目构 ...
- rest_framework之视图及源码剖析
最初形态(工作中可能会使用) 引子 Django的CBV我们应该都有所了解及使用,大体概括一下就是通过定义类并在类中定义get post put delete等对应于请求方法的方法,当请求来的时候会自 ...
- Redis源码剖析
Redis源码剖析和注释(一)---链表结构 Redis源码剖析和注释(二)--- 简单动态字符串 Redis源码剖析和注释(三)--- Redis 字典结构 Redis源码剖析和注释(四)--- 跳 ...
- 07.ElementUI 2.X 源码学习:源码剖析之工程化(二)
0x.00 前言 项目工程化系列文章链接如下,推荐按照顺序阅读文章 . 1️⃣ 源码剖析之工程化(一):项目概览.package.json.npm script 2️⃣ 源码剖析之工程化(二):项目构 ...
- 老李推荐:第6章2节《MonkeyRunner源码剖析》Monkey原理分析-事件源-事件源概览-获取命令字串
老李推荐:第6章2节<MonkeyRunner源码剖析>Monkey原理分析-事件源-事件源概览-获取命令字串 从上一节的描述可以知道,MonkeyRunner发送给Monkey的命令 ...
随机推荐
- CLP(FD)有限域上的约束逻辑式编程
译自http://www.pathwayslms.com/swipltuts/clpfd/clpfd.html#_simple_constraints,SWI-Prolog官网所推荐的进阶教程.目前还 ...
- Trie树【字典树】浅谈
最近随洛谷日报看了一下Trie树,来写一篇学习笔记. Trie树:支持字符串前缀查询等(目前我就学了这些qwq) 一般题型就是给定一个模式串,几个文本串,询问能够匹配前缀的文本串数量. 首先,来定义下 ...
- selenium3+python3自动化环境搭建
(我也是小白,刚开始接触自动化,以下内容是我自己在配置环境的时候遇到的问题及解决方法,是后面才记录的要是有什么遗漏或者问题,欢迎帮忙指出来.)1.1首先下载python下载网址:https://www ...
- SpringBoot常见注解
0.前言 这篇文章介绍的 Spring/SpringBoot 常用注解基本已经涵盖你工作中遇到的大部分常用的场景.对于每一个注解我都说了具体用法,掌握搞懂,使用 SpringBoot 来开发项目基本没 ...
- 网页添加 Live2D 看板娘
我是先参考别人的[点击跳转]博客来做的.不过我发现网上很多人都没有把一些细节写出来,用了别人那里下载的文件后里面的一些跳转链接就跳到他们的页面了.所以我这里写一写如何修改这些跳转链接吧. 1. ...
- python BeautifulSoup的使用方法
BeautifulSoup的使用 我们学习了正则表达式的相关用法,但是一旦正则写的有问题,可能得到的就不是我们想要的结果了,而且对于一个网页来说,都有一定的特殊的结构和层级关系,而且很多标签都有id或 ...
- NCEP数据资料获取 地面抬升指数
先放上数据地址:https://www.esrl.noaa.gov/psd/data/gridded/data.ncep.reanalysis.surface.html 美国国家环境预报中心(NCEP ...
- 自定义view的drawRoundRect模拟进度条
主要方法发介绍 1:drawRoundRect参数介绍 drawRoundRect(l,t,r,b,rx,ry,paint)里面的参数可以有两种: 1:前四个参数(l,t,r,,b)分别是矩形左边距离 ...
- 手把手教你如何制作和使用lib和dll
本文的内容经过本人亲自调试,确保可用,实用,测试环境为win10+vs2015+C++ 目录 静态库 什么是静态库? 怎么创建 如何使用 静态库的第一种使用方法 静态库的第二种使用方法 动态链接库 动 ...
- 国产化即时通信系统开发 -- 实现GGTalk的登录界面(Linux、Ubuntu、UOS、中标麒麟)
距离2013年开源GGTalk以来,7年已经过去了,GGTalk现在有了完整的PC版.安卓版.iOS版(即将发布),以及Xamarin版本. 然而,时代一直在变化,在今天,有个趋势越来越明显,那就是政 ...