Commit 87eec719 authored by Mikkel Nygaard Ravn's avatar Mikkel Nygaard Ravn Committed by GitHub

Support for custom build types on Android (#11354)

parent 561d17a8
// Copyright (c) 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.
import 'dart:async';
import 'dart:io';
import 'package:path/path.dart' as path;
import 'package:flutter_devicelab/framework/framework.dart';
import 'package:flutter_devicelab/framework/utils.dart';
void main() {
task(() async {
section('Setting up flutter project');
final Directory tmp = await Directory.systemTemp.createTemp('gradle');
final FlutterProject project = await FlutterProject.create(tmp, 'hello');
section('gradlew assembleDebug');
await project.runGradleTask('assembleDebug');
section('gradlew assembleProfile');
await project.runGradleTask('assembleProfile');
section('gradlew assembleRelease');
await project.runGradleTask('assembleRelease');
section('gradlew assembleLocal (custom debug build)');
await project.addCustomBuildType('local', initWith: 'debug');
await project.runGradleTask('assembleLocal');
section('gradlew assembleBeta (custom release build)');
await project.addCustomBuildType('beta', initWith: 'release');
await project.runGradleTask('assembleBeta');
section('gradlew assembleFreeDebug (product flavor)');
await project.addProductFlavor('free');
await project.runGradleTask('assembleFreeDebug');
await project.parent.delete(recursive: true);
return new TaskResult.success(null);
});
}
class FlutterProject {
FlutterProject(this.parent, this.name);
Directory parent;
String name;
static Future<FlutterProject> create(Directory directory, String name) async {
await inDirectory(directory, () async {
await flutter('create', options: <String>[name]);
});
return new FlutterProject(directory, name);
}
String get rootPath => path.join(parent.path, name);
String get androidPath => path.join(rootPath, 'android');
Future<Null> addCustomBuildType(String name, {String initWith}) async {
final File buildScript = new File(
path.join(androidPath, 'app', 'build.gradle'),
);
buildScript.openWrite(mode: FileMode.APPEND).write('''
android {
buildTypes {
$name {
initWith $initWith
}
}
}
''');
}
Future<Null> addProductFlavor(String name) async {
final File buildScript = new File(
path.join(androidPath, 'app', 'build.gradle'),
);
buildScript.openWrite(mode: FileMode.APPEND).write('''
android {
productFlavors {
$name {
applicationIdSuffix ".$name"
versionNameSuffix "-$name"
}
}
}
''');
}
Future<Null> runGradleTask(String task) async {
final ProcessResult result = await Process.run(
'./gradlew',
<String>['-q', 'app:$task'],
workingDirectory: androidPath,
);
if (result.exitCode != 0) {
print('stdout:');
print(result.stdout);
print('stderr:');
print(result.stderr);
}
assert(result.exitCode == 0);
}
}
...@@ -139,6 +139,12 @@ tasks: ...@@ -139,6 +139,12 @@ tasks:
stage: devicelab stage: devicelab
required_agent_capabilities: ["linux/android"] required_agent_capabilities: ["linux/android"]
gradle_plugin_test:
description: >
Verifies that the Flutter Gradle plugin supports standard and custom Android build types.
stage: devicelab
required_agent_capabilities: ["linux/android"]
flutter_gallery_instrumentation_test: flutter_gallery_instrumentation_test:
description: > description: >
Same as flutter_gallery__transition_perf but uses Android instrumentation Same as flutter_gallery__transition_perf but uses Android instrumentation
......
...@@ -17,12 +17,12 @@ import org.gradle.api.tasks.TaskAction ...@@ -17,12 +17,12 @@ import org.gradle.api.tasks.TaskAction
import org.gradle.api.tasks.bundling.Jar import org.gradle.api.tasks.bundling.Jar
buildscript { buildscript {
repositories { repositories {
jcenter() jcenter()
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:2.2.3' classpath 'com.android.tools.build:gradle:2.2.3'
} }
} }
apply plugin: FlutterPlugin apply plugin: FlutterPlugin
...@@ -35,6 +35,7 @@ class FlutterPlugin implements Plugin<Project> { ...@@ -35,6 +35,7 @@ class FlutterPlugin implements Plugin<Project> {
private Properties localProperties private Properties localProperties
private File flutterJar private File flutterJar
private File flutterX86Jar
private File debugFlutterJar private File debugFlutterJar
private File profileFlutterJar private File profileFlutterJar
private File releaseFlutterJar private File releaseFlutterJar
...@@ -119,7 +120,7 @@ class FlutterPlugin implements Plugin<Project> { ...@@ -119,7 +120,7 @@ class FlutterPlugin implements Plugin<Project> {
} }
// Add x86/x86_64 native library. Debug mode only, for now. // Add x86/x86_64 native library. Debug mode only, for now.
File flutterX86Jar = project.file("${project.buildDir}/${AndroidProject.FD_INTERMEDIATES}/flutter/flutter-x86.jar") flutterX86Jar = project.file("${project.buildDir}/${AndroidProject.FD_INTERMEDIATES}/flutter/flutter-x86.jar")
project.tasks.create("flutterBuildX86Jar", Jar) { project.tasks.create("flutterBuildX86Jar", Jar) {
destinationDir flutterX86Jar.parentFile destinationDir flutterX86Jar.parentFile
archiveName flutterX86Jar.name archiveName flutterX86Jar.name
...@@ -130,12 +131,10 @@ class FlutterPlugin implements Plugin<Project> { ...@@ -130,12 +131,10 @@ class FlutterPlugin implements Plugin<Project> {
into "lib/x86_64" into "lib/x86_64"
} }
} }
// Add flutter.jar dependencies to all <buildType>Compile configurations, including custom ones
project.dependencies { // added after applying the Flutter plugin.
debugCompile project.files(flutterX86Jar, debugFlutterJar) project.android.buildTypes.each { addFlutterJarCompileDependency(project, it) }
profileCompile project.files(profileFlutterJar) project.android.buildTypes.whenObjectAdded { addFlutterJarCompileDependency(project, it) }
releaseCompile project.files(releaseFlutterJar)
}
} }
project.extensions.create("flutter", FlutterExtension) project.extensions.create("flutter", FlutterExtension)
...@@ -150,14 +149,14 @@ class FlutterPlugin implements Plugin<Project> { ...@@ -150,14 +149,14 @@ class FlutterPlugin implements Plugin<Project> {
project.dependencies { project.dependencies {
compile pluginProject compile pluginProject
} }
pluginProject.afterEvaluate this.&addFlutterJarDependency pluginProject.afterEvaluate this.&addFlutterJarProvidedDependency
} else { } else {
project.logger.error("Plugin project :$name not found. Please update settings.gradle.") project.logger.error("Plugin project :$name not found. Please update settings.gradle.")
} }
} }
} }
private void addFlutterJarDependency(Project project) { private void addFlutterJarProvidedDependency(Project project) {
project.dependencies { project.dependencies {
if (flutterJar != null) { if (flutterJar != null) {
provided project.files(flutterJar) provided project.files(flutterJar)
...@@ -168,6 +167,42 @@ class FlutterPlugin implements Plugin<Project> { ...@@ -168,6 +167,42 @@ class FlutterPlugin implements Plugin<Project> {
} }
} }
/**
* Adds suitable flutter.jar compile dependencies to the specified buildType.
*
* Note: The BuildType DSL type is not public, and is therefore omitted from the signature.
*/
private void addFlutterJarCompileDependency(Project project, buildType) {
project.dependencies {
add(buildType.name + "Compile", project.files {
String buildMode = buildModeFor(buildType)
if (buildMode == "debug") {
[flutterX86Jar, debugFlutterJar]
} else if (buildMode == "profile") {
profileFlutterJar
} else {
releaseFlutterJar
}
})
}
}
/**
* 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.
*
* @return "debug", "profile", or "release" (fall-back).
*/
private static String buildModeFor(buildType) {
if (buildType.name == "profile") {
return "profile"
} else if (buildType.debuggable) {
return "debug"
}
return "release"
}
private void addFlutterTask(Project project) { private void addFlutterTask(Project project) {
if (project.flutter.source == null) { if (project.flutter.source == null) {
throw new GradleException("Must provide Flutter source directory") throw new GradleException("Must provide Flutter source directory")
...@@ -181,24 +216,24 @@ class FlutterPlugin implements Plugin<Project> { ...@@ -181,24 +216,24 @@ class FlutterPlugin implements Plugin<Project> {
target = project.property('target') target = project.property('target')
} }
if (project.tasks.findByName('flutterBuildX86Jar')) {
project.compileDebugJavaWithJavac.dependsOn project.flutterBuildX86Jar
}
File kernel File kernel
if (project.hasProperty('kernel')) { if (project.hasProperty('kernel')) {
kernel = project.file(project.property('kernel')) kernel = project.file(project.property('kernel'))
} }
project.android.applicationVariants.all { variant -> project.android.applicationVariants.all { variant ->
if (!["debug", "profile", "release"].contains(variant.name)) { if (project.tasks.findByName('flutterBuildX86Jar')) {
throw new GradleException("Build variant must be one of \"debug\", \"profile\", or \"release\" but was \"${variant.name}\"") Task task = project.tasks.findByName("compile${variant.name.capitalize()}JavaWithJavac")
if (task) {
task.dependsOn project.flutterBuildX86Jar
}
} }
GenerateDependencies dependenciesTask = project.tasks.create("flutterDependencies${variant.name.capitalize()}", GenerateDependencies) { String flutterBuildMode = buildModeFor(variant.buildType)
GenerateDependencies dependenciesTask = project.tasks.create(name: "flutterDependencies${variant.name.capitalize()}", type: GenerateDependencies) {
flutterRoot this.flutterRoot flutterRoot this.flutterRoot
flutterExecutable this.flutterExecutable flutterExecutable this.flutterExecutable
buildMode variant.name buildMode flutterBuildMode
localEngine this.localEngine localEngine this.localEngine
localEngineSrcPath this.localEngineSrcPath localEngineSrcPath this.localEngineSrcPath
targetPath target targetPath target
...@@ -207,11 +242,11 @@ class FlutterPlugin implements Plugin<Project> { ...@@ -207,11 +242,11 @@ class FlutterPlugin implements Plugin<Project> {
intermediateDir project.file("${project.buildDir}/${AndroidProject.FD_INTERMEDIATES}/flutter/${variant.name}") intermediateDir project.file("${project.buildDir}/${AndroidProject.FD_INTERMEDIATES}/flutter/${variant.name}")
} }
FlutterTask flutterTask = project.tasks.create("flutterBuild${variant.name.capitalize()}", FlutterTask) { FlutterTask flutterTask = project.tasks.create(name: "flutterBuild${variant.name.capitalize()}", type: FlutterTask) {
dependsOn dependenciesTask dependsOn dependenciesTask
flutterRoot this.flutterRoot flutterRoot this.flutterRoot
flutterExecutable this.flutterExecutable flutterExecutable this.flutterExecutable
buildMode variant.name buildMode flutterBuildMode
localEngine this.localEngine localEngine this.localEngine
localEngineSrcPath this.localEngineSrcPath localEngineSrcPath this.localEngineSrcPath
targetPath target targetPath target
...@@ -254,7 +289,7 @@ abstract class BaseFlutterTask extends DefaultTask { ...@@ -254,7 +289,7 @@ abstract class BaseFlutterTask extends DefaultTask {
if (buildMode != 'debug') { if (buildMode != 'debug') {
return project.file("${intermediateDir}/snapshot.d") return project.file("${intermediateDir}/snapshot.d")
} }
return project.file("${intermediateDir}/snapshot_blob.bin.d") return project.file("${intermediateDir}/snapshot_blob.bin.d")
} }
void buildFlx() { void buildFlx() {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment