flutter Android编译打包全过程解析

本篇主要讲解一个flutter工程是如何编译打包成一个apk的。

注意:这里我们是一个空的flutter项目,然后引入了一个webview-flutter的plugin来模拟一个plugin是如何一起打进去的。
flutter版本:2.4.0-5.0.pre.145

settings.gradle

因为最终产物是apk,所以其实总体上走的还是安卓编译,所以我们先来看settings.gradle文件:
在这里插入图片描述
这里我们可以看到,先读取了本地local.properties文件,里面包含了flutter sdk安装目录和android sdk安装目录等。根据flutter sdk安装目录,来到目录下的app_plugin_loader.gradle文件。
在这里插入图片描述
这里我们可以看到针对flutter-plugins-dependencies文件进行json解析,我们可以看下flutter-plugins-dependencies文件里的内容,包括了项目中各个平台引入的包的情况,我们项目中只引入了webview_flutter plugin。
在这里插入图片描述
ok,读取到了以后进行json解析,然后进行include和project对应处理,经过这一步以后settings.gradle就变成了

 include ":webview_flutter"
 project(":webview_flutter").projectDir = new File("xxxxxxx")//上面对应的path

没错,这么看的话其实变成了普通的一个android项目的settings.gradle结构了。

根目录build.gradle

ok打包的话接下来我们来看build.gradle文件,先来看根目录下的build.gradle文件。
在这里插入图片描述
这里我们可以看到指定build产物目录为flutter项目目录的build文件下,以及build下的app目录下。以及首先我们会运行app依赖。ok接下去我们再来看app下的build.gradle文件。

app/build.gradle

在这里插入图片描述
首先读取了loacl.properties文件,读取了flutter sdk相关的参数以后,加载了flutter.gradle文件。我们来看看这个flutter sdk里的flutter.gradle文件具体做了些啥。
在这里插入图片描述
这里我们看到又apply了一个自定义的plugin FlutterPlugin,ok我就来看这个FlutterPlugin都做了些啥。

FlutterPlugin

class FlutterPlugin implements Plugin<Project> {
    //省略部分代码,主要是声明了一些变量和环境参数。

