Flutter源碼剖析(一):源碼獲取與構建

2021-01-12 V大師在一號線
概述

本文介紹了Flutter源碼的獲取與構建,後面會另有文章介紹Flutter源碼的版本管理、開發環境搭建等主題。

準備工作

Flutter源碼分為兩個部分:

flutter/flutter[1]是框架層,為開發者提供各種接口,主要是dart代碼。flutter/engine[2]是引擎層,負責Flutter的渲染以及宿主的交互。

相關依賴的安裝可參考官方文檔:Setting up the Engine development environment · flutter/flutter Wiki[3]。以我的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 sdk

截止到 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[4]有詳細介紹,在此不做贅述,這裡我構建的是一個未優化、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源碼編譯環境[5]Flutter Engine與SDK的定製化與編譯[7]Setting up the Engine development environment · flutter/flutter Wiki[8]Compiling the engine · flutter/flutter Wiki[9]The flutter tool · flutter/flutter Wiki[10]Using depot_tools - The Chromium Projects[11]Working with Release Branches - The Chromium Projects[12]CIPD for chromium dependencies[13]Ninja, a small build system with a focus on speed[14]

更多相關內容可訪問我的博客:http://vimerzhao.top/[16]

關注我的公眾號:V大師在一號線

參考資料[1]

flutter/flutter: https://github.com/flutter/flutter

[2]

flutter/engine: https://github.com/flutter/engine

[3]

Setting up the Engine development environment · flutter/flutter Wiki: https://github.com/flutter/flutter/wiki/Setting-up-the-Engine-development-environment

[4]

Compiling the engine · flutter/flutter Wiki: https://github.com/flutter/flutter/wiki/Compiling-the-engine

[5]

搭建Flutter Engine源碼編譯環境: http://gityuan.com/2019/08/03/flutter_engine_setup/

[6]

Flutter Engine 編譯指北: https://fucknmb.com/2019/02/26/Flutter-Engine-%E7%BC%96%E8%AF%91%E6%8C%87%E5%8C%97/

[7]

Flutter Engine與SDK的定製化與編譯: http://zhengxiaoyong.com/2019/03/16/Flutter-Engine%E4%B8%8ESDK%E7%9A%84%E5%AE%9A%E5%88%B6%E5%8C%96%E4%B8%8E%E7%BC%96%E8%AF%91/

[8]

Setting up the Engine development environment · flutter/flutter Wiki: https://github.com/flutter/flutter/wiki/Setting-up-the-Engine-development-environment

[9]

Compiling the engine · flutter/flutter Wiki: https://github.com/flutter/flutter/wiki/Compiling-the-engine

[10]

The flutter tool · flutter/flutter Wiki: https://github.com/flutter/flutter/wiki/The-flutter-tool

[11]

Using depot_tools - The Chromium Projects: https://www.chromium.org/developers/how-tos/depottools

[12]

Working with Release Branches - The Chromium Projects: https://www.chromium.org/developers/how-tos/get-the-code/working-with-release-branches

[13]

CIPD for chromium dependencies: https://chromium.googlesource.com/chromium/src/+/master/docs/cipd.md

[14]

Ninja, a small build system with a focus on speed: https://ninja-build.org/

[15]

gn - Git at Google: https://gn.googlesource.com/gn/

[16]

http://vimerzhao.top/: http://vimerzhao.top/

