The author
๐ Author: Yangguang
The article framework
- Flutter create what is flutter create?
- What is flutter Build secretly doing behind his back?
- Flutter Assemble is important
- flutter run
- Overall project structure analysis
- Flutter Windows Desktop Run view
- Flutter Windows Desktop startup process
- Multithreaded model of flutter
- The Dart VM is introduced
preface
Before starting this article, it is necessary to give a brief introduction to the whole framework of Flutter so that those who are not familiar with Flutter can read the rest of the article more smoothly.
Diagram of Flutter (image from Flutter website)
The diagram above shows the layered design of the frame of the Flutter, from bottom to top, corresponding to each other
- The Embedder layer that Flutter contains on each platform is a platform-specific Embedder layer that connects to the operating system, enabling Flutter to use its operating system capabilities to access services such as surface rendering, accessibility and input, and to manage event loop queues. And by embedding layers that allow the upper layer to filter out operating system differences, flutter can be preconditioned to be cross-platform. The embedded layer is implemented in C++ on Windows and Linux, C++ and JAVA on Android, and Object-C and Object-C++ on macOS and ios. If The current embed layer of Flutter does not support your operating system platform, such as Cloud, you can even write a cloud embed layer to make Flutter support more platforms. Of course, just as an example, the Skia support does not support cloud nor is it clear.
- The Engine layer, the most important layer of Flutter, is written in C++ and provides the underlying implementation of the core API of Flutter. Includes graphics (via Skia), text layout, file and network IO, accessibility support, plug-in architecture, and toolchains for the Dart runtime and build environments. The engine wraps the underlying C++ code as Dart code, which is exposed to the Flutter framework layer via Dart: UI.
- The Flutter framework layer is a user-oriented layer that provides modern responsive frameworks written in the Dart language. It includes a rich set of platforms, layouts, and base libraries made up of a series of layers.
1. Run the Flutter Create Application command
Introduction to the create command
A project cannot be created without touching the flutter. The flutter create command supports the generation of project templates for a specific platform or type, as shown in the following command
Create a appliation flutter create myApplication. Create application flutter create D:\\MyDir\ myApplication Create a plugin for flutter create --template=plugin myplugin // View help for flutter create-hCopy the code
Tempalte options
The value of the template option determines the project template that will be created by the flutter create command
[app] (default) Generate a Flutter application. [module] Generate a project to add a Flutter module to an existing Android or iOS application. [package] Generate a shareable Flutter project containing modular Dart code. [plugin] Generate a shareable Flutter project containing an API in Dart code with a platform-specific implementation for Android, for iOS code, or for both. [skeleton] Generate a List View / Detail View Flutter application that follows community best practices.Copy the code
Platform options
Flutter supports create ios, Android, Windows, Linux, MAC, Windows, and Web projects. If the platform option is not specified, all systems will be created.
flutter create --platform=windows D:\Code\flutter-code\myapplication
Copy the code
Flutter Windows project initial structure
The Windows directory
Focus on the Windows directory, as shown above, which is a C++ project that uses CMake to build system management. Seeing that it is a CMake project, we tried to generate a visual studio solution directly using CMake without the help of flutter build.
Generate_config. cmake was missing. After looking carefully at the Windows template generated by Flutter, we found that many files were missing, such as internal reference flutter_windows.h, linked dynamic library, etc. For now the source of the flutter build command may answer my question.
2. Build the mode environment of Flutter upper framework source code
The command line tools for Flutter are provided by the superstructure of Flutter, written in Dart. In order to analyze the subsequent commands that Flutter provides, it is necessary to build a modal environment.
By default, you have already installed Flutter yourself before setting up a Flutter environment. For convenience, use the source mode directly on the installed Flutter.
Found the Flutter installation directory
where flutter
Copy the code
Find the source path and use VsCode to open it
VS Code modality environment setup
Open the VSCode launch.json file and search globally for Packages \\flutter_tools (the source of the flutter command is in this project).
The BUILD_ROOT configuration is supported
Dart: run (1151) Context. run The first line of the function
return context.run<void>(
name: 'command',
overrides: <Type, Generator>{FlutterCommand: () => this},
body: () async {
// The following four lines are the code to be added
final Map<String.String> env = Platform.environment;
if (env.containsKey("BUILD_ROOT")) {
globals.fs.currentDirectory = env["BUILD_ROOT"]; }/ /...},)Copy the code
You can also modify the CWD configuration of vscode’s current working directory to do this.
Launch. The json configuration
{
"name": "flutter_tools"."cwd": "packages\\flutter_tools"."request": "launch"."type": "dart"."program": "lib\\executable.dart"."args": [
"build",]."flutterMode": "debug"."env": {
"FLUTTER_ROOT": Your Flutter root directory."BUILD_ROOT": "Directory of projects you need to build"}}Copy the code
You only need to modify the args parameter to perform other command modulations.
3. Flutter Build command
When did the missing files in the cmake project complete? The flutter build command does the following things via the flutter build source mode.
- in
windows\flutter\ephemeral
Create one in the directorygenerated_config.cmake
Which records some of the environment variables of flutter and the build project - Create a new one
.plugin_symlinks
file - Update the CMake file
- Run the cmake config command to configure the C++ project
- Execute the cmake build command to build the C++ project
- Run the cmake install command
The above steps did not solve all my questions. I only found the generation of generated_config.cmake, such as when the flutter engine dynamic library was copied to the runtime directory, and when the incomplete C++ project dependencies were copied. The trick now seems to be to find cmake files.
CMake User-defined command
file: windows/flutter/CMakeLists.txt
add_custom_command(
OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS}
${CPP_WRAPPER_SOURCES_CORE} ${CPP_WRAPPER_SOURCES_PLUGIN}
${CPP_WRAPPER_SOURCES_APP}
${PHONY_OUTPUT}
COMMAND ${CMAKE_COMMAND} -E env
${FLUTTER_TOOL_ENVIRONMENT}
"${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat"
windows-x64 $<CONFIG>
VERBATIM
)
Copy the code
Explanation: ${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat. OUTPUT is the OUTPUT of the CMake build. COMMAND ${CMAKE_COMMAND} -e env ${FLUTTER_TOOL_ENVIROMENT} ${FLUTTER_TOOL_ENVIROMENT} is defined as follows. These environment variables are passed to tool_backend.bat.
file: windows\flutter\ephermeral\generated_cofig.cmake
# Generated code do not commit.
file(TO_CMAKE_PATH "C: \ \ Users \ \ Administrator \ \ Documents \ \ flutter_windows_2 5.3 stable \ \ flutter." " FLUTTER_ROOT)
file(TO_CMAKE_PATH "D:\\Code\\flutter-code\\myapplication" PROJECT_DIR)
# Environment variables to pass to tool_backend.sh
list(APPEND FLUTTER_TOOL_ENVIRONMENT
"FLUTTER_ROOT = C: \ \ Users \ \ Administrator \ \ Documents \ \ flutter_windows_2 5.3 stable \ \ flutter." "
"PROJECT_DIR=D:\\Code\\flutter-code\\myapplication"
"FLUTTER_ROOT = C: \ \ Users \ \ Administrator \ \ Documents \ \ flutter_windows_2 5.3 stable \ \ flutter." "
"FLUTTER_EPHEMERAL_DIR=D:\\Code\\flutter-code\\myapplication\\windows\\flutter\\ephemeral"
"PROJECT_DIR=D:\\Code\\flutter-code\\myapplication"
"FLUTTER_TARGET=D:\\Code\\flutter-code\\myapplication\\lib\\main.dart"
"DART_DEFINES=RkxVVFRFUl9XRUJfQVVUT19ERVRFQ1Q9dHJ1ZQ=="
"DART_OBFUSCATION=false"
"TRACK_WIDGET_CREATION=true"
"TREE_SHAKE_ICONS=false"
"PACKAGE_CONFIG=D:\\Code\\flutter-code\\myapplication\\.dart_tool\\package_config.json"
)
Copy the code
tool_backend.bat
file: FLUTTER_ROOT\packages\fluttertools\bin\tool_backend.bat
Bat executes the tool_backend.dart code. The tool_backend.dart code then runs the flutter Assemble command.
cmake install
install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}"
COMPONENT Runtime)
install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
COMPONENT Runtime)
install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}"
DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime)
message("AOT_LIBRARY : ${AOT_LIBRARY}")
# Install the AOT library on non-Debug builds only.
install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}"CONFIGURATIONS Profile; Release COMPONENT Runtime)Copy the code
The cmake install command is executed after the cmake build is complete and copies directories such as AOT build artifacts, resource files, and executable files.
4. Flutter Assemble orders
We know that cmake executes the flutter Assemble command during build. Now look at what the flutter Assembble does.
Flutter assemble launch.json configuration is as follows:
{
"name": "flutter_tools"."cwd": "packages\\flutter_tools"."request": "launch"."type": "dart"."program": "lib\\executable.dart"."args": [
"assemble"."--no-version-check"."--output=build"."-dTargetPlatform=windows-x64"."-dTrackWidgetCreation=true"."-dBuildMode=release"."-dTargetFile=lib\\main.dart"."-dTreeShakeIcons=true"."-dDartObfuscation=false"."release_bundle_windows_assets"]."flutterMode": "debug"."env": {
"FLUTTER_ROOT": Your Flutter root directory."BUILD_ROOT": "Your project root directory"}}Copy the code
The whole operation process of flutter Assemlbe
UnpackWindows
file: windows.dart : UnpackWindows
UnpackWindows will copy the files (.h,.cc,.dll) required by the previous CMkae build to the specified directory. The specific files can be viewed in the unpack_windows.stamp file in your application project root directory. For example, Will FLUTTER_ROOT/bin/cache/artifacts/engine/Windows – x64 – release/flutter_windows. DLL copied to project_dir/Windows/flutter/ephemera L.
The Dart to compile
file: common.dart: KernelSnapshot file: compile.dart: KernelCompiler file: common.dart: AOTElfDart
KernalSnapshot and AOTElfBase are responsible for compiling the DART code. Dart compilation takes a different form depending on the build mode, and AOTElfBase is skipped in DebBug mode.
Dart Release and Debug compilation
- Dart is compiled In Debbug mode In JIT (Just In Time) mode to produce an intermediate language (app.dill) that enables efficient hot overloading
- Dart is compiled in Ahead Of Time (AOT) mode under the Release model to generate machine code (app.so) for the corresponding platform, which improves execution efficiency. However, JIT compilation is also required for AOT mode compilation
Windows build product
The Release of Flutter Windows is divided into two parts. The first part is generated by dart code, which uses the Frontend_server compiler to convert dart code into an AST abstract syntax tree, and generates the Dart kernel product of app.dill. After a series of optimizations for the intermediate code (app.dill) using gen_snapshot in release mode, different binaries are generated according to different platforms. Linux ELF binaries are used for Windows, Linux and Android binaries. The second part is generated by the flutter engine code, which is usually already compiled, and finally compiled by the C++ project template created by flutter create to generate an executable binary.
The compiled product of Dart can be viewed in the./dart_tool/flutter_build directory of the current project root
WindowsAotBundle & BundleWindowsAssests
file: windows.dart: WindowsAotBundle file: windows.dart: BundleWindowsAssets
WindowsAotBundle and BundleWindowsAssets simply copy previously generated artifacts, such as Dart compiled app.dill (which will be renamed kenerl_blob.bin), app.so, assets, etc.
Assets can be viewed in build/flutter_assets in the current project root directory (kenerl_blob.bin is also in this directory) app.so can be viewed in Build/Windows in the current project root directory
A small summary
- Flutter create creates a flutter project template that contains an incomplete C++ project
- The flutter build command first generates the cmake_generated_. Cmake file so that its cmake config can be executed normally, and then builds the C++ project by executing the cmake build command. So the tool_backend.bat script is invoked using the cmkae command before cmake compiles the project
- The tool_backend.bat script executes the tool_backend.dart code. The tool_backend.dart code executes the flutter assemble command
- The flutter assemble command first generates the C++ files and libraries required for the cmake build, then compiles the Dart code and copies the build product to the appropriate location
- After executing tool_backend.bat, C++ code is compiled to generate application.exe
- The flutter build uses the cmake install command to copy the resources that the application. Exe runtime depends on to the runtime directory
5. Flutter Run
After the execution of the flutter build can be in the root directory of the current project build/Windows/runner/Release directory to see the final flutter generated by the product of the project, this directory can be packaged directly, but the flutter of c + + compilation mode is the MD of the project, So the final package also needs to copy the runtime environment required by Windows C++ into the Release directory.
Flutter release directory
DLL โ โ flutter_windows. Myapplication. Exe โ โ โdataโ โโ โโ MaterialIcons โ โโ โโ MaterialIcons โ โโ MaterialIcons โ โโ MaterialIcons โ โโ MaterialIcons โ โโ MaterialIcons โ โโ MaterialIcons โ โโ MaterialIcons โ โโ MaterialIcons โ โโ MaterialIcons-Regularโ โ โ garbage โ โ honey sci-imp 1.txt โ โ โ garbage sci-imp 1.txtCopy the code
- App. so is a Dart AOT product
- Icudtl. dat is an internationalization file
- There are some fonts, ICONS and so on in Flutter_assets
Build a Flutter Windows Application (C++ project) environment
Because the operation view and startup process of Flutter Windows Application need to be analyzed later, the source mode cannot be avoided. Here is a simple way to build the environment. Of course, if you want a detailed and convenient analysis of the Source of the Flutter Engine, you can also recompile the Flutter engine yourself.
1. Download the flutter Engine source code
git clone https://github.com/flutter/engine.git
Copy the code
Download the Flutter source code directly. Of course, if you also want to perform adjustments in the SKia or DART VM code, You need to download Google’s depot_tools and perform Glient Sync to update the third-party library code.
2. Switch to the engine branch corresponding to the specified local FLUTTER version
# Check the engine used by local flutter
flutter --version
# Change to Revision
git checkout your_revision
Copy the code
3. Add the PDB symbol file
In vs tools – > options – > mode – > symbol add your_project_path/Windows/flutter/ephemeral path.
4. Run the program and make sure the symbol is loaded (myApplication.exe)
You can then open the Flutter Engine source code in Visual Studio to tune.
Flutter Windows Application run view
Flutter start process
View with Flutter Windows Application running view
- Flutter Applicationn consists of a FlutterWindow which contains a Win32 main window. In the main function, a FlutterWindow is created and a Win32 main window is created. FlutterWindow listens for win32 window creation events and initializes the FlutterViewController object in the Windows window creation callback
- The FlutterViewController mainly displays engine rendering results to the corresponding FlutterView. It creates FlutterView and FlutterEngine. FlutterView and FlutterEngine are embedded through the Embedder API. That is, the C API provided by Flutter_windows. h calls the Flutter embedding layer and tells the embedding layer to create FlutterWindowsView and FlutterWindowsEngine. FlutterWindowsView, the real object of FlutterView, is actually a Windows window, which was set as a child window of the main window in the main window creation event of Win32
- When FlutterViewController is created, it also creates threadHosts and shells through the embedded layer engine. The Shell is very important, it is the central nerve of flutter. Responsible for engine creation, Root Isolate creation, DartVM startup, PlatformView creation, etc. After Shell creation, The start Shell will trigger the start of the Flutter engine. When the engine starts, DartVM will be created and then the Dart _runMainZoned function will be called. Dart Main will be called after _runMainZeoned
Multithreaded model of Flutter
Create a ThreadHost in the embedded layer engine. The ThreadHost creates four threads: Platform Thread (this Thread is not created by the flutter but directly taken over by the main Thread), UI Thread, Rasterizer Thread, AND IO Thread. And these four threads maintain four taskrunners. TaskRunner, TaskRunner, TaskRunner, the principle is similar to thread communication in Chromium, which has an internal MessageLoop to loop and wait and process tasks in the message queue. Each TaskRunner has its own responsibilities, which are as follows:
- Platfom TaskRunner: Runs on the main thread, which handles listening for user input times, keyboard and mouse events, and handles external and engine layer communications
- UI TaskRunner: Runs on the UI thread and is responsible for rendering the engine
- Rasterizer TaskRunner: Mainly responsible for GPU-related work
- IO TaskRunner: I/O is mainly responsible for performing time-consuming operations, such as reading local images, decompressing them into a format that can be processed by the CPU, and Posting them to the GPU TaskRunner
The Dart vm
The Dart virtual machine and Root Isolate are created with the start of the whole Flutter engine.
Dart is a single-threaded language. All code is executed sequentially. Dart provides a mechanism called Isolate, which enables Dart to support concurrent programming. But the form and process are particularly similar.
DartVM also has its own Isolate, which is completely managed by the VMS themselves and cannot be directly accessed by the Flutter engine. Dart ui-related operations are performed by Root Isolate using Dart C++ or by sending message notifications to UI TaskRunner, which can interact with Flutter engine modules.
- The heap inside the Isolate’s internal implementation is the MEMORY store managed by the GC that runs all objects allocated by the code in the Isolate
- The Isolate heap can reference objects in the VM Isolate heap, but the VM Isolate cannot reference the Isolate heap
- The Isolate is completely isolated from the Isolate and cannot reference each other
- Each Isolate has a Mutator Thread that executes the DART code and a Helper Thread that handles tasks within the VIRTUAL machine (such as GC and JIT). The Isolate can have multiple virtual machines, but like processes, they do not share memory with each other. No direct access, only communication through Dart’s unique Port.
Refer to the link
Flutter architectural overview | Flutter
The Engine architecture ยท flutter/flutter Wiki ยท GitHub
Wiki ยท GitHub The flutter tool ยท flutter/flutter Wiki ยท GitHub
Evolution and Flutter cross-platform architecture begins – Gityuan blog | Yuan Huihui technology blog