	//具体实现
    @Override
    void apply(Project project) {
        this.project = project

        def rootProject = project.rootProject
        rootProject.tasks.register('generateLockfiles') {
            rootProject.subprojects.each { subproject ->
                def gradlew = (OperatingSystem.current().isWindows()) ?
                    "${rootProject.projectDir}/gradlew.bat" : "${rootProject.projectDir}/gradlew"
                rootProject.exec {
                    workingDir rootProject.projectDir
                    executable gradlew
                    args ":${subproject.name}:dependencies", "--write-locks"
                }
            }
        }

        //1.配置maven地址,如果环境变量里有FLUTTER_STORAGE_BASE_URL就用,没有的话直接用默认的
        String hostedRepository = System.env.FLUTTER_STORAGE_BASE_URL ?: DEFAULT_MAVEN_HOST
        String repository = useLocalEngine()
            ? project.property('local-engine-repo')
            : "$hostedRepository/download.flutter.io"
        rootProject.allprojects {
            repositories {
                maven {
                    url repository
                }
            }
        }

		//2.FlutterExtension类包含了source和target属性,创建扩展配置项
        project.extensions.create("flutter", FlutterExtension)
        //3.添加各种task,之后会详解
        this.addFlutterTasks(project)

        //4.如果构建的时候配置了多个abi参数,那就为每个abi都构建一个自己的apk
        if (shouldSplitPerAbi()) {
            project.android {
                splits {
                    abi {
                        // Enables building multiple APKs per ABI.
                        enable true
                        // Resets the list of ABIs that Gradle should create APKs for to none.
                        reset()
                        // Specifies that we do not want to also generate a universal APK that includes all ABIs.
                        universalApk false
                    }
                }
            }
        }

		//5.编译命令如果有deferred-component-names参数,那就配置到dynamiceFeatures 属性里
        if (project.hasProperty('deferred-component-names')) {
            String[] componentNames = project.property('deferred-component-names').split(',').collect {":${it}"}
            project.android {
                dynamicFeatures = componentNames
            }
        }

		//6.循环添加 d--target-platform参数并添加
        getTargetPlatforms().each { targetArch ->
            String abiValue = PLATFORM_ARCH_MAP[targetArch]
            project.android {
                if (shouldSplitPerAbi()) {
                    splits {
                        abi {
                            include abiValue
                        }
                    }
                }
            }
        }
		//7.获取flutter sdk,没有就报错
        String flutterRootPath = resolveProperty("flutter.sdk", System.env.FLUTTER_ROOT)
        if (flutterRootPath == null) {
            throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file or with a FLUTTER_ROOT environment variable.")
        }
        flutterRoot = project.file(flutterRootPath)
        if (!flutterRoot.isDirectory()) {
            throw new GradleException("flutter.sdk must point to the Flutter SDK directory")
        }
		//8.获取flutter engine版本号,注意,这里如果我们使用的是我们自己本地编译的flutter engine的话,直接取+。flutter engine自己编译之后几篇内容里我们会详解,挺有意思的
        engineVersion = useLocalEngine()
            ? "+" // Match any version since there's only one.
            : "1.0.0-" + Paths.get(flutterRoot.absolutePath, "bin", "internal", "engine.version").toFile().text.trim()

		//9.获取flutter.bat命令脚本
        String flutterExecutableName = Os.isFamily(Os.FAMILY_WINDOWS) ? "flutter.bat" : "flutter"
        flutterExecutable = Paths.get(flutterRoot.absolutePath, "bin", flutterExecutableName).toFile();
		//10..huoqu flutter混淆脚本
        String flutterProguardRules = Paths.get(flutterRoot.absolutePath, "packages", "flutter_tools",
                "gradle", "flutter_proguard_rules.pro")
        //11.新增profile构建类型,也就是我们分析性能的时候用到的profile类型
        project.android.buildTypes {
            // Add profile build type.
            profile {
                initWith debug
                if (it.hasProperty("matchingFallbacks")) {
                    matchingFallbacks = ["debug", "release"]
                }
            }
            //12.目前只有在aot构建多apk的时候才会为false,,主要用添加了一个release构建类型。 
            if (shouldShrinkResources(project)) {
                release {
                    // Enables code shrinking, obfuscation, and optimization for only
                    // your project's release build type.
                    minifyEnabled true
                    // Enables resource shrinking, which is performed by the
                    // Android Gradle plugin.
                    // NOTE: The resource shrinker can't be used for libraries.
                    shrinkResources isBuiltAsApp(project)
                    // Fallback to `android/app/proguard-rules.pro`.
                    // This way, custom Proguard rules can be configured as needed.
                    proguardFiles project.android.getDefaultProguardFile("proguard-android.txt"), flutterProguardRules, "proguard-rules.pro"
                }
            }
        }

		//13.如果使用的是本地编译的flutter engine的话,就要用本地的engine来build
        if (useLocalEngine()) {
            // This is required to pass the local engine to flutter build aot.
            String engineOutPath = project.property('local-engine-out')
            File engineOut = project.file(engineOutPath)
            if (!engineOut.isDirectory()) {
                throw new GradleException('local-engine-out must point to a local engine build')
            }
            localEngine = engineOut.name
            localEngineSrcPath = engineOut.parentFile.parent
        }
        //14.给所有buildtypes添加依赖
        project.android.buildTypes.all this.&addFlutterDependencies
    }

    private static Boolean shouldShrinkResources(Project project) {
        if (project.hasProperty("shrink")) {
            return project.property("shrink").toBoolean()
        }
        return true
    }

