mirror of
https://github.com/flutter/flutter
synced 2024-09-19 16:21:58 +00:00
Improve Android builds. (#9801)
Eagerly generate local.properties, and always update the flutter.sdk setting in it, in case FLUTTER_ROOT has changed. Fixes #8365. Fixes #9716 - at least the specific issue reported. My Android Studio still complains about Gradle versions - it ships with v3.2, but requires v3.3... Add a 'generate dependencies' task to the Gradle build, which checks if the snapshot dependencies file exists, and runs an extra build before the actual FlutterTask if it doesn't. This makes the first build slower, but sub-sequent builds (without source changes) much faster. Fixes #9717.
This commit is contained in:
parent
4bbf158b6a
commit
6b54137a15
|
@ -194,7 +194,20 @@ class FlutterPlugin implements Plugin<Project> {
|
|||
throw new GradleException("Build variant must be one of \"debug\", \"profile\", or \"release\" but was \"${variant.name}\"")
|
||||
}
|
||||
|
||||
GenerateDependencies dependenciesTask = project.tasks.create("flutterDependencies${variant.name.capitalize()}", GenerateDependencies) {
|
||||
flutterRoot this.flutterRoot
|
||||
flutterExecutable this.flutterExecutable
|
||||
buildMode variant.name
|
||||
localEngine this.localEngine
|
||||
localEngineSrcPath this.localEngineSrcPath
|
||||
targetPath target
|
||||
kernelFile kernel
|
||||
sourceDir project.file(project.flutter.source)
|
||||
intermediateDir project.file("${project.buildDir}/${AndroidProject.FD_INTERMEDIATES}/flutter/${variant.name}")
|
||||
}
|
||||
|
||||
FlutterTask flutterTask = project.tasks.create("flutterBuild${variant.name.capitalize()}", FlutterTask) {
|
||||
dependsOn dependenciesTask
|
||||
flutterRoot this.flutterRoot
|
||||
flutterExecutable this.flutterExecutable
|
||||
buildMode variant.name
|
||||
|
@ -222,7 +235,7 @@ class FlutterExtension {
|
|||
String target
|
||||
}
|
||||
|
||||
class FlutterTask extends DefaultTask {
|
||||
abstract class BaseFlutterTask extends DefaultTask {
|
||||
File flutterRoot
|
||||
File flutterExecutable
|
||||
String buildMode
|
||||
|
@ -232,67 +245,18 @@ class FlutterTask extends DefaultTask {
|
|||
String targetPath
|
||||
@Optional @InputFile
|
||||
File kernelFile
|
||||
|
||||
File sourceDir
|
||||
|
||||
@OutputDirectory
|
||||
File intermediateDir
|
||||
|
||||
CopySpec getAssets() {
|
||||
return project.copySpec {
|
||||
from "${intermediateDir}/app.flx"
|
||||
if (buildMode != 'debug') {
|
||||
from "${intermediateDir}/vm_snapshot_data"
|
||||
from "${intermediateDir}/vm_snapshot_instr"
|
||||
from "${intermediateDir}/isolate_snapshot_data"
|
||||
from "${intermediateDir}/isolate_snapshot_instr"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FileCollection readDependencies(File dependenciesFile) {
|
||||
if (dependenciesFile.exists()) {
|
||||
try {
|
||||
// Dependencies file has Makefile syntax:
|
||||
// <target> <files>: <source> <files> <separated> <by> <space>
|
||||
String depText = dependenciesFile.text
|
||||
return project.files(depText.split(': ')[1].split())
|
||||
} catch (Exception e) {
|
||||
logger.error("Error reading dependency file ${dependenciesFile}: ${e}")
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
@InputFiles
|
||||
FileCollection getSourceFiles() {
|
||||
File dependenciesFile
|
||||
@OutputFile
|
||||
File getDependenciesFile() {
|
||||
if (buildMode != 'debug') {
|
||||
dependenciesFile = project.file("${intermediateDir}/snapshot.d")
|
||||
} else {
|
||||
dependenciesFile = project.file("${intermediateDir}/snapshot_blob.bin.d")
|
||||
return project.file("${intermediateDir}/snapshot.d")
|
||||
}
|
||||
FileCollection sources = readDependencies(dependenciesFile)
|
||||
if (sources != null) {
|
||||
// We have a dependencies file. Add a dependency on gen_snapshot as well, since the
|
||||
// snapshots have to be rebuilt if it changes.
|
||||
FileCollection snapshotter = readDependencies(project.file("${intermediateDir}/gen_snapshot.d"))
|
||||
if (snapshotter != null) {
|
||||
sources = sources.plus(snapshotter)
|
||||
}
|
||||
// Finally, add a dependency on pubspec.yaml as well.
|
||||
return sources.plus(project.files('pubspec.yaml'))
|
||||
}
|
||||
// No dependencies file (or problems parsing it). Fall back to source files.
|
||||
return project.fileTree(
|
||||
dir: sourceDir,
|
||||
exclude: ['android', 'ios'],
|
||||
include: ['**/*.dart', 'pubspec.yaml']
|
||||
)
|
||||
return project.file("${intermediateDir}/snapshot_blob.bin.d")
|
||||
}
|
||||
|
||||
@TaskAction
|
||||
void build() {
|
||||
void buildFlx() {
|
||||
if (!sourceDir.isDirectory()) {
|
||||
throw new GradleException("Invalid Flutter source directory: ${sourceDir}")
|
||||
}
|
||||
|
@ -339,3 +303,73 @@ class FlutterTask extends DefaultTask {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
class GenerateDependencies extends BaseFlutterTask {
|
||||
@TaskAction
|
||||
void build() {
|
||||
File dependenciesFile = getDependenciesFile();
|
||||
if (!dependenciesFile.exists()) {
|
||||
buildFlx()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class FlutterTask extends BaseFlutterTask {
|
||||
@OutputDirectory
|
||||
File getOutputDirectory() {
|
||||
return intermediateDir
|
||||
}
|
||||
|
||||
CopySpec getAssets() {
|
||||
return project.copySpec {
|
||||
from "${intermediateDir}/app.flx"
|
||||
if (buildMode != 'debug') {
|
||||
from "${intermediateDir}/vm_snapshot_data"
|
||||
from "${intermediateDir}/vm_snapshot_instr"
|
||||
from "${intermediateDir}/isolate_snapshot_data"
|
||||
from "${intermediateDir}/isolate_snapshot_instr"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FileCollection readDependencies(File dependenciesFile) {
|
||||
if (dependenciesFile.exists()) {
|
||||
try {
|
||||
// Dependencies file has Makefile syntax:
|
||||
// <target> <files>: <source> <files> <separated> <by> <space>
|
||||
String depText = dependenciesFile.text
|
||||
return project.files(depText.split(': ')[1].split())
|
||||
} catch (Exception e) {
|
||||
logger.error("Error reading dependency file ${dependenciesFile}: ${e}")
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
@InputFiles
|
||||
FileCollection getSourceFiles() {
|
||||
File dependenciesFile = getDependenciesFile()
|
||||
FileCollection sources = readDependencies(dependenciesFile)
|
||||
if (sources != null) {
|
||||
// We have a dependencies file. Add a dependency on gen_snapshot as well, since the
|
||||
// snapshots have to be rebuilt if it changes.
|
||||
FileCollection snapshotter = readDependencies(project.file("${intermediateDir}/gen_snapshot.d"))
|
||||
if (snapshotter != null) {
|
||||
sources = sources.plus(snapshotter)
|
||||
}
|
||||
// Finally, add a dependency on pubspec.yaml as well.
|
||||
return sources.plus(project.files('pubspec.yaml'))
|
||||
}
|
||||
// No dependencies file (or problems parsing it). Fall back to source files.
|
||||
return project.fileTree(
|
||||
dir: sourceDir,
|
||||
exclude: ['android', 'ios'],
|
||||
include: ['**/*.dart', 'pubspec.yaml']
|
||||
)
|
||||
}
|
||||
|
||||
@TaskAction
|
||||
void build() {
|
||||
buildFlx()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -78,7 +78,7 @@ String getGradleAppOutDirV2() {
|
|||
// Note: this call takes about a second to complete.
|
||||
String _calculateGradleAppOutDirV2() {
|
||||
final String gradle = ensureGradle();
|
||||
ensureLocalProperties();
|
||||
updateLocalProperties();
|
||||
try {
|
||||
final String properties = runCheckedSync(
|
||||
<String>[gradle, 'app:properties'],
|
||||
|
@ -141,28 +141,42 @@ String ensureGradle() {
|
|||
return gradle;
|
||||
}
|
||||
|
||||
/// Create android/local.properties if needed.
|
||||
File ensureLocalProperties() {
|
||||
final File localProperties = fs.file('android/local.properties');
|
||||
if (!localProperties.existsSync()) {
|
||||
localProperties.writeAsStringSync(
|
||||
'sdk.dir=${escapePath(androidSdk.directory)}\n'
|
||||
'flutter.sdk=${escapePath(Cache.flutterRoot)}\n'
|
||||
);
|
||||
/// Create android/local.properties if needed, and update Flutter settings.
|
||||
void updateLocalProperties({String projectPath, String buildMode}) {
|
||||
final File localProperties = (projectPath == null)
|
||||
? fs.file(fs.path.join('android', 'local.properties'))
|
||||
: fs.file(fs.path.join(projectPath, 'android', 'local.properties'));
|
||||
bool changed = false;
|
||||
|
||||
SettingsFile settings;
|
||||
if (localProperties.existsSync()) {
|
||||
settings = new SettingsFile.parseFromFile(localProperties);
|
||||
} else {
|
||||
settings = new SettingsFile();
|
||||
settings.values['sdk.dir'] = escapePath(androidSdk.directory);
|
||||
changed = true;
|
||||
}
|
||||
return localProperties;
|
||||
final String escapedRoot = escapePath(Cache.flutterRoot);
|
||||
if (changed || settings.values['flutter.sdk'] != escapedRoot) {
|
||||
settings.values['flutter.sdk'] = escapedRoot;
|
||||
changed = true;
|
||||
}
|
||||
if (buildMode != null && settings.values['flutter.buildMode'] != buildMode) {
|
||||
settings.values['flutter.buildMode'] = buildMode;
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (changed)
|
||||
settings.writeContents(localProperties);
|
||||
}
|
||||
|
||||
Future<Null> buildGradleProject(BuildMode buildMode, String target, String kernelPath) async {
|
||||
final File localProperties = ensureLocalProperties();
|
||||
// Update the local.properties file with the build mode.
|
||||
// FlutterPlugin v1 reads local.properties to determine build mode. Plugin v2
|
||||
// uses the standard Android way to determine what to build, but we still
|
||||
// update local.properties, in case we want to use it in the future.
|
||||
final String buildModeName = getModeName(buildMode);
|
||||
final SettingsFile settings = new SettingsFile.parseFromFile(localProperties);
|
||||
settings.values['flutter.buildMode'] = buildModeName;
|
||||
settings.writeContents(localProperties);
|
||||
updateLocalProperties(buildMode: buildModeName);
|
||||
|
||||
injectPlugins();
|
||||
|
||||
|
|
|
@ -151,6 +151,8 @@ class ItemListNotifier<T> {
|
|||
}
|
||||
|
||||
class SettingsFile {
|
||||
SettingsFile();
|
||||
|
||||
SettingsFile.parse(String contents) {
|
||||
for (String line in contents.split('\n')) {
|
||||
line = line.trim();
|
||||
|
|
|
@ -6,6 +6,7 @@ import 'dart:async';
|
|||
|
||||
import '../android/android.dart' as android;
|
||||
import '../android/android_sdk.dart' as android_sdk;
|
||||
import '../android/gradle.dart' as gradle;
|
||||
import '../base/common.dart';
|
||||
import '../base/file_system.dart';
|
||||
import '../base/utils.dart';
|
||||
|
@ -121,6 +122,9 @@ class CreateCommand extends FlutterCommand {
|
|||
if (argResults['pub'])
|
||||
await pubGet(directory: dirPath);
|
||||
|
||||
if (android_sdk.androidSdk != null)
|
||||
gradle.updateLocalProperties(projectPath: dirPath);
|
||||
|
||||
appPath = fs.path.join(dirPath, 'example');
|
||||
final String androidPluginIdentifier = templateContext['androidIdentifier'];
|
||||
final String exampleProjectName = projectName + '_example';
|
||||
|
@ -153,6 +157,9 @@ class CreateCommand extends FlutterCommand {
|
|||
injectPlugins(directory: appPath);
|
||||
}
|
||||
|
||||
if (android_sdk.androidSdk != null)
|
||||
gradle.updateLocalProperties(projectPath: appPath);
|
||||
|
||||
printStatus('');
|
||||
|
||||
// Run doctor; tell the user the next steps.
|
||||
|
|
Loading…
Reference in a new issue