相關焦點

  • 大量Flutter項目源碼,快來學習吧
    Flutter水果茶類效果源碼>介紹:Flutter開發一款水果茶app,有首頁展示,購物車,詳情頁源碼下載:https://www.dandroid.cn/?android省市區三級聯動介紹:實現省市區三級聯動源碼下載
  • 今日新增源碼:app升級、設備租賃、仿餓了麼效果源碼
    Flutter app升級源碼gt; _checkAppInfo() { return Future.value(AppUpgradeInfo( title: &39;, contents: [ &39;, &39;, &39;, &39;, &39; ], apkDownloadUrl: &39;, force: false, ));源碼下載
  • Spring源碼高級筆記——Spring IOC源碼深度剖析
    Spring IOC源碼深度剖析 好處:提高培養代碼架構思維、深入理解框架原則定焦原則框架中doXXX,做具體處理的地方)Spring源碼構建下載源碼(github)安裝gradle 5.6.3(類似於maven) ldea 2019.1 Jdk 11.0.5導入
  • 面試經典問題SpringMVC執行流程(源碼解讀剖析)
    Spring 框架提供了構建 Web 應用程式的全功能 MVC 模塊。使用 Spring 可插入的 MVC 架構,從而在使用Spring進行WEB開發時,可以選擇使用Spring的Spring MVC框架或集成其他MVC開發框架。
  • Github一夜爆火的SSM源碼剖析手冊也太香了吧
    我們學習的各種設計模式,最終都需要在源碼中進行落地。當然,我們也需要從優秀的源碼中挖掘設計模式及設計模式的應用場景,學習其中的設計藝術。所以,學習源碼已經是大勢所趨!如何高效閱讀源碼?面對複雜的類庫繼承關係、純英文的源碼及注釋,很多工程師在學習時遇到重重障礙,就單單一個Spring源碼都很難打個通關了,更別說SSM了!
  • HarmonyOS源碼獲取大全
    代碼倉庫地址:https://openharmony.gitee.com源碼獲取概述本文檔將介紹如何獲取OpenHarmony源碼並說明OpenHarmony的源碼目錄結構。獲取方式4:從代碼倉庫獲取。通過repo或git工具從代碼倉庫中下載。獲取方式1:從鏡像站點獲取為了獲得更好的下載性能,您可以選擇從以下站點的鏡像庫獲取源碼或者對應的解決方案。
  • muduo源碼剖析學習總結
    muduo源碼剖析學習總結一、簡介muduo 是一個基於 Reactor 模式的現代 C++ 網絡庫,它採用非阻塞 IO 模型,基於事件驅動和回調,原生支持多核多線程,適合編寫 Linux 服務端多線程網絡應用程式二、源碼我一直覺得看源碼得有頭,「頭」的意思是從一個案例處理,去揭開她的面紗;我們從muduo庫的一個使用案例中出發,一步一步來讀取源碼:案例:muduo_test.cpp
  • 網際網路輕量級SSM框架揭秘:Spring、Spring MVC、MyBatis源碼剖析
    本書Spring源碼剖析篇基於Spring4.3.2版本,剖析了Spring 上下文、Spring AOP和Spring事務的實現,並通過實例展示了框架陷阱的隱蔽性及學習框架原理的必要性。Spring MVC源碼剖析篇基於SpringMVC3.0版本,這個版本比較簡單、核心清晰,便於讀者理解透徹,這裡主要講解其中的設計模式及可插拔的設計思路。
  • 阿里新產Spring源碼高級筆記,原來看懂源碼如此簡單
    說實話我讀Spring源碼一剛開始為了面試,後來為了解決工作中的問題,再後來就是個人喜好了。說的好聽點是有匠人精神;說的委婉點是好奇(底層是怎麼實現的);說的不自信點是對黑盒的東西我用的沒底,怕用錯;說的簡單直白點是提升自我價值,為了更高的薪資待遇(這裡對真正的技術迷說聲抱歉)。
  • ArrayList源碼剖析與代碼實測
    ArrayList源碼剖析與代碼實測(基於OpenJdk14)目錄ArrayList源碼剖析與代碼實測(基於OpenJdk14) 繼承關係從構造函數開始從add方法深入 / 數組的擴容其他的刪查改方法modCount與fail-fast機制總結參考寫本篇博客的目的在於讓自己能夠更加了解Java的容器與實現,能夠掌握原始碼的一些實現與思想
  • 如何優雅地本地化構建Mybatis源碼?
    一.環境準備不耽誤各位想提升技術的熱血沸騰的心情,不想囉嗦半天雞湯廢話,直接進入正題。要想構建源碼,大家都知道第一步幹什麼?github走起。源碼構建上面環境準備,大家會存在一個疑問,構建Mybatis源碼為什麼要下載parent項目呢?答疑:clone下載mybatis源碼後,可以嘗試一下使用mvn clear install構建一下項目,毫無疑問肯定會報錯。因為它依賴parent項目。
  • Redis源碼剖析之SDS
    Redis中sds相關的源碼都在 和中(連結可以直接跳轉到我中文注釋版redis源碼),其中sds.h中定義了所有SDS的api,當然也實現了部分幾個api,比如sds長度、sds剩餘可用空間……,不急著看代碼,我們先看下sds的數據結構,看完後為什麼代碼那麼寫你就一目了然。
  • Flutter 自動化測試 -詳解
    作為 Flutter 開發,FlutterDriver 是足夠幫助他們進行測試的,而作為自動化測試工程師最大的困難是對 dart 語言不了解,不知道如何在 FlutterDriver 驅動下用 Dart 語言編寫 TestCase,所以需要一款更加簡單的、不需要學習 Dart 語言的工具來幫助我們去實現自動化測試,而 Appium Flutter Driver 滿足這一點。
  • 第一次看到如此詳細的Spring源碼筆記,不愧是源碼No.1
    有一說一Spring算是Java程式設計師必備的技能,市面上99%的網際網路公司都在使用Spring框架,可以說學Java就是在學Spring,特別是在前三年,一定要把Spirng的基礎知識給吃透了,然後再有深度的去學習,學習Spring的源碼。
  • 阿里P9都窺視已久的「Java並發實現原理:JDK源碼剖析」
    本書基於JDK 7和JDK 8,對整個Concurrent包進行全面的源碼剖析。JDK 8中大部分並發功能的實現和JDK 7一樣,但新增了一些額外特性。例如CompletableFuture、ConcurrentHashMap的新實現、StampedLock、LongAdder等。
  • 美團大牛手擼並發原理筆記,由淺入深剖析JDK源碼
    相信很多人對於Concurrent並發包都是一知半解,更別說Concurrent包源碼了。(大牛另當別論)可以說要是Concurrent包與其源碼有一定的了解的話是完全可以避免重複造輪子,也能避免因為使用不當而掉到「坑」裡,更不會說停留於一個「似是而非」的階段。那麼問題來了,如何學?
  • 騰訊首推Netty成長筆記:(原理+應用+源碼+調優全都有)
    Netty普通開發人員在工作中一般很少接觸Netty,只有在閱讀一 些分布式框架底層源碼時,才會發現底層通信模塊大部分是Netty,現代網際網路架構,Netty這個優秀的網絡通信框架其實在分布式系統的構建中是起到了舉足輕重的作用。
  • 基於Netty構建高可用分布式系統:文檔+源碼+落地項目
    (文末會介紹一個基於Netty構建的遊戲項目)大數據領域建議大家在學習之前,先理解透整個框架原理結構,運行過程,可以少走很多彎路。中級篇 Netty編解碼開發指南第6章 編解碼技術第7章 Java序列化第8章 Google Protobuf編解碼第9章 JBoss Marshalling編解碼高級篇 Netty多協議開發和應用第10章 HTTP協議開發應用第11章 WebSocket協議開發第12章 UDP協議開發第13章 文件傳輸第14章 私有協議棧開發源碼分析篇
  • Python源碼剖析,豆瓣評分8.8
    一、本書的主要特點: 1、 一本深入剖析Python具體實現的著作 2、 內容新鮮,採用的Python語言版本 3、 大量的圖表形象地展示本書以CPython為研究對象,在C代碼一級,深入細緻地剖析了Python的實現。書中不僅包括了對大量Python內置對象的剖析,更將大量的篇幅用於對Python虛擬機及Python特性的剖析。
  • 技術分享——一路踩坑構建Dubbo源碼
    源碼環境隨著目前對技術棧的求知慾,也開始入手Dubbo源碼啦!!!構建源碼第一步:必備開發環境:Java 1.5 以上的版本;maven 2.2.1 或者以上的版本;官網下載原始碼官網構建文檔學習一下;