    /**
     * 15.给各个buildtypes添加依赖,主要是embedding和libflutter.so
     * 查看addApiDependencies方法我们可以看到其实就是根据buildtypes,用api或者compile取添加依赖,这和我们平时android开发
     * 添加第三方依赖一样。
     */
    void addFlutterDependencies(buildType) {
        String flutterBuildMode = buildModeFor(buildType)
        if (!supportsBuildMode(flutterBuildMode)) {
            return
        }
        // The embedding is set as an API dependency in a Flutter plugin.
        // Therefore, don't make the app project depend on the embedding if there are Flutter
        // plugins.
        // This prevents duplicated classes when using custom build types. That is, a custom build
        // type like profile is used, and the plugin and app projects have API dependencies on the
        // embedding.
        if (!isFlutterAppProject() || getPluginList().size() == 0) {
            addApiDependencies(project, buildType.name,
                    "io.flutter:flutter_embedding_$flutterBuildMode:$engineVersion")
        }
        List<String> platforms = getTargetPlatforms().collect()
        // Debug mode includes x86 and x64, which are commonly used in emulators.
        if (flutterBuildMode == "debug" && !useLocalEngine()) {
            platforms.add("android-x86")
            platforms.add("android-x64")
        }
        platforms.each { platform ->
            String arch = PLATFORM_ARCH_MAP[platform].replace("-", "_")
            // Add the `libflutter.so` dependency.
            addApiDependencies(project, buildType.name,
                    "io.flutter:${arch}_$flutterBuildMode:$engineVersion")
        }
    }

//。。。省略

ok整体过了一遍,我们接下来主要来看addFlutterTasks方法,这里才是整个编译过程最重要的一个地方。

private void addFlutterTasks(Project project) {
        if (project.state.failure) {
            return
        }
        //1.读取各个配置项,如果有,就赋值
        String[] fileSystemRootsValue = null
        if (project.hasProperty('filesystem-roots')) {
            fileSystemRootsValue = project.property('filesystem-roots').split('\\|')
        }
        String fileSystemSchemeValue = null
        if (project.hasProperty('filesystem-scheme')) {
            fileSystemSchemeValue = project.property('filesystem-scheme')
        }
        Boolean trackWidgetCreationValue = true
        if (project.hasProperty('track-widget-creation')) {
            trackWidgetCreationValue = project.property('track-widget-creation').toBoolean()
        }
        String extraFrontEndOptionsValue = null
        if (project.hasProperty('extra-front-end-options')) {
            extraFrontEndOptionsValue = project.property('extra-front-end-options')
        }
        String extraGenSnapshotOptionsValue = null
        if (project.hasProperty('extra-gen-snapshot-options')) {
            extraGenSnapshotOptionsValue = project.property('extra-gen-snapshot-options')
        }
        String splitDebugInfoValue = null
        if (project.hasProperty('split-debug-info')) {
            splitDebugInfoValue = project.property('split-debug-info')
        }
        Boolean dartObfuscationValue = false
        if (project.hasProperty('dart-obfuscation')) {
            dartObfuscationValue = project.property('dart-obfuscation').toBoolean();
        }
        Boolean treeShakeIconsOptionsValue = false
        if (project.hasProperty('tree-shake-icons')) {
            treeShakeIconsOptionsValue = project.property('tree-shake-icons').toBoolean()
        }
        String dartDefinesValue = null
        if (project.hasProperty('dart-defines')) {
            dartDefinesValue = project.property('dart-defines')
        }
        String bundleSkSLPathValue;
        if (project.hasProperty('bundle-sksl-path')) {
            bundleSkSLPathValue = project.property('bundle-sksl-path')
        }
        String performanceMeasurementFileValue;
        if (project.hasProperty('performance-measurement-file')) {
            performanceMeasurementFileValue = project.property('performance-measurement-file')
        }
        String codeSizeDirectoryValue;
        if (project.hasProperty('code-size-directory')) {
            codeSizeDirectoryValue = project.property('code-size-directory')
        }
        Boolean deferredComponentsValue = false
        if (project.hasProperty('deferred-components')) {
            deferredComponentsValue = project.property('deferred-components').toBoolean()
        }
        Boolean validateDeferredComponentsValue = true
        if (project.hasProperty('validate-deferred-components')) {
            validateDeferredComponentsValue = project.property('validate-deferred-components').toBoolean()
        }
        //2.默认返回DEFAULT_PLATFORMS
        def targetPlatforms = getTargetPlatforms()
        
        def addFlutterDeps = { variant ->
            if (shouldSplitPerAbi()) {
            	//3.一个apk多个abi变体不允许具有相同的versioncode,所以这一步就是给每个apk赋值唯一的versioncode。
            	//更多信息可以看https://developer.android.com/studio/build/configure-apk-splits
                variant.outputs.each { output ->
                    def abiVersionCode = ABI_VERSION.get(output.getFilter(OutputFile.ABI))
                    if (abiVersionCode != null) {
                        output.versionCodeOverride =
                            abiVersionCode * 1000 + variant.versionCode
                    }
                }
            }
			//4.获取编译类型,debug,release,profile
            String variantBuildMode = buildModeFor(variant.buildType)
            //5.拼接字符串,生成各自编译类型对应的task名字
            String taskName = toCammelCase(["compile", FLUTTER_BUILD_PREFIX, variant.name])
            //6.给task各种赋值,这里FlutterTask就是一个基础的gradle task,后面会详细描述
            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)
                        }
                    }
                }
            }
            //7.项目构建中间产物
            File libJar = project.file("${project.buildDir}/${AndroidProject.FD_INTERMEDIATES}/flutter/${variant.name}/libs.jar")
            
            //8.创建packLibsFlutterBuildDebug,packLibsFlutterBuildRelease,packLibsFlutterProfile指令,主要用于把build/intermediates/flutter/debug/目录下根据abi生成的app.so转换成libs.jar
            Task packFlutterAppAotTask = project.tasks.create(name: "packLibs${FLUTTER_BUILD_PREFIX}${variant.name.capitalize()}", type: Jar) {
                destinationDir libJar.parentFile
                archiveName libJar.name
                dependsOn compileTask
                targetPlatforms.each { targetPlatform ->
                    String abi = PLATFORM_ARCH_MAP[targetPlatform]
                    from("${compileTask.intermediateDir}/${abi}") {
                        include "*.so"
                        // 9.把app.so转变成lib/<abi>/libapp.so
                        rename { String filename ->
                            return "lib/${abi}/lib${filename}"
                        }
                    }
                }
            }
            //10.把packFlutterAppAotTask生成的产物添加到依赖里去
            addApiDependencies(project, variant.name, project.files {
                packFlutterAppAotTask
            })
            // 11.如果有is-plugin属性的话,我们就编译aar
            boolean isBuildingAar = project.hasProperty('is-plugin')
            // In add to app scenarios, a Gradle project contains a `:flutter` and `:app` project.
            // We know that `:flutter` is used as a subproject when these tasks exists and we aren't building an AAR.
            Task packageAssets = project.tasks.findByPath(":flutter:package${variant.name.capitalize()}Assets")
            Task cleanPackageAssets = project.tasks.findByPath(":flutter:cleanPackage${variant.name.capitalize()}Assets")
            //12.判断是否是FlutterModule依赖
            boolean isUsedAsSubproject = packageAssets && cleanPackageAssets && !isBuildingAar
            Task copyFlutterAssetsTask = project.tasks.create(
                name: "copyFlutterAssets${variant.name.capitalize()}",
                type: Copy,
            ) {
                dependsOn compileTask
                with compileTask.assets
                if (isUsedAsSubproject) {
                    dependsOn packageAssets
                    dependsOn cleanPackageAssets
                    into packageAssets.outputDir
                    return
                }
                // `variant.mergeAssets` will be removed at the end of 2019.
                def mergeAssets = variant.hasProperty("mergeAssetsProvider") ?
                    variant.mergeAssetsProvider.get() : variant.mergeAssets
                dependsOn mergeAssets
                dependsOn "clean${mergeAssets.name.capitalize()}"
                mergeAssets.mustRunAfter("clean${mergeAssets.name.capitalize()}")
                into mergeAssets.outputDir
            }
            if (!isUsedAsSubproject) {
                def variantOutput = variant.outputs.first()
                def processResources = variantOutput.hasProperty("processResourcesProvider") ?
                    variantOutput.processResourcesProvider.get() : variantOutput.processResources
                processResources.dependsOn(copyFlutterAssetsTask)
            }
            return copyFlutterAssetsTask
        } // end def addFlutterDeps

		//13.如果是flutter app module的话
        if (isFlutterAppProject()) {
            project.android.applicationVariants.all { variant ->
                Task assembleTask = getAssembleTask(variant)
                if (!shouldConfigureFlutterTask(assembleTask)) {
                  return
                }
                Task copyFlutterAssetsTask = addFlutterDeps(variant)
                def variantOutput = variant.outputs.first()
                def processResources = variantOutput.hasProperty("processResourcesProvider") ?
                    variantOutput.processResourcesProvider.get() : variantOutput.processResources
                processResources.dependsOn(copyFlutterAssetsTask)

                //14.将apk复制到已知位置,一遍遍运行flutter run,或者flutter build apk命令,一般默认位置是<app-dir>/build/app/outputs/flutter-apk/<filename>.apk
                //
                // The filename consists of `app<-abi>?<-flavor-name>?-<build-mode>.apk`.
                // Where:
                //   * `abi` can be `armeabi-v7a|arm64-v8a|x86|x86_64` only if the flag `split-per-abi` is set.
                //   * `flavor-name` is the flavor used to build the app in lower case if the assemble task is called.
                //   * `build-mode` can be `release|debug|profile`.
                variant.outputs.all { output ->
                    assembleTask.doLast {
                        // `packageApplication` became `packageApplicationProvider` in AGP 3.3.0.
                        def outputDirectory = variant.hasProperty("packageApplicationProvider")
                            ? variant.packageApplicationProvider.get().outputDirectory
                            : variant.packageApplication.outputDirectory
                        //  `outputDirectory` is a `DirectoryProperty` in AGP 4.1.
                        String outputDirectoryStr = outputDirectory.metaClass.respondsTo(outputDirectory, "get")
                            ? outputDirectory.get()
                            : outputDirectory
                        String filename = "app"
                        String abi = output.getFilter(OutputFile.ABI)
                        if (abi != null && !abi.isEmpty()) {
                            filename += "-${abi}"
                        }
                        if (variant.flavorName != null && !variant.flavorName.isEmpty()) {
                            filename += "-${variant.flavorName.toLowerCase()}"
                        }
                        filename += "-${buildModeFor(variant.buildType)}"
                        project.copy {
                            from new File("$outputDirectoryStr/${output.outputFileName}")
                            into new File("${project.buildDir}/outputs/flutter-apk");
                            rename {
                                return "${filename}.apk"
                            }
                        }
                    }
                }
            }
            //14.这里主要是去执行flutter pub get去获取flutter对应的依赖,并添加
            configurePlugins()
            return
        }
        //15.如果是模块依赖的方式集成到现在项目中的话,对模块做上述相应重复操作。
        String hostAppProjectName = project.rootProject.hasProperty('flutter.hostAppProjectName') ? project.rootProject.property('flutter.hostAppProjectName') : "app"
        Project appProject = project.rootProject.findProject(":${hostAppProjectName}")
        assert appProject != null : "Project :${hostAppProjectName} doesn't exist. To custom the host app project name, set `org.gradle.project.flutter.hostAppProjectName=<project-name>` in gradle.properties."
        // Wait for the host app project configuration.
        appProject.afterEvaluate {
            assert appProject.android != null
            project.android.libraryVariants.all { libraryVariant ->
                Task copyFlutterAssetsTask
                appProject.android.applicationVariants.all { appProjectVariant ->
                    Task appAssembleTask = getAssembleTask(appProjectVariant)
                    if (!shouldConfigureFlutterTask(appAssembleTask)) {
                        return
                    }
                    // Find a compatible application variant in the host app.
                    //
                    // For example, consider a host app that defines the following variants:
                    // | ----------------- | ----------------------------- |
                    // |   Build Variant   |   Flutter Equivalent Variant  |
                    // | ----------------- | ----------------------------- |
                    // |   freeRelease     |   release                      |
                    // |   freeDebug       |   debug                       |
                    // |   freeDevelop     |   debug                       |
                    // |   profile         |   profile                     |
                    // | ----------------- | ----------------------------- |
                    //
                    // This mapping is based on the following rules:
                    // 1. If the host app build variant name is `profile` then the equivalent
                    //    Flutter variant is `profile`.
                    // 2. If the host app build variant is debuggable
                    //    (e.g. `buildType.debuggable = true`), then the equivalent Flutter
                    //    variant is `debug`.
                    // 3. Otherwise, the equivalent Flutter variant is `release`.
                    String variantBuildMode = buildModeFor(libraryVariant.buildType)
                    if (buildModeFor(appProjectVariant.buildType) != variantBuildMode) {
                        return
                    }
                    if (copyFlutterAssetsTask == null) {
                        copyFlutterAssetsTask = addFlutterDeps(libraryVariant)
                    }
                    Task mergeAssets = project
                        .tasks
                        .findByPath(":${hostAppProjectName}:merge${appProjectVariant.name.capitalize()}Assets")
                    assert mergeAssets
                    mergeAssets.dependsOn(copyFlutterAssetsTask)
                }
            }
        }
        configurePlugins()
    }

