2019-07-23 16:27:42 +00:00
import static groovy . io . FileType . FILES
2016-03-12 00:30:56 +00:00
import com.android.builder.model.AndroidProject
2019-06-10 20:16:09 +00:00
import com.android.build.OutputFile
2019-11-22 23:02:20 +00:00
import groovy.json.JsonSlurper
2019-07-23 16:27:42 +00:00
import java.nio.file.Path
import java.nio.file.Paths
2019-09-24 23:16:22 +00:00
import java.util.regex.Matcher
import java.util.regex.Pattern
2017-02-16 22:17:09 +00:00
import org.apache.tools.ant.taskdefs.condition.Os
2016-03-12 00:30:56 +00:00
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
2016-06-06 19:56:04 +00:00
import org.gradle.api.file.CopySpec
2016-03-12 00:30:56 +00:00
import org.gradle.api.file.FileCollection
import org.gradle.api.tasks.Copy
2017-01-31 22:48:48 +00:00
import org.gradle.api.tasks.InputFiles
2016-03-12 00:30:56 +00:00
import org.gradle.api.tasks.OutputDirectory
import org.gradle.api.tasks.TaskAction
2017-01-31 22:48:48 +00:00
import org.gradle.api.tasks.bundling.Jar
2020-12-09 20:58:05 +00:00
import org.gradle.util.VersionNumber
2016-03-12 00:30:56 +00:00
2017-02-10 08:37:38 +00:00
buildscript {
2017-07-31 11:57:24 +00:00
repositories {
2018-10-24 21:33:39 +00:00
google ( )
2017-12-14 14:38:39 +00:00
jcenter ( )
2017-07-31 11:57:24 +00:00
}
dependencies {
2020-12-02 03:01:09 +00:00
classpath 'com.android.tools.build:gradle:4.1.0'
2017-07-31 11:57:24 +00:00
}
2017-02-10 08:37:38 +00:00
}
2018-12-17 22:40:48 +00:00
android {
compileOptions {
sourceCompatibility 1.8
targetCompatibility 1.8
}
}
2017-02-10 08:37:38 +00:00
apply plugin: FlutterPlugin
2016-03-12 00:30:56 +00:00
class FlutterPlugin implements Plugin < Project > {
2020-05-10 04:14:01 +00:00
private static final String DEFAULT_MAVEN_HOST = "https://storage.googleapis.com" ;
2019-09-17 15:19:33 +00:00
2019-06-10 20:16:09 +00:00
// The platforms that can be passed to the `--Ptarget-platform` flag.
private static final String PLATFORM_ARM32 = "android-arm" ;
private static final String PLATFORM_ARM64 = "android-arm64" ;
private static final String PLATFORM_X86 = "android-x86" ;
private static final String PLATFORM_X86_64 = "android-x64" ;
// The ABI architectures.
private static final String ARCH_ARM32 = "armeabi-v7a" ;
private static final String ARCH_ARM64 = "arm64-v8a" ;
private static final String ARCH_X86 = "x86" ;
private static final String ARCH_X86_64 = "x86_64" ;
// Maps platforms to ABI architectures.
private static final Map PLATFORM_ARCH_MAP = [
( PLATFORM_ARM32 ) : ARCH_ARM32 ,
( PLATFORM_ARM64 ) : ARCH_ARM64 ,
( PLATFORM_X86 ) : ARCH_X86 ,
( PLATFORM_X86_64 ) : ARCH_X86_64 ,
]
// The version code that gives each ABI a value.
// For each APK variant, use the following versions to override the version of the Universal APK.
// Otherwise, the Play Store will complain that the APK variants have the same version.
private static final Map ABI_VERSION = [
( ARCH_ARM32 ) : 1 ,
( ARCH_ARM64 ) : 2 ,
( ARCH_X86 ) : 3 ,
( ARCH_X86_64 ) : 4 ,
]
// When split is enabled, multiple APKs are generated per each ABI.
private static final List DEFAULT_PLATFORMS = [
PLATFORM_ARM32 ,
PLATFORM_ARM64 ,
2020-07-24 22:33:13 +00:00
PLATFORM_X86_64 ,
2019-06-10 20:16:09 +00:00
]
// The name prefix for flutter builds. This is used to identify gradle tasks
// where we expect the flutter tool to provide any error output, and skip the
// standard Gradle error output in the FlutterEventLogger. If you change this,
// be sure to change any instances of this string in symbols in the code below
// to match.
static final String FLUTTER_BUILD_PREFIX = "flutterBuild"
2019-09-17 15:19:33 +00:00
private Project project
2019-06-13 23:05:28 +00:00
private Map baseJar = [ : ]
2016-06-06 19:56:04 +00:00
private File flutterRoot
2017-02-16 22:17:09 +00:00
private File flutterExecutable
2016-05-28 00:12:52 +00:00
private String localEngine
2017-02-23 13:56:19 +00:00
private String localEngineSrcPath
2017-01-31 22:48:48 +00:00
private Properties localProperties
2019-09-17 15:19:33 +00:00
private String engineVersion
2019-06-10 20:16:09 +00:00
2016-03-12 00:30:56 +00:00
@Override
void apply ( Project project ) {
2019-09-17 15:19:33 +00:00
this . project = project
2021-01-13 22:09:04 +00:00
// Configure the Maven repository.
String hostedRepository = System . env . FLUTTER_STORAGE_BASE_URL ? : DEFAULT_MAVEN_HOST
String repository = useLocalEngine ( )
? project . property ( 'local-engine-repo' )
: "$hostedRepository/download.flutter.io"
project . rootProject . allprojects {
repositories {
maven {
url repository
}
}
}
2019-05-20 20:09:20 +00:00
project . extensions . create ( "flutter" , FlutterExtension )
2020-12-02 03:01:09 +00:00
this . addFlutterTasks ( project )
2019-06-10 20:16:09 +00:00
// By default, assembling APKs generates fat APKs if multiple platforms are passed.
// Configuring split per ABI allows to generate separate APKs for each abi.
// This is a noop when building a bundle.
2019-09-17 15:19:33 +00:00
if ( shouldSplitPerAbi ( ) ) {
2019-06-10 20:16:09 +00:00
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
}
}
}
}
2019-09-17 15:19:33 +00:00
getTargetPlatforms ( ) . each { targetArch - >
2019-06-10 20:16:09 +00:00
String abiValue = PLATFORM_ARCH_MAP [ targetArch ]
2019-05-20 20:09:20 +00:00
project . android {
2019-09-17 15:19:33 +00:00
if ( shouldSplitPerAbi ( ) ) {
2019-06-10 20:16:09 +00:00
splits {
abi {
include abiValue
}
}
2019-05-20 20:09:20 +00:00
}
}
}
2019-09-04 00:49:10 +00:00
2019-09-17 15:19:33 +00:00
String flutterRootPath = resolveProperty ( "flutter.sdk" , System . env . FLUTTER_ROOT )
2016-06-06 19:56:04 +00:00
if ( flutterRootPath = = null ) {
2017-05-22 14:50:31 +00:00
throw new GradleException ( "Flutter SDK not found. Define location with flutter.sdk in the local.properties file or with a FLUTTER_ROOT environment variable." )
2016-03-12 00:30:56 +00:00
}
2016-06-06 19:56:04 +00:00
flutterRoot = project . file ( flutterRootPath )
if ( ! flutterRoot . isDirectory ( ) ) {
2016-03-12 00:30:56 +00:00
throw new GradleException ( "flutter.sdk must point to the Flutter SDK directory" )
}
2019-11-06 20:52:37 +00:00
engineVersion = useLocalEngine ( )
? "+" // Match any version since there's only one.
: "1.0.0-" + Paths . get ( flutterRoot . absolutePath , "bin" , "internal" , "engine.version" ) . toFile ( ) . text . trim ( )
2019-09-17 15:19:33 +00:00
2017-02-16 22:17:09 +00:00
String flutterExecutableName = Os . isFamily ( Os . FAMILY_WINDOWS ) ? "flutter.bat" : "flutter"
flutterExecutable = Paths . get ( flutterRoot . absolutePath , "bin" , flutterExecutableName ) . toFile ( ) ;
2020-12-07 17:23:04 +00:00
String flutterProguardRules = Paths . get ( flutterRoot . absolutePath , "packages" , "flutter_tools" ,
"gradle" , "flutter_proguard_rules.pro" )
2019-09-11 00:22:55 +00:00
project . android . buildTypes {
2020-12-07 17:23:04 +00:00
// Add profile build type.
2019-09-11 00:22:55 +00:00
profile {
initWith debug
if ( it . hasProperty ( "matchingFallbacks" ) ) {
matchingFallbacks = [ "debug" , "release" ]
}
}
2020-12-02 03:01:09 +00:00
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"
2019-09-11 00:22:55 +00:00
}
}
2020-12-02 03:01:09 +00:00
2019-09-17 15:19:33 +00:00
if ( useLocalEngine ( ) ) {
2019-11-06 20:52:37 +00:00
// This is required to pass the local engine to flutter build aot.
String engineOutPath = project . property ( 'local-engine-out' )
2019-09-04 00:49:10 +00:00
File engineOut = project . file ( engineOutPath )
2017-02-23 13:56:19 +00:00
if ( ! engineOut . isDirectory ( ) ) {
2019-11-06 20:52:37 +00:00
throw new GradleException ( 'local-engine-out must point to a local engine build' )
2016-04-12 21:26:22 +00:00
}
2017-02-23 13:56:19 +00:00
localEngine = engineOut . name
localEngineSrcPath = engineOut . parentFile . parent
2019-09-17 15:19:33 +00:00
}
2021-01-13 22:09:04 +00:00
project . android . buildTypes . all this . & addFlutterDependencies
2019-09-17 15:19:33 +00:00
}
/ * *
* Adds the dependencies required by the Flutter project .
* This includes:
* 1 . The embedding
* 2 . libflutter . so
* /
void addFlutterDependencies ( buildType ) {
2019-11-06 20:52:37 +00:00
String flutterBuildMode = buildModeFor ( buildType )
if ( ! supportsBuildMode ( flutterBuildMode ) ) {
return
}
2021-01-13 22:09:04 +00:00
// 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" )
2019-09-17 15:19:33 +00:00
}
List < String > platforms = getTargetPlatforms ( ) . collect ( )
// Debug mode includes x86 and x64, which are commonly used in emulators.
2019-11-06 23:22:54 +00:00
if ( flutterBuildMode = = "debug" & & ! useLocalEngine ( ) ) {
2019-09-17 15:19:33 +00:00
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 ,
2019-11-06 20:52:37 +00:00
"io.flutter:${arch}_$flutterBuildMode:$engineVersion" )
2016-04-12 21:26:22 +00:00
}
2019-07-23 16:27:42 +00:00
}
/ * *
* Returns the directory where the plugins are built .
* /
2019-09-17 15:19:33 +00:00
private File getPluginBuildDir ( ) {
2019-07-23 16:27:42 +00:00
// Module projects specify this flag to include plugins in the same repo as the module project.
if ( project . ext . has ( "pluginBuildDir" ) ) {
return project . ext . get ( "pluginBuildDir" )
}
return project . buildDir
}
2017-03-23 13:59:12 +00:00
2019-09-17 15:19:33 +00:00
/ * *
* Configures the Flutter plugin dependencies .
*
* The plugins are added to pubspec . yaml . Then , upon running ` flutter pub get ` ,
* the tool generates a ` . flutter - plugins ` file , which contains a 1 : 1 map to each plugin location .
* Finally , the project 's `settings.gradle` loads each plugin' s android directory as a subproject .
* /
private void configurePlugins ( ) {
if ( ! buildPluginAsAar ( ) ) {
2019-09-24 23:16:22 +00:00
getPluginList ( ) . each this . & configurePluginProject
2019-11-22 23:02:20 +00:00
getPluginDependencies ( ) . each this . & configurePluginDependencies
2019-09-17 15:19:33 +00:00
return
}
2019-11-02 16:46:25 +00:00
project . repositories {
maven {
url "${getPluginBuildDir()}/outputs/repo"
2019-09-17 15:19:33 +00:00
}
}
2019-09-24 23:16:22 +00:00
getPluginList ( ) . each { pluginName , pluginPath - >
configurePluginAar ( pluginName , pluginPath , project )
2019-09-17 15:19:33 +00:00
}
}
2019-09-24 23:16:22 +00:00
private static final Pattern GROUP_PATTERN = ~ /group\s+\'(.+)\'/
private static final Pattern PROJECT_NAME_PATTERN = ~ /rootProject\.name\s+=\s+\'(.+)\'/
// Adds the plugin AAR dependency to the app project.
private void configurePluginAar ( String pluginName , String pluginPath , Project project ) {
// Extract the group id from the plugin's build.gradle.
// This is `group '<group-id>'`
File pluginBuildFile = project . file ( Paths . get ( pluginPath , "android" , "build.gradle" ) ) ;
if ( ! pluginBuildFile . exists ( ) ) {
throw new GradleException ( "Plugin $pluginName doesn't have the required file $pluginBuildFile." )
}
Matcher groupParts = GROUP_PATTERN . matcher ( pluginBuildFile . text )
assert groupParts . count = = 1
assert groupParts . hasGroup ( )
String groupId = groupParts [ 0 ] [ 1 ]
// Extract the artifact name from the plugin's settings.gradle.
// This is `rootProject.name = '<artifact-name>'`
File pluginSettings = project . file ( Paths . get ( pluginPath , "android" , "settings.gradle" ) ) ;
if ( ! pluginSettings . exists ( ) ) {
throw new GradleException ( "Plugin $pluginName doesn't have the required file $pluginSettings." )
}
Matcher projectNameParts = PROJECT_NAME_PATTERN . matcher ( pluginSettings . text )
assert projectNameParts . count = = 1
assert projectNameParts . hasGroup ( )
String artifactId = "${projectNameParts[0][1]}_release"
assert ! groupId . empty
project . dependencies . add ( "api" , "$groupId:$artifactId:+" )
}
// Adds the plugin project dependency to the app project .
2019-11-22 23:02:20 +00:00
private void configurePluginProject ( String pluginName , String _ ) {
Project pluginProject = project . rootProject . findProject ( ":$pluginName" )
2019-09-17 15:19:33 +00:00
if ( pluginProject = = null ) {
2019-11-22 23:02:20 +00:00
project . logger . error ( "Plugin project :$pluginName not found. Please update settings.gradle." )
2019-09-17 15:19:33 +00:00
return
}
// Add plugin dependency to the app project.
project . dependencies {
2021-01-13 22:09:04 +00:00
api pluginProject
2019-09-17 15:19:33 +00:00
}
2020-12-09 20:58:05 +00:00
Closure addEmbeddingDependencyToPlugin = { buildType - >
2019-09-17 15:19:33 +00:00
String flutterBuildMode = buildModeFor ( buildType )
2019-09-26 00:59:17 +00:00
// In AGP 3.5, the embedding must be added as an API implementation,
// so java8 features are desugared against the runtime classpath.
// For more, see https://github.com/flutter/flutter/issues/40126
2019-11-06 20:52:37 +00:00
if ( ! supportsBuildMode ( flutterBuildMode ) ) {
2019-09-17 15:19:33 +00:00
return
}
2020-12-07 17:23:04 +00:00
// Copy build types from the app to the plugin.
// This allows to build apps with plugins and custom build types or flavors.
pluginProject . android . buildTypes {
"${buildType.name}" { }
}
2021-01-13 22:09:04 +00:00
// The embedding is API dependency of the plugin, so the AGP is able to desugar
// default method implementations when the interface is implemented by a plugin.
2020-12-09 20:58:05 +00:00
//
2021-01-13 22:09:04 +00:00
// See https://issuetracker.google.com/139821726, and
// https://github.com/flutter/flutter/issues/72185 for more details.
addApiDependencies (
pluginProject ,
buildType . name ,
"io.flutter:flutter_embedding_$flutterBuildMode:$engineVersion"
)
2019-09-17 15:19:33 +00:00
}
2020-12-07 17:23:04 +00:00
// Wait until the Android plugin loaded.
2019-09-17 15:19:33 +00:00
pluginProject . afterEvaluate {
2021-01-13 22:09:04 +00:00
project . android . buildTypes . all addEmbeddingDependencyToPlugin
2019-09-17 15:19:33 +00:00
}
}
2019-12-18 03:48:01 +00:00
// Returns `true` if the given path contains an `android/build.gradle` file.
//
// TODO(egarciad): Fix https://github.com/flutter/flutter/issues/39657.
// Android Studio may create empty android directories due to the logic in <app>/android/settings.gradle,
// which imports all plugins regardless of whether they support the android platform.
private Boolean doesSupportAndroidPlatform ( String path ) {
File editableAndroidProject = new File ( path , 'android' + File . separator + 'build.gradle' )
return editableAndroidProject . exists ( )
}
2019-11-22 23:02:20 +00:00
// Add the dependencies on other plugin projects to the plugin project.
// A plugin A can depend on plugin B. As a result, this dependency must be surfaced by
// making the Gradle plugin project A depend on the Gradle plugin project B.
private void configurePluginDependencies ( Object dependencyObject ) {
assert dependencyObject . name instanceof String
Project pluginProject = project . rootProject . findProject ( ":${dependencyObject.name}" )
2019-12-18 03:48:01 +00:00
if ( pluginProject = = null | |
! doesSupportAndroidPlatform ( pluginProject . projectDir . parentFile . path ) ) {
2019-11-22 23:02:20 +00:00
return
}
assert dependencyObject . dependencies instanceof List
dependencyObject . dependencies . each { pluginDependencyName - >
assert pluginDependencyName instanceof String
if ( pluginDependencyName . empty ) {
return
}
Project dependencyProject = project . rootProject . findProject ( ":$pluginDependencyName" )
2019-12-18 03:48:01 +00:00
if ( dependencyProject = = null | |
! doesSupportAndroidPlatform ( dependencyProject . projectDir . parentFile . path ) ) {
2019-11-22 23:02:20 +00:00
return
}
2020-11-21 02:03:39 +00:00
// Wait for the Android plugin to load and add the dependency to the plugin project.
pluginProject . afterEvaluate {
pluginProject . dependencies {
implementation dependencyProject
}
2019-11-22 23:02:20 +00:00
}
}
}
2019-09-17 15:19:33 +00:00
private Properties getPluginList ( ) {
2020-06-18 22:19:12 +00:00
File pluginsFile = new File ( project . projectDir . parentFile . parentFile , '.flutter-plugins' )
Properties allPlugins = readPropertiesIfExist ( pluginsFile )
2019-09-18 23:42:20 +00:00
Properties androidPlugins = new Properties ( )
2020-06-18 22:19:12 +00:00
allPlugins . each { name , path - >
if ( doesSupportAndroidPlatform ( path ) ) {
androidPlugins . setProperty ( name , path )
}
// TODO(amirh): log an error if this plugin was specified to be an Android
// plugin according to the new schema, and was missing a build.gradle file.
// https://github.com/flutter/flutter/issues/40784
2020-06-18 21:08:01 +00:00
}
2019-09-18 23:42:20 +00:00
return androidPlugins
2019-07-23 16:27:42 +00:00
}
2019-11-22 23:02:20 +00:00
// Gets the plugins dependencies from `.flutter-plugins-dependencies`.
private List getPluginDependencies ( ) {
// Consider a `.flutter-plugins-dependencies` file with the following content:
// {
// "dependencyGraph": [
// {
// "name": "plugin-a",
// "dependencies": ["plugin-b","plugin-c"]
// },
// {
// "name": "plugin-b",
// "dependencies": ["plugin-c"]
// },
// {
// "name": "plugin-c",
// "dependencies": []'
// }
// ]
// }
//
// This means, `plugin-a` depends on `plugin-b` and `plugin-c`.
// `plugin-b` depends on `plugin-c`.
// `plugin-c` doesn't depend on anything.
File pluginsDependencyFile = new File ( project . projectDir . parentFile . parentFile , '.flutter-plugins-dependencies' )
if ( pluginsDependencyFile . exists ( ) ) {
def object = new JsonSlurper ( ) . parseText ( pluginsDependencyFile . text )
assert object instanceof Map
assert object . dependencyGraph instanceof List
return object . dependencyGraph
}
return [ ]
}
2019-07-23 16:27:42 +00:00
private static String toCammelCase ( List < String > parts ) {
if ( parts . empty ) {
return ""
}
return "${parts[0]}${parts[1..-1].collect { it.capitalize() }.join('')}"
}
2019-09-17 15:19:33 +00:00
private String resolveProperty ( String name , String defaultValue ) {
2019-06-13 23:05:28 +00:00
if ( localProperties = = null ) {
localProperties = readPropertiesIfExist ( new File ( project . projectDir . parentFile , "local.properties" ) )
}
String result
if ( project . hasProperty ( name ) ) {
result = project . property ( name )
}
if ( result = = null ) {
result = localProperties . getProperty ( name )
}
if ( result = = null ) {
result = defaultValue
}
return result
}
private static Properties readPropertiesIfExist ( File propertiesFile ) {
Properties result = new Properties ( )
if ( propertiesFile . exists ( ) ) {
propertiesFile . withReader ( 'UTF-8' ) { reader - > result . load ( reader ) }
}
return result
}
2019-09-17 15:19:33 +00:00
private List < String > getTargetPlatforms ( ) {
2019-06-13 23:05:28 +00:00
if ( ! project . hasProperty ( 'target-platform' ) ) {
return DEFAULT_PLATFORMS
}
return project . property ( 'target-platform' ) . split ( ',' ) . collect {
if ( ! PLATFORM_ARCH_MAP [ it ] ) {
throw new GradleException ( "Invalid platform: $it." )
}
return it
}
}
2019-09-17 15:19:33 +00:00
private Boolean shouldSplitPerAbi ( ) {
2019-06-13 23:05:28 +00:00
if ( project . hasProperty ( 'split-per-abi' ) ) {
return project . property ( 'split-per-abi' ) . toBoolean ( )
}
return false ;
}
2019-09-17 15:19:33 +00:00
private Boolean useLocalEngine ( ) {
2019-11-06 20:52:37 +00:00
return project . hasProperty ( 'local-engine-repo' )
2019-06-13 23:05:28 +00:00
}
2019-09-17 15:19:33 +00:00
private Boolean isVerbose ( ) {
2019-07-23 16:27:42 +00:00
if ( project . hasProperty ( 'verbose' ) ) {
return project . property ( 'verbose' ) . toBoolean ( )
}
return false
}
2019-12-10 18:26:14 +00:00
/// Whether to build the debug app in "fast-start" mode.
private Boolean isFastStart ( ) {
if ( project . hasProperty ( "fast-start" ) ) {
return project . property ( "fast-start" ) . toBoolean ( )
}
return false
}
2019-09-16 22:27:05 +00:00
private static Boolean isBuiltAsApp ( Project project ) {
// Projects are built as applications when the they use the `com.android.application`
// plugin.
return project . plugins . hasPlugin ( "com.android.application" ) ;
}
2019-07-23 16:27:42 +00:00
private static Boolean buildPluginAsAar ( ) {
return System . getProperty ( 'build-plugins-as-aars' ) = = 'true'
}
2019-11-06 20:52:37 +00:00
// Returns true if the build mode is supported by the current call to Gradle.
// This only relevant when using a local engine. Because the engine
// is built for a specific mode, the call to Gradle must match that mode.
private Boolean supportsBuildMode ( String flutterBuildMode ) {
if ( ! useLocalEngine ( ) ) {
return true ;
}
assert project . hasProperty ( 'local-engine-build-mode' )
// Don't configure dependencies for a build mode that the local engine
// doesn't support.
return project . property ( 'local-engine-build-mode' ) = = flutterBuildMode
}
2019-09-17 15:19:33 +00:00
private void addCompileOnlyDependency ( Project project , String variantName , Object dependency , Closure config = null ) {
2017-08-24 08:44:32 +00:00
if ( project . state . failure ) {
return
}
2019-07-23 16:27:42 +00:00
String configuration ;
if ( project . getConfigurations ( ) . findByName ( "compileOnly" ) ) {
configuration = "${variantName}CompileOnly" ;
} else {
configuration = "${variantName}Provided" ;
2017-03-23 13:59:12 +00:00
}
2019-09-17 15:19:33 +00:00
project . dependencies . add ( configuration , dependency , config )
2016-03-12 00:30:56 +00:00
}
2019-07-23 16:27:42 +00:00
private static void addApiDependencies ( Project project , String variantName , Object dependency , Closure config = null ) {
String configuration ;
// `compile` dependencies are now `api` dependencies.
if ( project . getConfigurations ( ) . findByName ( "api" ) ) {
configuration = "${variantName}Api" ;
} else {
configuration = "${variantName}Compile" ;
2017-07-31 11:57:24 +00:00
}
2019-07-23 16:27:42 +00:00
project . dependencies . add ( configuration , dependency , config )
2017-07-31 11:57:24 +00:00
}
/ * *
* Returns a Flutter build mode suitable for the specified Android buildType .
*
* Note: The BuildType DSL type is not public , and is therefore omitted from the signature .
*
2019-06-18 18:11:38 +00:00
* @return "debug" , "profile" , or "release" ( fall - back ) .
2017-07-31 11:57:24 +00:00
* /
private static String buildModeFor ( buildType ) {
if ( buildType . name = = "profile" ) {
return "profile"
} else if ( buildType . debuggable ) {
return "debug"
}
return "release"
}
2019-06-10 20:16:09 +00:00
private static String getEngineArtifactDirName ( buildType , targetArch ) {
if ( buildType . name = = "profile" ) {
return "${targetArch}-profile"
} else if ( buildType . debuggable ) {
return "${targetArch}"
}
return "${targetArch}-release"
}
2020-12-02 03:01:09 +00:00
/ * *
* Gets the directory that contains the Flutter source code .
* This is the the directory containing the ` android / ` directory .
* /
private File getFlutterSourceDirectory ( ) {
2016-03-12 00:30:56 +00:00
if ( project . flutter . source = = null ) {
throw new GradleException ( "Must provide Flutter source directory" )
}
2020-12-02 03:01:09 +00:00
return project . file ( project . flutter . source )
}
/ * *
* Gets the target file . This is typically ` lib / main . dart ` .
* /
private String getFlutterTarget ( ) {
2017-01-31 22:48:48 +00:00
String target = project . flutter . target
2016-06-07 20:05:42 +00:00
if ( target = = null ) {
target = 'lib/main.dart'
}
2017-02-23 14:09:05 +00:00
if ( project . hasProperty ( 'target' ) ) {
target = project . property ( 'target' )
}
2020-12-02 03:01:09 +00:00
return target
}
// In AGP 4.0, the Android linter task depends on the JAR tasks that generate `libapp.so`.
// When building APKs, this causes an issue where building release requires the debug JAR,
// but Gradle won't build debug.
//
// To workaround this issue, only configure the JAR task that is required given the task
// from the command line.
//
// The AGP team said that this issue is fixed in Gradle 7.0, which isn't released at the
// time of adding this code. Once released, this can be removed.
//
// Tested cases:
// * `./gradlew assembleRelease`
// * `./gradlew app:assembleRelease.`
// * `./gradlew assemble{flavorName}Release`
// * `./gradlew app:assemble{flavorName}Release`
// * `./gradlew assemble.`
// * `./gradlew app:assemble.`
// * `./gradlew bundle.`
// * `./gradlew bundleRelease.`
// * `./gradlew app:bundleRelease.`
//
// Related issues:
// https://issuetracker.google.com/issues/158060799
// https://issuetracker.google.com/issues/158753935
private boolean shouldConfigureFlutterTask ( Task assembleTask ) {
def cliTasksNames = project . gradle . startParameter . taskNames
if ( cliTasksNames . size ( ) ! = 1 | | ! cliTasksNames . first ( ) . contains ( "assemble" ) ) {
return true
}
def taskName = cliTasksNames . first ( ) . split ( ":" ) . last ( )
if ( taskName = = "assemble" ) {
return true
}
if ( taskName = = assembleTask . name ) {
return true
}
if ( taskName . endsWith ( "Release" ) & & assembleTask . name . endsWith ( "Release" ) ) {
return true
}
if ( taskName . endsWith ( "Debug" ) & & assembleTask . name . endsWith ( "Debug" ) ) {
return true
}
if ( taskName . endsWith ( "Profile" ) & & assembleTask . name . endsWith ( "Profile" ) ) {
return true
}
return false
}
private Task getAssembleTask ( variant ) {
// `assemble` became `assembleProvider` in AGP 3.3.0.
return variant . hasProperty ( "assembleProvider" ) ? variant . assembleProvider . get ( ) : variant . assemble
}
2021-01-13 22:09:04 +00:00
private boolean isFlutterAppProject ( ) {
return project . android . hasProperty ( "applicationVariants" )
}
2020-12-02 03:01:09 +00:00
private void addFlutterTasks ( Project project ) {
if ( project . state . failure ) {
return
}
2018-03-17 19:47:40 +00:00
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' )
}
2020-05-14 19:17:02 +00:00
Boolean trackWidgetCreationValue = true
2018-02-12 18:44:31 +00:00
if ( project . hasProperty ( 'track-widget-creation' ) ) {
2018-04-24 16:51:25 +00:00
trackWidgetCreationValue = project . property ( 'track-widget-creation' ) . toBoolean ( )
2018-02-12 18:44:31 +00:00
}
2017-10-03 19:55:53 +00:00
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' )
}
2020-02-06 01:45:24 +00:00
String splitDebugInfoValue = null
if ( project . hasProperty ( 'split-debug-info' ) ) {
splitDebugInfoValue = project . property ( 'split-debug-info' )
}
2020-02-27 16:58:33 +00:00
Boolean dartObfuscationValue = false
if ( project . hasProperty ( 'dart-obfuscation' ) ) {
dartObfuscationValue = project . property ( 'dart-obfuscation' ) . toBoolean ( ) ;
}
2020-02-05 04:34:24 +00:00
Boolean treeShakeIconsOptionsValue = false
if ( project . hasProperty ( 'tree-shake-icons' ) ) {
treeShakeIconsOptionsValue = project . property ( 'tree-shake-icons' ) . toBoolean ( )
}
2020-03-06 22:53:36 +00:00
String dartDefinesValue = null
if ( project . hasProperty ( 'dart-defines' ) ) {
dartDefinesValue = project . property ( 'dart-defines' )
}
2020-04-30 20:39:08 +00:00
String bundleSkSLPathValue ;
if ( project . hasProperty ( 'bundle-sksl-path' ) ) {
bundleSkSLPathValue = project . property ( 'bundle-sksl-path' )
}
2020-05-01 22:34:28 +00:00
String performanceMeasurementFileValue ;
if ( project . hasProperty ( 'performance-measurement-file' ) ) {
performanceMeasurementFileValue = project . property ( 'performance-measurement-file' )
}
[flutter_tools] support code size tooling on iOS, linux, windows, macOS, and Android on Windows (#63610)
Adds support for size analysis on iOS, macOS, linux, and Windows - using an uncompressed directory based approach. The output format is not currently specified.
Adds support for size analysis on android on windows, switching to package:archive
Updates the console format to display as a tree, allowing longer paths. Increases the number of dart libraries shown (to avoid only ever printing the flutter/dart:ui libraries, which dominate the size)
2020-08-25 17:00:24 +00:00
String codeSizeDirectoryValue ;
if ( project . hasProperty ( 'code-size-directory' ) ) {
codeSizeDirectoryValue = project . property ( 'code-size-directory' )
}
2019-09-17 15:19:33 +00:00
def targetPlatforms = getTargetPlatforms ( )
2019-06-09 01:43:25 +00:00
def addFlutterDeps = { variant - >
2019-09-17 15:19:33 +00:00
if ( shouldSplitPerAbi ( ) ) {
2019-06-10 20:16:09 +00:00
variant . outputs . each { output - >
// Assigns the new version code to versionCodeOverride, which changes the version code
// for only the output APK, not for the variant itself. Skipping this step simply
// causes Gradle to use the value of variant.versionCode for the APK.
// For more, see https://developer.android.com/studio/build/configure-apk-splits
def abiVersionCode = ABI_VERSION . get ( output . getFilter ( OutputFile . ABI ) )
if ( abiVersionCode ! = null ) {
output . versionCodeOverride =
abiVersionCode * 1000 + variant . versionCode
}
}
}
2019-09-27 17:53:37 +00:00
String variantBuildMode = buildModeFor ( variant . buildType )
2019-11-19 19:26:07 +00:00
String taskName = toCammelCase ( [ "compile" , FLUTTER_BUILD_PREFIX , variant . name ] )
FlutterTask compileTask = project . tasks . create ( name: taskName , type: FlutterTask ) {
flutterRoot this . flutterRoot
flutterExecutable this . flutterExecutable
buildMode variantBuildMode
localEngine this . localEngine
localEngineSrcPath this . localEngineSrcPath
2020-12-02 03:01:09 +00:00
targetPath getFlutterTarget ( )
2019-11-19 19:26:07 +00:00
verbose isVerbose ( )
2019-12-10 18:26:14 +00:00
fastStart isFastStart ( )
2019-11-19 19:26:07 +00:00
fileSystemRoots fileSystemRootsValue
fileSystemScheme fileSystemSchemeValue
trackWidgetCreation trackWidgetCreationValue
targetPlatformValues = targetPlatforms
2020-12-02 03:01:09 +00:00
sourceDir getFlutterSourceDirectory ( )
2019-11-19 19:26:07 +00:00
intermediateDir project . file ( "${project.buildDir}/${AndroidProject.FD_INTERMEDIATES}/flutter/${variant.name}/" )
extraFrontEndOptions extraFrontEndOptionsValue
extraGenSnapshotOptions extraGenSnapshotOptionsValue
2020-02-06 01:45:24 +00:00
splitDebugInfo splitDebugInfoValue
2020-02-05 04:34:24 +00:00
treeShakeIcons treeShakeIconsOptionsValue
2020-02-27 16:58:33 +00:00
dartObfuscation dartObfuscationValue
2020-03-06 22:53:36 +00:00
dartDefines dartDefinesValue
2020-04-30 20:39:08 +00:00
bundleSkSLPath bundleSkSLPathValue
2020-05-01 22:34:28 +00:00
performanceMeasurementFile performanceMeasurementFileValue
[flutter_tools] support code size tooling on iOS, linux, windows, macOS, and Android on Windows (#63610)
Adds support for size analysis on iOS, macOS, linux, and Windows - using an uncompressed directory based approach. The output format is not currently specified.
Adds support for size analysis on android on windows, switching to package:archive
Updates the console format to display as a tree, allowing longer paths. Increases the number of dart libraries shown (to avoid only ever printing the flutter/dart:ui libraries, which dominate the size)
2020-08-25 17:00:24 +00:00
codeSizeDirectory codeSizeDirectoryValue
2020-02-17 03:15:52 +00:00
doLast {
project . exec {
if ( Os . isFamily ( Os . FAMILY_WINDOWS ) ) {
2020-02-23 00:06:01 +00:00
commandLine ( 'cmd' , '/c' , "attrib -r ${assetsDirectory}/* /s" )
2020-02-17 03:15:52 +00:00
} else {
commandLine ( 'chmod' , '-R' , 'u+w' , assetsDirectory )
}
}
}
2019-05-20 20:09:20 +00:00
}
2019-09-27 17:53:37 +00:00
File libJar = project . file ( "${project.buildDir}/${AndroidProject.FD_INTERMEDIATES}/flutter/${variant.name}/libs.jar" )
2019-09-17 15:19:33 +00:00
Task packFlutterAppAotTask = project . tasks . create ( name: "packLibs${FLUTTER_BUILD_PREFIX}${variant.name.capitalize()}" , type: Jar ) {
2019-05-20 20:09:20 +00:00
destinationDir libJar . parentFile
archiveName libJar . name
2019-11-19 19:26:07 +00:00
dependsOn compileTask
targetPlatforms . each { targetPlatform - >
String abi = PLATFORM_ARCH_MAP [ targetPlatform ]
from ( "${compileTask.intermediateDir}/${abi}" ) {
include "*.so"
2019-09-17 15:19:33 +00:00
// Move `app.so` to `lib/<abi>/libapp.so`
2019-06-10 20:16:09 +00:00
rename { String filename - >
2019-11-19 19:26:07 +00:00
return "lib/${abi}/lib${filename}"
2019-05-20 20:09:20 +00:00
}
}
}
2017-01-31 22:48:48 +00:00
}
2019-06-19 05:37:42 +00:00
addApiDependencies ( project , variant . name , project . files {
2019-09-17 15:19:33 +00:00
packFlutterAppAotTask
2019-06-13 23:05:28 +00:00
} )
2019-10-09 23:29:20 +00:00
// We build an AAR when this property is defined.
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.
2018-10-09 17:40:03 +00:00
Task packageAssets = project . tasks . findByPath ( ":flutter:package${variant.name.capitalize()}Assets" )
Task cleanPackageAssets = project . tasks . findByPath ( ":flutter:cleanPackage${variant.name.capitalize()}Assets" )
2019-10-09 23:29:20 +00:00
boolean isUsedAsSubproject = packageAssets & & cleanPackageAssets & & ! isBuildingAar
Task copyFlutterAssetsTask = project . tasks . create (
name: "copyFlutterAssets${variant.name.capitalize()}" ,
type: Copy ,
) {
2019-11-19 19:26:07 +00:00
dependsOn compileTask
with compileTask . assets
2019-09-27 17:53:37 +00:00
if ( isUsedAsSubproject ) {
2019-01-18 00:33:14 +00:00
dependsOn packageAssets
dependsOn cleanPackageAssets
into packageAssets . outputDir
2019-09-27 17:53:37 +00:00
return
2019-01-18 00:33:14 +00:00
}
2019-09-27 17:53:37 +00:00
// `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 ) {
2019-10-09 23:29:20 +00:00
def variantOutput = variant . outputs . first ( )
def processResources = variantOutput . hasProperty ( "processResourcesProvider" ) ?
variantOutput . processResourcesProvider . get ( ) : variantOutput . processResources
processResources . dependsOn ( copyFlutterAssetsTask )
2016-03-12 00:30:56 +00:00
}
2020-12-02 03:01:09 +00:00
return copyFlutterAssetsTask
2016-03-12 00:30:56 +00:00
}
2021-01-13 22:09:04 +00:00
if ( isFlutterAppProject ( ) ) {
2020-04-01 17:03:56 +00:00
project . android . applicationVariants . all { variant - >
2020-12-02 03:01:09 +00:00
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 )
2020-04-01 17:03:56 +00:00
// Copy the output APKs into a known location, so `flutter run` or `flutter build apk`
// can discover them. By default, this is `<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"
}
}
}
}
}
2020-12-02 03:01:09 +00:00
configurePlugins ( )
return
}
// Flutter host module project (Add-to-app).
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 | relese |
// | 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 )
}
}
2018-04-06 11:11:47 +00:00
}
2019-09-17 15:19:33 +00:00
configurePlugins ( )
2016-03-12 00:30:56 +00:00
}
}
class FlutterExtension {
String source
2016-06-07 20:05:42 +00:00
String target
2016-03-12 00:30:56 +00:00
}
2017-05-05 12:53:51 +00:00
abstract class BaseFlutterTask extends DefaultTask {
2016-06-06 19:56:04 +00:00
File flutterRoot
2017-02-16 22:17:09 +00:00
File flutterExecutable
2016-06-06 19:56:04 +00:00
String buildMode
2020-01-25 19:13:03 +00:00
@Optional @Input
2016-06-06 19:56:04 +00:00
String localEngine
2020-01-25 19:13:03 +00:00
@Optional @Input
2017-02-23 13:56:19 +00:00
String localEngineSrcPath
2017-02-23 14:09:05 +00:00
@Input
2019-12-10 18:26:14 +00:00
Boolean fastStart
@Input
2016-06-07 20:05:42 +00:00
String targetPath
2019-11-08 20:41:24 +00:00
@Optional
2018-06-06 20:43:32 +00:00
Boolean verbose
@Optional @Input
2018-03-17 19:47:40 +00:00
String [ ] fileSystemRoots
@Optional @Input
String fileSystemScheme
2018-10-17 14:39:20 +00:00
@Input
2018-02-12 18:44:31 +00:00
Boolean trackWidgetCreation
@Optional @Input
2019-11-19 19:26:07 +00:00
List < String > targetPlatformValues
2016-03-12 00:30:56 +00:00
File sourceDir
2017-05-05 12:53:51 +00:00
File intermediateDir
2017-10-03 19:55:53 +00:00
@Optional @Input
String extraFrontEndOptions
@Optional @Input
String extraGenSnapshotOptions
2020-02-05 04:34:24 +00:00
@Optional @Input
2020-02-06 01:45:24 +00:00
String splitDebugInfo
@Optional @Input
2020-02-05 04:34:24 +00:00
Boolean treeShakeIcons
2020-02-27 16:58:33 +00:00
@Optional @Input
Boolean dartObfuscation
2020-03-06 22:53:36 +00:00
@Optional @Input
String dartDefines
2020-04-30 20:39:08 +00:00
@Optional @Input
String bundleSkSLPath
[flutter_tools] support code size tooling on iOS, linux, windows, macOS, and Android on Windows (#63610)
Adds support for size analysis on iOS, macOS, linux, and Windows - using an uncompressed directory based approach. The output format is not currently specified.
Adds support for size analysis on android on windows, switching to package:archive
Updates the console format to display as a tree, allowing longer paths. Increases the number of dart libraries shown (to avoid only ever printing the flutter/dart:ui libraries, which dominate the size)
2020-08-25 17:00:24 +00:00
@Optional @Input
String codeSizeDirectory ;
2020-05-01 22:34:28 +00:00
String performanceMeasurementFile ;
2017-05-05 12:53:51 +00:00
Include kernel_compile.d in Gradle depfiles (#17175)
This updates the Android build to declare the kernel compile depfile as
an output and its contents as inputs when running with --preview-dart-2
(the default mode).
The 'flutter build aot' command behaves differently depending on whether
it's running in Dart 1 or Dart 2 mode:
* Dart 1: the entrypoint Dart file (typically main.dart) is passed
directly to gen_snapshot, which then emits snapshot.d, whose contents
list the transitive closure of Dart dependencies (input files) for the
snapshot. snapshot.d is a declared output, its contents (plus
gen_snapshot itself) constitute the set of input files to the Gradle
build action.
* Dart 2: then entrypoint Dart file (typically main.dart) is first
compiled with the Dart kernel frontend. This emits kernel_compile.d,
whose contents list the transitive closure of Dart dependencies (input
files) for the kernel 'dill' output file. This 'dill' file is then
passed to gen_snapshot, which emits snapshot.d, whose contents are
empty. As of this change, both snapshot.d and kernel_compile.d are
declared outputs, and their contents (plus gen_snapshot and the
frontend compiler themselves) constitute the set of input files to the
Gradle build action.
This fixes a bug wherein profile/release AOT outputs were not
invalidated due to snapshot.d being empty, and kernel_compile.d being
ignored. This was introduced during recent refactoring of the AOT build
code, wherein the kernel compile and gen_snapshot actions were changed
to emit independent depfiles (previously one stomped -- or failed to --
on the other's output).
2018-05-02 01:11:57 +00:00
@OutputFiles
FileCollection getDependenciesFiles ( ) {
2018-08-16 15:47:20 +00:00
FileCollection depfiles = project . files ( )
2018-09-04 15:50:05 +00:00
2019-11-08 20:41:24 +00:00
// Includes all sources used in the flutter compilation.
depfiles + = project . files ( "${intermediateDir}/flutter_build.d" )
2018-06-15 18:53:30 +00:00
return depfiles
2017-05-05 12:53:51 +00:00
}
2018-04-12 08:12:26 +00:00
void buildBundle ( ) {
2017-05-05 12:53:51 +00:00
if ( ! sourceDir . isDirectory ( ) ) {
throw new GradleException ( "Invalid Flutter source directory: ${sourceDir}" )
}
intermediateDir . mkdirs ( )
2019-11-19 19:26:07 +00:00
// 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" ) {
2020-10-09 19:25:15 +00:00
ruleNames = [ "debug_android_application" ]
2019-11-19 19:26:07 +00:00
} else {
2019-12-10 18:26:14 +00:00
ruleNames = targetPlatformValues . collect { "android_aot_bundle_${buildMode}_$it" }
2019-11-19 19:26:07 +00:00
}
2017-05-05 12:53:51 +00:00
project . exec {
2020-04-08 02:42:57 +00:00
logging . captureStandardError LogLevel . ERROR
2017-05-05 12:53:51 +00:00
executable flutterExecutable . absolutePath
workingDir sourceDir
if ( localEngine ! = null ) {
args "--local-engine" , localEngine
args "--local-engine-src-path" , localEngineSrcPath
}
2018-06-06 20:43:32 +00:00
if ( verbose ) {
args "--verbose"
2019-11-08 20:41:24 +00:00
} else {
args "--quiet"
2018-06-06 20:43:32 +00:00
}
2019-11-08 20:41:24 +00:00
args "assemble"
args "--depfile" , "${intermediateDir}/flutter_build.d"
args "--output" , "${intermediateDir}"
2020-05-01 22:34:28 +00:00
if ( performanceMeasurementFile ! = null ) {
args "--performance-measurement-file=${performanceMeasurementFile}"
}
2019-12-10 18:26:14 +00:00
if ( ! fastStart | | buildMode ! = "debug" ) {
args "-dTargetFile=${targetPath}"
} else {
args "-dTargetFile=${Paths.get(flutterRoot.absolutePath, " examples ", " splash ", " lib ", " main . dart ")}"
}
2019-11-19 19:26:07 +00:00
args "-dTargetPlatform=android"
2019-11-08 20:41:24 +00:00
args "-dBuildMode=${buildMode}"
2020-05-04 18:22:15 +00:00
if ( trackWidgetCreation ! = null ) {
args "-dTrackWidgetCreation=${trackWidgetCreation}"
}
2020-02-06 01:45:24 +00:00
if ( splitDebugInfo ! = null ) {
args "-dSplitDebugInfo=${splitDebugInfo}"
}
2020-02-05 04:34:24 +00:00
if ( treeShakeIcons = = true ) {
args "-dTreeShakeIcons=true"
}
2020-02-27 16:58:33 +00:00
if ( dartObfuscation = = true ) {
args "-dDartObfuscation=true"
}
2020-03-06 22:53:36 +00:00
if ( dartDefines ! = null ) {
2020-04-16 17:56:49 +00:00
args "--DartDefines=${dartDefines}"
2020-03-06 22:53:36 +00:00
}
2020-04-30 20:39:08 +00:00
if ( bundleSkSLPath ! = null ) {
args "-iBundleSkSLPath=${bundleSkSLPath}"
}
[flutter_tools] support code size tooling on iOS, linux, windows, macOS, and Android on Windows (#63610)
Adds support for size analysis on iOS, macOS, linux, and Windows - using an uncompressed directory based approach. The output format is not currently specified.
Adds support for size analysis on android on windows, switching to package:archive
Updates the console format to display as a tree, allowing longer paths. Increases the number of dart libraries shown (to avoid only ever printing the flutter/dart:ui libraries, which dominate the size)
2020-08-25 17:00:24 +00:00
if ( codeSizeDirectory ! = null ) {
args "-dCodeSizeDirectory=${codeSizeDirectory}"
}
2018-06-15 18:53:30 +00:00
if ( extraGenSnapshotOptions ! = null ) {
2019-12-19 21:44:21 +00:00
args "--ExtraGenSnapshotOptions=${extraGenSnapshotOptions}"
2018-08-16 15:43:41 +00:00
}
2020-06-04 04:02:07 +00:00
if ( extraFrontEndOptions ! = null ) {
args "--ExtraFrontEndOptions=${extraFrontEndOptions}"
}
2019-11-19 19:26:07 +00:00
args ruleNames
2017-05-05 12:53:51 +00:00
}
}
}
class FlutterTask extends BaseFlutterTask {
2016-03-12 00:30:56 +00:00
@OutputDirectory
2017-05-05 12:53:51 +00:00
File getOutputDirectory ( ) {
return intermediateDir
}
2016-03-12 00:30:56 +00:00
2020-02-17 03:15:52 +00:00
String getAssetsDirectory ( ) {
return "${outputDirectory}/flutter_assets"
}
2016-06-06 19:56:04 +00:00
CopySpec getAssets ( ) {
return project . copySpec {
2017-12-14 16:27:25 +00:00
from "${intermediateDir}"
include "flutter_assets/**" // the working dir and its files
2019-05-20 20:09:20 +00:00
}
}
CopySpec getSnapshots ( ) {
return project . copySpec {
from "${intermediateDir}"
2018-01-15 02:24:07 +00:00
2018-10-09 20:04:06 +00:00
if ( buildMode = = 'release' | | buildMode = = 'profile' ) {
2019-11-19 19:26:07 +00:00
targetPlatformValues . each {
include "${PLATFORM_ARCH_MAP[targetArch]}/app.so"
}
2016-06-06 19:56:04 +00:00
}
2018-01-15 02:24:07 +00:00
}
2016-03-12 00:30:56 +00:00
}
2020-02-20 21:24:36 +00:00
FileCollection readDependencies ( File dependenciesFile , Boolean inputs ) {
2019-11-08 20:41:24 +00:00
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,
2020-02-20 21:24:36 +00:00
def matcher = depText . split ( ': ' ) [ inputs ? 1 : 0 ] = ~ /(\\ |[^\s])+/
2019-11-08 20:41:24 +00:00
// then we replace all escaped spaces with regular spaces
def depList = matcher . collect { it [ 0 ] . replaceAll ( "\\\\ " , " " ) }
return project . files ( depList )
}
return project . files ( ) ;
2017-03-14 11:49:30 +00:00
}
2017-01-31 22:48:48 +00:00
@InputFiles
FileCollection getSourceFiles ( ) {
Include kernel_compile.d in Gradle depfiles (#17175)
This updates the Android build to declare the kernel compile depfile as
an output and its contents as inputs when running with --preview-dart-2
(the default mode).
The 'flutter build aot' command behaves differently depending on whether
it's running in Dart 1 or Dart 2 mode:
* Dart 1: the entrypoint Dart file (typically main.dart) is passed
directly to gen_snapshot, which then emits snapshot.d, whose contents
list the transitive closure of Dart dependencies (input files) for the
snapshot. snapshot.d is a declared output, its contents (plus
gen_snapshot itself) constitute the set of input files to the Gradle
build action.
* Dart 2: then entrypoint Dart file (typically main.dart) is first
compiled with the Dart kernel frontend. This emits kernel_compile.d,
whose contents list the transitive closure of Dart dependencies (input
files) for the kernel 'dill' output file. This 'dill' file is then
passed to gen_snapshot, which emits snapshot.d, whose contents are
empty. As of this change, both snapshot.d and kernel_compile.d are
declared outputs, and their contents (plus gen_snapshot and the
frontend compiler themselves) constitute the set of input files to the
Gradle build action.
This fixes a bug wherein profile/release AOT outputs were not
invalidated due to snapshot.d being empty, and kernel_compile.d being
ignored. This was introduced during recent refactoring of the AOT build
code, wherein the kernel compile and gen_snapshot actions were changed
to emit independent depfiles (previously one stomped -- or failed to --
on the other's output).
2018-05-02 01:11:57 +00:00
FileCollection sources = project . files ( )
for ( File depfile in getDependenciesFiles ( ) ) {
2020-02-20 21:24:36 +00:00
sources + = readDependencies ( depfile , true )
Include kernel_compile.d in Gradle depfiles (#17175)
This updates the Android build to declare the kernel compile depfile as
an output and its contents as inputs when running with --preview-dart-2
(the default mode).
The 'flutter build aot' command behaves differently depending on whether
it's running in Dart 1 or Dart 2 mode:
* Dart 1: the entrypoint Dart file (typically main.dart) is passed
directly to gen_snapshot, which then emits snapshot.d, whose contents
list the transitive closure of Dart dependencies (input files) for the
snapshot. snapshot.d is a declared output, its contents (plus
gen_snapshot itself) constitute the set of input files to the Gradle
build action.
* Dart 2: then entrypoint Dart file (typically main.dart) is first
compiled with the Dart kernel frontend. This emits kernel_compile.d,
whose contents list the transitive closure of Dart dependencies (input
files) for the kernel 'dill' output file. This 'dill' file is then
passed to gen_snapshot, which emits snapshot.d, whose contents are
empty. As of this change, both snapshot.d and kernel_compile.d are
declared outputs, and their contents (plus gen_snapshot and the
frontend compiler themselves) constitute the set of input files to the
Gradle build action.
This fixes a bug wherein profile/release AOT outputs were not
invalidated due to snapshot.d being empty, and kernel_compile.d being
ignored. This was introduced during recent refactoring of the AOT build
code, wherein the kernel compile and gen_snapshot actions were changed
to emit independent depfiles (previously one stomped -- or failed to --
on the other's output).
2018-05-02 01:11:57 +00:00
}
2019-11-08 20:41:24 +00:00
return sources + project . files ( 'pubspec.yaml' )
2017-01-31 22:48:48 +00:00
}
2020-02-20 21:24:36 +00:00
@OutputFiles
FileCollection getOutputFiles ( ) {
FileCollection sources = project . files ( )
for ( File depfile in getDependenciesFiles ( ) ) {
sources + = readDependencies ( depfile , false )
}
return sources
}
2016-03-12 00:30:56 +00:00
@TaskAction
void build ( ) {
2018-04-12 08:12:26 +00:00
buildBundle ( )
2016-03-12 00:30:56 +00:00
}
}