Article directory
- Environmental preparation
- Flutter build apk process combing
- Summarize
- Flutter tools (dart) source code debugging
-
- Method 1: Dart Command Line App
- Method 2: Dart Remote Debug
-
- Use the vm option just provided to start the dart vm to perform the flutter compilation task
- reference
Environmental preparation
flutter_windows_3.3.10-stable(flutter sdk)
windows 10
Flutter build apk process combing
Note:
The following {flutter sdk path} indicates the flutter sdk installation directory
1. The flutter here is {flutter sdk path}\bin\flutter.bat batch program
The essence of the batch program is to run the dart program
"%dart%" --disable-dart-dev --packages="%flutter_tools_dir%\.dart_tool\package_config.json" %FLUTTER_TOOL_ARGS% "%snapshot_path%" %* & exit /B !ERRORLEVEL!
{flutter sdk path}\bin\cache\dart-sdk\bin\dart.exe {flutter sdk path}\bin\cache\flutter_tools.snapshot, and the \flutter_tools.snapshot here is essentially an intermediate product of dart compilation? ? ? ? The entry function is the main function in {flutter sdk path}\packages\flutter_tools\bin\flutter_tools.dart
2. Track the dart file step by step to
{flutter sdk path}\packages\flutter_tools\lib\src\android\gradle.dart
Future<void> buildGradleApp({
required FlutterProject project,
required AndroidBuildInfo androidBuildInfo,
required String target,
required bool isBuildingBundle,
required List<GradleHandledError> localGradleErrors,
bool validateDeferredComponents = true,
bool deferredComponentsEnabled = false,
int retry = 0,
@visibleForTesting int? maxRetries,
}) async {
。。。
final String assembleTask = isBuildingBundle
? getBundleTaskFor(buildInfo)
: getAssembleTaskFor(buildInfo);
。。。
。。。
final List<String> command = <String>[
_gradleUtils.getExecutable(project),//这里windows环境下就是gradlew.bat批处理程序
];
if (_logger.isVerbose) {
command.add('--full-stacktrace');
command.add('--info');
command.add('-Pverbose=true');
} else {
command.add('-q');
}
。。。
。。。
command.add(assembleTask);
。。。
}
{flutter sdk path}\packages\flutter_tools\lib\src\android\gradle_utils.dart
/// Gets the Gradle executable path and prepares the Gradle project.
/// This is the `gradlew` or `gradlew.bat` script in the `android/` directory.
String getExecutable(FlutterProject project) {
final Directory androidDir = project.android.hostAppGradleRoot;
injectGradleWrapperIfNeeded(androidDir);
final File gradle = androidDir.childFile(
_platform.isWindows ? 'gradlew.bat' : 'gradlew',
);
if (gradle.existsSync()) {
_logger.printTrace('Using gradle from ${gradle.absolute.path}.');
// If the Gradle executable doesn't have execute permission,
// then attempt to set it.
_operatingSystemUtils.makeExecutable(gradle);
return gradle.absolute.path;
}
throwToolExit(
'Unable to locate gradlew script. Please check that ${gradle.path} '
'exists or that ${gradle.dirname} can be read.'
);
}
It can be seen that gradlew.bat is actually executed... assemblexxx
where assemblexxx is the compilation task defined by android gradle
3. Come to the flutter custom gradle plugin to find clues
Define the function addFlutterTasks in {flutter sdk path}\packages\flutter_tools\gradle\flutter.gradle,
and create a custom gradle task for FlutterTask. Specifically, how this task is related to the android gradle compilation task needs to be studied? ? ?
private void addFlutterTasks(Project project) {
。。。
FlutterTask compileTask = project.tasks.create(name: taskName, type: FlutterTask) {
flutterRoot this.flutterRoot
flutterExecutable this.flutterExecutable
buildMode variantBuildMode
localEngine this.localEngine
localEngineSrcPath this.localEngineSrcPath
targetPath getFlutterTarget()
verbose isVerbose()
fastStart isFastStart()
fileSystemRoots fileSystemRootsValue
fileSystemScheme fileSystemSchemeValue
trackWidgetCreation trackWidgetCreationValue
targetPlatformValues = targetPlatforms
sourceDir getFlutterSourceDirectory()
intermediateDir project.file("${project.buildDir}/${AndroidProject.FD_INTERMEDIATES}/flutter/${variant.name}/")
extraFrontEndOptions extraFrontEndOptionsValue
extraGenSnapshotOptions extraGenSnapshotOptionsValue
splitDebugInfo splitDebugInfoValue
treeShakeIcons treeShakeIconsOptionsValue
dartObfuscation dartObfuscationValue
dartDefines dartDefinesValue
bundleSkSLPath bundleSkSLPathValue
performanceMeasurementFile performanceMeasurementFileValue
codeSizeDirectory codeSizeDirectoryValue
deferredComponents deferredComponentsValue
validateDeferredComponents validateDeferredComponentsValue
doLast {
project.exec {
if (Os.isFamily(Os.FAMILY_WINDOWS)) {
commandLine('cmd', '/c', "attrib -r ${assetsDirectory}/* /s")
} else {
commandLine('chmod', '-R', 'u+w', assetsDirectory)
}
}
}
}
。。。
}
FlutterTask inherits from BaseFlutterTask, BaseFlutterTask has function buildBundle()
void buildBundle() {
if (!sourceDir.isDirectory()) {
throw new GradleException("Invalid Flutter source directory: ${sourceDir}")
}
intermediateDir.mkdirs()
// Compute the rule name for flutter assemble. To speed up builds that contain
// multiple ABIs, the target name is used to communicate which ones are required
// rather than the TargetPlatform. This allows multiple builds to share the same
// cache.
String[] ruleNames;
if (buildMode == "debug") {
ruleNames = ["debug_android_application"]
} else if (deferredComponents) {
ruleNames = targetPlatformValues.collect { "android_aot_deferred_components_bundle_${buildMode}_$it" }
} else {
ruleNames = targetPlatformValues.collect { "android_aot_bundle_${buildMode}_$it" }
}
project.exec {
logging.captureStandardError LogLevel.ERROR
executable flutterExecutable.absolutePath
workingDir sourceDir
if (localEngine != null) {
args "--local-engine", localEngine
args "--local-engine-src-path", localEngineSrcPath
}
if (verbose) {
args "--verbose"
} else {
args "--quiet"
}
args "assemble"
args "--no-version-check"
args "--depfile", "${intermediateDir}/flutter_build.d"
args "--output", "${intermediateDir}"
if (performanceMeasurementFile != null) {
args "--performance-measurement-file=${performanceMeasurementFile}"
}
if (!fastStart || buildMode != "debug") {
args "-dTargetFile=${targetPath}"
} else {
args "-dTargetFile=${Paths.get(flutterRoot.absolutePath, "examples", "splash", "lib", "main.dart")}"
}
args "-dTargetPlatform=android"
args "-dBuildMode=${buildMode}"
if (trackWidgetCreation != null) {
args "-dTrackWidgetCreation=${trackWidgetCreation}"
}
if (splitDebugInfo != null) {
args "-dSplitDebugInfo=${splitDebugInfo}"
}
if (treeShakeIcons == true) {
args "-dTreeShakeIcons=true"
}
if (dartObfuscation == true) {
args "-dDartObfuscation=true"
}
if (dartDefines != null) {
args "--DartDefines=${dartDefines}"
}
if (bundleSkSLPath != null) {
args "-dBundleSkSLPath=${bundleSkSLPath}"
}
if (codeSizeDirectory != null) {
args "-dCodeSizeDirectory=${codeSizeDirectory}"
}
if (extraGenSnapshotOptions != null) {
args "--ExtraGenSnapshotOptions=${extraGenSnapshotOptions}"
}
if (extraFrontEndOptions != null) {
args "--ExtraFrontEndOptions=${extraFrontEndOptions}"
}
args ruleNames
}
}
Go back to the flutter.bat script in the flutter sdk to execute flutter assemble
4. Go back to the flutter.bat script in the flutter sdk to execute flutter assemble
At this time, I originally thought that the gradle assemblexxx was executed in a loop, but it was not
because the flutter assemble went to the dart program after execution
{flutter sdk path}\packages\flutter_tools\lib\src\commands\assemble.dart
Need to analyze in detail how to execute the dart program compilation in flutter? How to generate flutter_assets? And what are the functions of the three files kernel_blob.bin, vm_snapshot_data, and isolate_snapshot_data in debug mode and how are they generated in the flutter_assets directory?
Here are two very important files
{flutter sdk path}\bin\cache\artifacts\engine\windows-x64\frontend_server.dart.snapshot
{flutter sdk path}\bin\cache\artifacts\engine\android-arm- release\windows-x64\gen_snapshot.exe
One is the intermediate product of dart compilation, which needs to be used with dart vm and is responsible for generating kernel files?
A pure binary executable that is responsible for generating the aot executable?
而这个frontend_server.dart.snapshot不同于之前的flutter_tool.snapshot,他是存在于engine的Dart代码中的,而不是Flutter SDK中。
engine的代码需要单独下载:https://github.com/flutter/engine
Summarize
Flutter tools (dart) source code debugging
The entire directory of {flutter sdk}\packages\flutter_tools is opened as the root directory of the dart project (if the as does not recognize the project, check whether the project has specified the dart sdk path, file->settings->dart, specify the dart sdk path as {flutter sdk} \bin\cache\dart-sdk and apply)
There are two ways:
Method 1: Dart Command Line App
Method 2: Dart Remote Debug
Method 1: Dart Command Line App
Specify the dart entry file, the command line parameter is build apk, and the working directory selects any flutter project root directory (the dart command will be executed in the specified directory, here is to execute flutter to compile android apk)
Method 2: Dart Remote Debug
Here you can see that two options --enable-vm-service:12345 --pause_isolates_on_start must be specified when the corresponding dart vm is started, of which 12345 is specified at will and will be used later
Use the vm option just provided to start the dart vm to perform the flutter compilation task
1. First, modify the flutter.bat file
exist
“%dart%” --packages=“%flutter_tools_dir%.dart_tool\package_config.json” %FLUTTER_TOOL_ARGS% “%snapshot_path%” %* & “%exit_with_errorlevel%”
Before assigning the variable FLUTTER_TOOL_ARGS
SET FLUTTER_TOOL_ARGS=–enable-vm-service:12345 --pause_isolates_on_start --disable-service-auth-codes %FLUTTER_TOOL_ARGS%
2. Then go directly to the root directory of any flutter project to execute flutter build apk
for example
G:\MyWork\Flutter\Tools\flutter_windows_3.7.3-stable\flutter\bin\flutter.bat --no-color build apk
3. Encountered a problem: Dart Remote Debug cannot assert that it has tracked the flutter_tools.dart source code file
But if it is Dart Command Line App
G:/MyWork/Flutter/Tools/flutter_windows_3.7.3-stable/flutter/bin/cache/dart-sdk/bin/dart.exe --enable-asserts --pause_isolates_on_start --enable-vm-service:63036 G:\MyWork\Flutter\Tools\flutter_windows_3.7.3-stable\flutter\packages\flutter_tools\bin\flutter_tools.dart build apk
Then normally assert to the main function of flutter_tools.dart source code
Compare the commands executed by flutter.bat batch
“G:\MyWork\Flutter\Tools\flutter_windows_3.7.3-stable\flutter\bin\cache\dart-sdk\bin\dart.exe” --packages=“G:\MyWork\Flutter\Tools\flutter_windows_3.7.3-stable\flutter\packages\flutter_tools.dart_tool\package_config.json” --enable-vm-service:12345 --pause_isolates_on_start --disable-service-auth-codes “G:\MyWork\Flutter\Tools\flutter_windows_3.7.3-stable\flutter\bin\cache\flutter_tools.snapshot” --no-color build apk
The comparison found that it may be caused by not specifying the option –enable-asserts when starting dart vm
Modify the dart vm startup option in flutter.bat, add --enable-asserts
The snapshot file does not support assert
Modify the dart vm startup entry in flutter.bat, and replace the snapshot file with the flutter_tools.dart file (effective!!!)
Bundle
SET snapshot_path=%cache_dir%\flutter_tools.snapshot
changed to
SET snapshot_path=%flutter_tools_dir%\bin\flutter_tools.dart
Re-execute step 2 flutter build apk
can now assert to the main function of the flutter_tools.dart file normally
reference
https://developer.aliyun.com/article/761239
https://juejin.cn/post/7093388612078665764
Note: The above two blog posts are using other versions of flutter sdk, so they are a little different from the content shared this time. For example, the flutter sdk version of assemble.dart in the reference blog post does not exist