packFlutterAppAotTask和copyFlutterAssetsTask两个task完成了以后相当于生成了flutter_assets目录下的这些flutter产物,最终将会编译打包进apk里,也就是apk里相对应的flutter_assets下。
在这里插入图片描述

在这里插入图片描述

至此,flutter打包的大框架上的流程就走完了,但你是不是发现其实还没到点上。。没错我们回到上面的第6条,我们来着重看下这个FlutterTask任务。

abstract class BaseFlutterTask extends DefaultTask {
    @Internal
    File flutterRoot
    @Internal
    File flutterExecutable
    @Input
    String buildMode
    @Optional @Input
    String localEngine
    @Optional @Input
    String localEngineSrcPath
    @Optional @Input
    Boolean fastStart
    @Input
    String targetPath
    @Optional @Internal
    Boolean verbose
    @Optional @Input
    String[] fileSystemRoots
    @Optional @Input
    String fileSystemScheme
    @Input
    Boolean trackWidgetCreation
    @Optional @Input
    List<String> targetPlatformValues
    @Internal
    File sourceDir
    @Internal
    File intermediateDir
    @Optional @Input
    String extraFrontEndOptions
    @Optional @Input
    String extraGenSnapshotOptions
    @Optional @Input
    String splitDebugInfo
    @Optional @Input
    Boolean treeShakeIcons
    @Optional @Input
    Boolean dartObfuscation
    @Optional @Input
    String dartDefines
    @Optional @Input
    String bundleSkSLPath
    @Optional @Input
    String codeSizeDirectory;
    @Optional @Input
    String performanceMeasurementFile;
    @Optional @Input
    Boolean deferredComponents
    @Optional @Input
    Boolean validateDeferredComponents

