概述
本文介紹了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大師在一號線