FlutterPlugin.groovy 6.44 KB
Newer Older
1 2 3 4 5 6 7
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package org.domokit.sky.gradle

import com.android.builder.model.AndroidProject
8
import com.google.common.base.Joiner
9 10 11 12 13
import org.gradle.api.DefaultTask
import org.gradle.api.GradleException
import org.gradle.api.Project
import org.gradle.api.Plugin
import org.gradle.api.Task
14
import org.gradle.api.file.CopySpec
15 16 17 18 19 20 21
import org.gradle.api.file.FileCollection
import org.gradle.api.tasks.Copy
import org.gradle.api.tasks.InputDirectory
import org.gradle.api.tasks.OutputDirectory
import org.gradle.api.tasks.TaskAction

class FlutterPlugin implements Plugin<Project> {
22 23
    private File flutterRoot
    private String buildMode
24
    private String localEngine
25 26 27 28 29 30

    @Override
    void apply(Project project) {
        Properties properties = new Properties()
        properties.load(project.rootProject.file("local.properties").newDataInputStream())

31 32
        String flutterRootPath = properties.getProperty("flutter.sdk")
        if (flutterRootPath == null) {
33 34
            throw new GradleException("flutter.sdk must be defined in local.properties")
        }
35 36
        flutterRoot = project.file(flutterRootPath)
        if (!flutterRoot.isDirectory()) {
37 38 39
            throw new GradleException("flutter.sdk must point to the Flutter SDK directory")
        }

40 41 42 43 44 45 46 47
        buildMode = properties.getProperty("flutter.buildMode")
        if (buildMode == null) {
            buildMode = "release"
        }
        if (!["debug", "profile", "release"].contains(buildMode)) {
            throw new GradleException("flutter.buildMode must be one of \"debug\", \"profile\", or \"release\" but was \"${buildMode}\"")
        }

48 49 50 51 52 53 54 55
        File flutterJar
        String flutterJarPath = properties.getProperty("flutter.jar")
        if (flutterJarPath != null) {
            flutterJar = project.file(flutterJarPath)
            if (!flutterJar.isFile()) {
                throw new GradleException("flutter.jar must point to a Flutter engine JAR")
            }
        } else {
56 57 58 59 60 61 62 63 64 65 66
            // TODO(abarth): Support x64 and x86 in addition to arm.
            String artifactType = "unknown";
            if (buildMode == "debug") {
                artifactType = "android-arm"
            } else if (buildMode == "profile") {
                artifactType = "android-arm-profile"
            } else if (buildMode == "release") {
                artifactType = "android-arm-release"
            }
            flutterJar = new File(flutterRoot, Joiner.on(File.separatorChar).join(
                "bin", "cache", "artifacts", "engine", artifactType, "flutter.jar"))
67 68
            if (!flutterJar.isFile()) {
                project.exec {
69
                    executable "${flutterRoot}/bin/flutter"
70 71 72 73 74 75 76 77
                    args "precache"
                }
                if (!flutterJar.isFile()) {
                    throw new GradleException("Unable to find flutter.jar in SDK: ${flutterJar}")
                }
            }
        }

78
        localEngine = properties.getProperty("flutter.localEngine")
79

80
        project.extensions.create("flutter", FlutterExtension)
81
        project.dependencies.add("compile", project.files(flutterJar))
82 83 84 85 86 87 88 89
        project.afterEvaluate this.&addFlutterTask
    }

    private void addFlutterTask(Project project) {
        if (project.flutter.source == null) {
            throw new GradleException("Must provide Flutter source directory")
        }

90 91 92 93 94
        String target = project.flutter.target;
        if (target == null) {
            target = 'lib/main.dart'
        }

95
        FlutterTask flutterTask = project.tasks.create("flutterBuild", FlutterTask) {
96 97 98
            flutterRoot this.flutterRoot
            buildMode this.buildMode
            localEngine this.localEngine
99
            targetPath target
100 101 102 103 104
            sourceDir project.file(project.flutter.source)
            intermediateDir project.file("${project.buildDir}/${AndroidProject.FD_INTERMEDIATES}/flutter")
        }

        project.android.applicationVariants.all { variant ->
105
            Task copyFlxTask = project.tasks.create(name: "copyFlutterAssets${variant.name.capitalize()}", type: Copy) {
106 107 108
                dependsOn flutterTask
                dependsOn variant.mergeAssets
                into variant.mergeAssets.outputDir
109
                with flutterTask.assets
110 111 112 113 114 115 116 117
            }
            variant.outputs[0].processResources.dependsOn(copyFlxTask)
        }
    }
}

class FlutterExtension {
    String source
118
    String target
119 120 121
}

class FlutterTask extends DefaultTask {
122 123 124
    File flutterRoot
    String buildMode
    String localEngine
125
    String targetPath
126 127 128 129 130 131 132

    @InputDirectory
    File sourceDir

    @OutputDirectory
    File intermediateDir

133 134 135 136 137 138 139 140 141 142
    CopySpec getAssets() {
        return project.copySpec {
            from "${intermediateDir}/app.flx"
            if (buildMode != 'debug') {
                from "${intermediateDir}/snapshot_aot_instr"
                from "${intermediateDir}/snapshot_aot_isolate"
                from "${intermediateDir}/snapshot_aot_rodata"
                from "${intermediateDir}/snapshot_aot_vmisolate"
            }
        }
143 144 145 146 147 148 149 150 151
    }

    @TaskAction
    void build() {
        if (!sourceDir.isDirectory()) {
            throw new GradleException("Invalid Flutter source directory: ${sourceDir}")
        }

        intermediateDir.mkdirs()
152 153 154 155 156 157 158 159 160

        if (buildMode != "debug") {
          project.exec {
            executable "${flutterRoot}/bin/flutter"
            workingDir sourceDir
            if (localEngine != null) {
              args "--local-engine", localEngine
            }
            args "build", "aot"
161
            args "--target", targetPath
162 163 164 165 166 167
            args "--target-platform", "android-arm"
            args "--output-dir", "${intermediateDir}"
            args "--${buildMode}"
          }
        }

168
        project.exec {
169
            executable "${flutterRoot}/bin/flutter"
170
            workingDir sourceDir
171 172
            if (localEngine != null) {
              args "--local-engine", localEngine
173
            }
174
            args "build", "flx"
175
            args "--target", targetPath
176 177 178 179 180 181 182
            args "--output-file", "${intermediateDir}/app.flx"
            if (buildMode != "debug") {
              args "--precompiled"
            } else {
              args "--snapshot", "${intermediateDir}/snapshot_blob.bin"
              args "--depfile", "${intermediateDir}/snapshot_blob.bin.d"
            }
183 184 185 186
            args "--working-dir", "${intermediateDir}/flx"
        }
    }
}