    @OutputFiles
    FileCollection getDependenciesFiles() {
        FileCollection depfiles = project.files()

        // Includes all sources used in the flutter compilation.
        depfiles += project.files("${intermediateDir}/flutter_build.d")
        return depfiles
    }

    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
        }
    }
}

class FlutterTask extends BaseFlutterTask {
    @OutputDirectory
    File getOutputDirectory() {
        return intermediateDir
    }

    @Internal
    String getAssetsDirectory() {
        return "${outputDirectory}/flutter_assets"
    }

    @Internal
    CopySpec getAssets() {
        return project.copySpec {
            from "${intermediateDir}"
            include "flutter_assets/**" // the working dir and its files
        }
    }

    @Internal
    CopySpec getSnapshots() {
        return project.copySpec {
            from "${intermediateDir}"

            if (buildMode == 'release' || buildMode == 'profile') {
                targetPlatformValues.each {
                    include "${PLATFORM_ARCH_MAP[targetArch]}/app.so"
                }
            }
        }
    }

    FileCollection readDependencies(File dependenciesFile, Boolean inputs) {
      if (dependenciesFile.exists()) {
        // Dependencies file has Makefile syntax:
        //   <target> <files>: <source> <files> <separated> <by> <non-escaped space>
        String depText = dependenciesFile.text
        // So we split list of files by non-escaped(by backslash) space,
        def matcher = depText.split(': ')[inputs ? 1 : 0] =~ /(\\ |[^\s])+/
        // then we replace all escaped spaces with regular spaces
        def depList = matcher.collect{it[0].replaceAll("\\\\ ", " ")}
        return project.files(depList)
      }
      return project.files();
    }

    @InputFiles
    FileCollection getSourceFiles() {
        FileCollection sources = project.files()
        for (File depfile in getDependenciesFiles()) {
          sources += readDependencies(depfile, true)
        }
        return sources + project.files('pubspec.yaml')
    }

    @OutputFiles
    FileCollection getOutputFiles() {
        FileCollection sources = project.files()
        for (File depfile in getDependenciesFiles()) {
          sources += readDependencies(depfile, false)
        }
        return sources
    }

    @TaskAction
    void build() {
        buildBundle()
    }
}

按照task基础,我们直接来看@TaskAction,里面调用了buildBundle方法,我们来这个方法,里面重点执行了flutter编译命令脚本,饼配置了各种脚本参数,主要调用了flutter sdk下面的bin/flutter 编译命令。至此应用层面打包apk的流程就过完了。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值