Support for custom build types on Android (#11354)

This commit is contained in:
Mikkel Nygaard Ravn 2017-07-31 13:57:24 +02:00 committed by GitHub
parent 561d17a876
commit 87eec719e2
3 changed files with 174 additions and 26 deletions

View file

@ -0,0 +1,107 @@
// 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);
}
}

View file

@ -139,6 +139,12 @@ tasks:
stage: devicelab
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:
description: >
Same as flutter_gallery__transition_perf but uses Android instrumentation

View file

@ -17,12 +17,12 @@ import org.gradle.api.tasks.TaskAction
import org.gradle.api.tasks.bundling.Jar
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.2.3'
}
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.2.3'
}
}
apply plugin: FlutterPlugin
@ -35,6 +35,7 @@ class FlutterPlugin implements Plugin<Project> {
private Properties localProperties
private File flutterJar
private File flutterX86Jar
private File debugFlutterJar
private File profileFlutterJar
private File releaseFlutterJar
@ -119,7 +120,7 @@ class FlutterPlugin implements Plugin<Project> {
}
// 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) {
destinationDir flutterX86Jar.parentFile
archiveName flutterX86Jar.name
@ -130,12 +131,10 @@ class FlutterPlugin implements Plugin<Project> {
into "lib/x86_64"
}
}
project.dependencies {
debugCompile project.files(flutterX86Jar, debugFlutterJar)
profileCompile project.files(profileFlutterJar)
releaseCompile project.files(releaseFlutterJar)
}
// Add flutter.jar dependencies to all <buildType>Compile configurations, including custom ones
// added after applying the Flutter plugin.
project.android.buildTypes.each { addFlutterJarCompileDependency(project, it) }
project.android.buildTypes.whenObjectAdded { addFlutterJarCompileDependency(project, it) }
}
project.extensions.create("flutter", FlutterExtension)
@ -150,14 +149,14 @@ class FlutterPlugin implements Plugin<Project> {
project.dependencies {
compile pluginProject
}
pluginProject.afterEvaluate this.&addFlutterJarDependency
pluginProject.afterEvaluate this.&addFlutterJarProvidedDependency
} else {
project.logger.error("Plugin project :$name not found. Please update settings.gradle.")
}
}
}
private void addFlutterJarDependency(Project project) {
private void addFlutterJarProvidedDependency(Project project) {
project.dependencies {
if (flutterJar != null) {
provided project.files(flutterJar)
@ -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) {
if (project.flutter.source == null) {
throw new GradleException("Must provide Flutter source directory")
@ -181,24 +216,24 @@ class FlutterPlugin implements Plugin<Project> {
target = project.property('target')
}
if (project.tasks.findByName('flutterBuildX86Jar')) {
project.compileDebugJavaWithJavac.dependsOn project.flutterBuildX86Jar
}
File kernel
if (project.hasProperty('kernel')) {
kernel = project.file(project.property('kernel'))
}
project.android.applicationVariants.all { variant ->
if (!["debug", "profile", "release"].contains(variant.name)) {
throw new GradleException("Build variant must be one of \"debug\", \"profile\", or \"release\" but was \"${variant.name}\"")
if (project.tasks.findByName('flutterBuildX86Jar')) {
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
flutterExecutable this.flutterExecutable
buildMode variant.name
buildMode flutterBuildMode
localEngine this.localEngine
localEngineSrcPath this.localEngineSrcPath
targetPath target
@ -207,11 +242,11 @@ class FlutterPlugin implements Plugin<Project> {
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
flutterRoot this.flutterRoot
flutterExecutable this.flutterExecutable
buildMode variant.name
buildMode flutterBuildMode
localEngine this.localEngine
localEngineSrcPath this.localEngineSrcPath
targetPath target
@ -254,7 +289,7 @@ abstract class BaseFlutterTask extends DefaultTask {
if (buildMode != 'debug') {
return project.file("${intermediateDir}/snapshot.d")
}
return project.file("${intermediateDir}/snapshot_blob.bin.d")
return project.file("${intermediateDir}/snapshot_blob.bin.d")
}
void buildFlx() {