Android Flutter compilation

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

insert image description here

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)
insert image description here
There are two ways:
Method 1: Dart Command Line App
Method 2: Dart Remote Debug

Method 1: Dart Command Line App

insert image description here
insert image description here
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

insert image description here

insert image description here

insert image description here
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
insert image description here

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
insert image description here

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

Guess you like

Origin blog.csdn.net/weixin_41548050/article/details/128657671