Revert "Revert "Use FlutterProject to locate files (#18913)" (#19409)" (#19456)
With a fix of a path being printed relative instead of absolute.
diff --git a/packages/flutter_tools/lib/src/android/android_device.dart b/packages/flutter_tools/lib/src/android/android_device.dart
index 65fb6ab..c69d947 100644
--- a/packages/flutter_tools/lib/src/android/android_device.dart
+++ b/packages/flutter_tools/lib/src/android/android_device.dart
@@ -21,6 +21,7 @@
import '../build_info.dart';
import '../device.dart';
import '../globals.dart';
+import '../project.dart';
import '../protocol_discovery.dart';
import 'adb.dart';
@@ -241,7 +242,7 @@
String _getSourceSha1(ApplicationPackage app) {
final AndroidApk apk = app;
- final File shaFile = fs.file('${apk.apkPath}.sha1');
+ final File shaFile = fs.file('${apk.file.path}.sha1');
return shaFile.existsSync() ? shaFile.readAsStringSync() : '';
}
@@ -269,16 +270,16 @@
@override
Future<bool> installApp(ApplicationPackage app) async {
final AndroidApk apk = app;
- if (!fs.isFileSync(apk.apkPath)) {
- printError('"${apk.apkPath}" does not exist.');
+ if (!apk.file.existsSync()) {
+ printError('"${fs.path.relative(apk.file.path)}" does not exist.');
return false;
}
if (!await _checkForSupportedAdbVersion() || !await _checkForSupportedAndroidVersion())
return false;
- final Status status = logger.startProgress('Installing ${apk.apkPath}...', expectSlowOperation: true);
- final RunResult installResult = await runAsync(adbCommandForDevice(<String>['install', '-t', '-r', apk.apkPath]));
+ final Status status = logger.startProgress('Installing ${fs.path.relative(apk.file.path)}...', expectSlowOperation: true);
+ final RunResult installResult = await runAsync(adbCommandForDevice(<String>['install', '-t', '-r', apk.file.path]));
status.stop();
// Some versions of adb exit with exit code 0 even on failure :(
// Parsing the output to check for failures.
@@ -374,12 +375,13 @@
if (!prebuiltApplication) {
printTrace('Building APK');
await buildApk(
+ project: new FlutterProject(fs.currentDirectory),
target: mainPath,
buildInfo: buildInfo,
);
// Package has been built, so we can get the updated application ID and
// activity name from the .apk.
- package = await AndroidApk.fromCurrentDirectory();
+ package = await AndroidApk.fromAndroidProject(new FlutterProject(fs.currentDirectory).android);
}
printTrace("Stopping app '${package.name}' on $name.");
diff --git a/packages/flutter_tools/lib/src/android/apk.dart b/packages/flutter_tools/lib/src/android/apk.dart
index 4a2af8e..57e7f29 100644
--- a/packages/flutter_tools/lib/src/android/apk.dart
+++ b/packages/flutter_tools/lib/src/android/apk.dart
@@ -4,17 +4,22 @@
import 'dart:async';
+import 'package:meta/meta.dart';
+
import '../base/common.dart';
import '../build_info.dart';
import '../globals.dart';
+import '../project.dart';
+
import 'android_sdk.dart';
import 'gradle.dart';
Future<Null> buildApk({
- String target,
+ @required FlutterProject project,
+ @required String target,
BuildInfo buildInfo = BuildInfo.debug
}) async {
- if (!isProjectUsingGradle()) {
+ if (!project.android.isUsingGradle()) {
throwToolExit(
'The build process for Android has changed, and the current project configuration\n'
'is no longer valid. Please consult\n\n'
@@ -33,5 +38,9 @@
throwToolExit('Try re-installing or updating your Android SDK.');
}
- return buildGradleProject(buildInfo, target);
+ return buildGradleProject(
+ project: project,
+ buildInfo: buildInfo,
+ target: target,
+ );
}
diff --git a/packages/flutter_tools/lib/src/android/gradle.dart b/packages/flutter_tools/lib/src/android/gradle.dart
index 833ae58..c7b1e25 100644
--- a/packages/flutter_tools/lib/src/android/gradle.dart
+++ b/packages/flutter_tools/lib/src/android/gradle.dart
@@ -4,6 +4,8 @@
import 'dart:async';
+import 'package:meta/meta.dart';
+
import '../android/android_sdk.dart';
import '../artifacts.dart';
import '../base/common.dart';
@@ -14,16 +16,13 @@
import '../base/process.dart';
import '../base/utils.dart';
import '../build_info.dart';
-import '../bundle.dart' as bundle;
import '../cache.dart';
import '../flutter_manifest.dart';
import '../globals.dart';
+import '../project.dart';
import 'android_sdk.dart';
import 'android_studio.dart';
-const String gradleManifestPath = 'android/app/src/main/AndroidManifest.xml';
-const String gradleAppOutV1 = 'android/app/build/outputs/apk/app-debug.apk';
-const String gradleAppOutDirV1 = 'android/app/build/outputs/apk';
const String gradleVersion = '4.1';
final RegExp _assembleTaskPattern = new RegExp(r'assemble([^:]+): task ');
@@ -45,9 +44,6 @@
r'|If you are using NDK, verify the ndk.dir is set to a valid NDK directory. It is currently set to .*)');
-bool isProjectUsingGradle() {
- return fs.isFileSync('android/build.gradle');
-}
FlutterPluginVersion get flutterPluginVersion {
final File plugin = fs.file('android/buildSrc/src/main/groovy/FlutterPlugin.groovy');
@@ -69,18 +65,17 @@
return FlutterPluginVersion.none;
}
-/// Returns the path to the apk file created by [buildGradleProject], relative
-/// to current directory.
-Future<String> getGradleAppOut() async {
+/// Returns the apk file created by [buildGradleProject]
+Future<File> getGradleAppOut(AndroidProject androidProject) async {
switch (flutterPluginVersion) {
case FlutterPluginVersion.none:
// Fall through. Pretend we're v1, and just go with it.
case FlutterPluginVersion.v1:
- return gradleAppOutV1;
+ return androidProject.gradleAppOutV1File;
case FlutterPluginVersion.managed:
// Fall through. The managed plugin matches plugin v2 for now.
case FlutterPluginVersion.v2:
- return fs.path.relative(fs.path.join((await _gradleProject()).apkDirectory, 'app.apk'));
+ return fs.file((await _gradleProject()).apkDirectory.childFile('app.apk'));
}
return null;
}
@@ -94,12 +89,13 @@
// of calculating the app properties using Gradle. This may take minutes.
Future<GradleProject> _readGradleProject() async {
final String gradle = await _ensureGradle();
- await updateLocalProperties();
+ final FlutterProject flutterProject = new FlutterProject(fs.currentDirectory);
+ await updateLocalProperties(project: flutterProject);
try {
final Status status = logger.startProgress('Resolving dependencies...', expectSlowOperation: true);
final RunResult runResult = await runCheckedAsync(
<String>[gradle, 'app:properties'],
- workingDirectory: 'android',
+ workingDirectory: flutterProject.android.directory.path,
environment: _gradleEnv,
);
final String properties = runResult.stdout.trim();
@@ -117,7 +113,7 @@
}
}
// Fall back to the default
- return new GradleProject(<String>['debug', 'profile', 'release'], <String>[], gradleAppOutDirV1);
+ return new GradleProject(<String>['debug', 'profile', 'release'], <String>[], flutterProject.android.gradleAppOutV1Directory);
}
void handleKnownGradleExceptions(String exceptionString) {
@@ -199,28 +195,19 @@
/// Overwrite android/local.properties in the specified Flutter project, if needed.
///
/// Throws, if `pubspec.yaml` or Android SDK cannot be located.
-Future<void> updateLocalProperties({String projectPath, BuildInfo buildInfo}) async {
- final Directory android = (projectPath == null)
- ? fs.directory('android')
- : fs.directory(fs.path.join(projectPath, 'android'));
- final String flutterManifest = (projectPath == null)
- ? fs.path.join(bundle.defaultManifestPath)
- : fs.path.join(projectPath, bundle.defaultManifestPath);
- if (androidSdk == null) {
+///
+/// If [requireSdk] is `true` this will fail with a tool-exit if no Android Sdk
+/// is found.
+Future<void> updateLocalProperties({
+ @required FlutterProject project,
+ BuildInfo buildInfo,
+ bool requireAndroidSdk = true,
+}) async {
+ if (requireAndroidSdk && androidSdk == null) {
throwToolExit('Unable to locate Android SDK. Please run `flutter doctor` for more details.');
}
- FlutterManifest manifest;
- try {
- manifest = await FlutterManifest.createFromPath(flutterManifest);
- } catch (error) {
- throwToolExit('Failed to load pubspec.yaml: $error');
- }
- updateLocalPropertiesSync(android, manifest, buildInfo);
-}
-/// Overwrite local.properties in the specified directory, if needed.
-void updateLocalPropertiesSync(Directory android, FlutterManifest manifest, [BuildInfo buildInfo]) {
- final File localProperties = android.childFile('local.properties');
+ final File localProperties = await project.androidLocalPropertiesFile;
bool changed = false;
SettingsFile settings;
@@ -238,6 +225,8 @@
}
}
+ final FlutterManifest manifest = await project.manifest;
+
if (androidSdk != null)
changeIfNecessary('sdk.dir', escapePath(androidSdk.directory));
changeIfNecessary('flutter.sdk', escapePath(Cache.flutterRoot));
@@ -254,7 +243,11 @@
settings.writeContents(localProperties);
}
-Future<Null> buildGradleProject(BuildInfo buildInfo, String target) async {
+Future<Null> buildGradleProject({
+ @required FlutterProject project,
+ @required BuildInfo buildInfo,
+ @required String target,
+}) async {
// Update the local.properties file with the build mode, version name and code.
// FlutterPlugin v1 reads local.properties to determine build mode. Plugin v2
// uses the standard Android way to determine what to build, but we still
@@ -263,7 +256,7 @@
// and can be overwritten with flutter build command.
// The default Gradle script reads the version name and number
// from the local.properties file.
- await updateLocalProperties(buildInfo: buildInfo);
+ await updateLocalProperties(project: project, buildInfo: buildInfo);
final String gradle = await _ensureGradle();
@@ -271,7 +264,7 @@
case FlutterPluginVersion.none:
// Fall through. Pretend it's v1, and just go for it.
case FlutterPluginVersion.v1:
- return _buildGradleProjectV1(gradle);
+ return _buildGradleProjectV1(project, gradle);
case FlutterPluginVersion.managed:
// Fall through. Managed plugin builds the same way as plugin v2.
case FlutterPluginVersion.v2:
@@ -279,7 +272,7 @@
}
}
-Future<Null> _buildGradleProjectV1(String gradle) async {
+Future<Null> _buildGradleProjectV1(FlutterProject project, String gradle) async {
// Run 'gradlew build'.
final Status status = logger.startProgress('Running \'gradlew build\'...', expectSlowOperation: true);
final int exitCode = await runCommandAndStreamOutput(
@@ -293,7 +286,7 @@
if (exitCode != 0)
throwToolExit('Gradle build failed: $exitCode', exitCode: exitCode);
- printStatus('Built $gradleAppOutV1.');
+ printStatus('Built ${fs.path.relative(project.android.gradleAppOutV1File.path)}.');
}
Future<Null> _buildGradleProjectV2(String gradle, BuildInfo buildInfo, String target) async {
@@ -371,10 +364,10 @@
if (apkFile == null)
throwToolExit('Gradle build failed to produce an Android package.');
// Copy the APK to app.apk, so `flutter run`, `flutter install`, etc. can find it.
- apkFile.copySync(fs.path.join(project.apkDirectory, 'app.apk'));
+ apkFile.copySync(project.apkDirectory.childFile('app.apk').path);
printTrace('calculateSha: ${project.apkDirectory}/app.apk');
- final File apkShaFile = fs.file(fs.path.join(project.apkDirectory, 'app.apk.sha1'));
+ final File apkShaFile = project.apkDirectory.childFile('app.apk.sha1');
apkShaFile.writeAsStringSync(calculateSha(apkFile));
String appSize;
@@ -390,15 +383,15 @@
final String apkFileName = project.apkFileFor(buildInfo);
if (apkFileName == null)
return null;
- File apkFile = fs.file(fs.path.join(project.apkDirectory, apkFileName));
+ File apkFile = fs.file(fs.path.join(project.apkDirectory.path, apkFileName));
if (apkFile.existsSync())
return apkFile;
- apkFile = fs.file(fs.path.join(project.apkDirectory, buildInfo.modeName, apkFileName));
+ apkFile = fs.file(fs.path.join(project.apkDirectory.path, buildInfo.modeName, apkFileName));
if (apkFile.existsSync())
return apkFile;
if (buildInfo.flavor != null) {
// Android Studio Gradle plugin v3 adds flavor to path.
- apkFile = fs.file(fs.path.join(project.apkDirectory, buildInfo.flavor, buildInfo.modeName, apkFileName));
+ apkFile = fs.file(fs.path.join(project.apkDirectory.path, buildInfo.flavor, buildInfo.modeName, apkFileName));
if (apkFile.existsSync())
return apkFile;
}
@@ -453,13 +446,13 @@
return new GradleProject(
buildTypes.toList(),
productFlavors.toList(),
- fs.path.normalize(fs.path.join(buildDir, 'outputs', 'apk')),
+ fs.directory(fs.path.join(buildDir, 'outputs', 'apk')),
);
}
final List<String> buildTypes;
final List<String> productFlavors;
- final String apkDirectory;
+ final Directory apkDirectory;
String _buildTypeFor(BuildInfo buildInfo) {
if (buildTypes.contains(buildInfo.modeName))
diff --git a/packages/flutter_tools/lib/src/application_package.dart b/packages/flutter_tools/lib/src/application_package.dart
index ff52975..b1dbdaa 100644
--- a/packages/flutter_tools/lib/src/application_package.dart
+++ b/packages/flutter_tools/lib/src/application_package.dart
@@ -18,6 +18,7 @@
import 'ios/ios_workflow.dart';
import 'ios/plist_utils.dart' as plist;
import 'ios/xcodeproj.dart';
+import 'project.dart';
import 'tester/flutter_tester.dart';
abstract class ApplicationPackage {
@@ -31,7 +32,7 @@
String get displayName => name;
- String get packagePath => null;
+ File get packagesFile => null;
@override
String toString() => displayName;
@@ -39,21 +40,21 @@
class AndroidApk extends ApplicationPackage {
/// Path to the actual apk file.
- final String apkPath;
+ final File file;
/// The path to the activity that should be launched.
final String launchActivity;
AndroidApk({
String id,
- @required this.apkPath,
+ @required this.file,
@required this.launchActivity
- }) : assert(apkPath != null),
+ }) : assert(file != null),
assert(launchActivity != null),
super(id: id);
/// Creates a new AndroidApk from an existing APK.
- factory AndroidApk.fromApk(String applicationBinary) {
+ factory AndroidApk.fromApk(File apk) {
final String aaptPath = androidSdk?.latestVersion?.aaptPath;
if (aaptPath == null) {
printError('Unable to locate the Android SDK; please run \'flutter doctor\'.');
@@ -64,7 +65,7 @@
aaptPath,
'dump',
'xmltree',
- applicationBinary,
+ apk.path,
'AndroidManifest.xml',
];
@@ -72,47 +73,46 @@
.parseFromXmlDump(runCheckedSync(aaptArgs));
if (data == null) {
- printError('Unable to read manifest info from $applicationBinary.');
+ printError('Unable to read manifest info from ${apk.path}.');
return null;
}
if (data.packageName == null || data.launchableActivityName == null) {
- printError('Unable to read manifest info from $applicationBinary.');
+ printError('Unable to read manifest info from ${apk.path}.');
return null;
}
return new AndroidApk(
id: data.packageName,
- apkPath: applicationBinary,
+ file: apk,
launchActivity: '${data.packageName}/${data.launchableActivityName}'
);
}
/// Creates a new AndroidApk based on the information in the Android manifest.
- static Future<AndroidApk> fromCurrentDirectory() async {
- String manifestPath;
- String apkPath;
+ static Future<AndroidApk> fromAndroidProject(AndroidProject androidProject) async {
+ File apkFile;
- if (isProjectUsingGradle()) {
- apkPath = await getGradleAppOut();
- if (fs.file(apkPath).existsSync()) {
+ if (androidProject.isUsingGradle()) {
+ apkFile = await getGradleAppOut(androidProject);
+ if (apkFile.existsSync()) {
// Grab information from the .apk. The gradle build script might alter
// the application Id, so we need to look at what was actually built.
- return new AndroidApk.fromApk(apkPath);
+ return new AndroidApk.fromApk(apkFile);
}
// The .apk hasn't been built yet, so we work with what we have. The run
// command will grab a new AndroidApk after building, to get the updated
// IDs.
- manifestPath = gradleManifestPath;
} else {
- manifestPath = fs.path.join('android', 'AndroidManifest.xml');
- apkPath = fs.path.join(getAndroidBuildDirectory(), 'app.apk');
+ apkFile = fs.file(fs.path.join(getAndroidBuildDirectory(), 'app.apk'));
}
- if (!fs.isFileSync(manifestPath))
+ final File manifest = androidProject.gradleManifestFile;
+
+ if (!manifest.existsSync())
return null;
- final String manifestString = fs.file(manifestPath).readAsStringSync();
+ final String manifestString = manifest.readAsStringSync();
final xml.XmlDocument document = xml.parse(manifestString);
final Iterable<xml.XmlElement> manifests = document.findElements('manifest');
@@ -138,16 +138,16 @@
return new AndroidApk(
id: packageId,
- apkPath: apkPath,
+ file: apkFile,
launchActivity: launchActivity
);
}
@override
- String get packagePath => apkPath;
+ File get packagesFile => file;
@override
- String get name => fs.path.basename(apkPath);
+ String get name => file.basename;
}
/// Tests whether a [FileSystemEntity] is an iOS bundle directory
@@ -158,18 +158,18 @@
IOSApp({@required String projectBundleId}) : super(id: projectBundleId);
/// Creates a new IOSApp from an existing app bundle or IPA.
- factory IOSApp.fromPrebuiltApp(String applicationBinary) {
- final FileSystemEntityType entityType = fs.typeSync(applicationBinary);
+ factory IOSApp.fromPrebuiltApp(FileSystemEntity applicationBinary) {
+ final FileSystemEntityType entityType = fs.typeSync(applicationBinary.path);
if (entityType == FileSystemEntityType.notFound) {
printError(
- 'File "$applicationBinary" does not exist. Use an app bundle or an ipa.');
+ 'File "${applicationBinary.path}" does not exist. Use an app bundle or an ipa.');
return null;
}
Directory bundleDir;
if (entityType == FileSystemEntityType.directory) {
final Directory directory = fs.directory(applicationBinary);
if (!_isBundleDirectory(directory)) {
- printError('Folder "$applicationBinary" is not an app bundle.');
+ printError('Folder "${applicationBinary.path}" is not an app bundle.');
return null;
}
bundleDir = fs.directory(applicationBinary);
@@ -305,16 +305,16 @@
String get _bundlePath => bundleDir.path;
}
-Future<ApplicationPackage> getApplicationPackageForPlatform(TargetPlatform platform, {
- String applicationBinary
-}) async {
+Future<ApplicationPackage> getApplicationPackageForPlatform(
+ TargetPlatform platform,
+ {File applicationBinary}) async {
switch (platform) {
case TargetPlatform.android_arm:
case TargetPlatform.android_arm64:
case TargetPlatform.android_x64:
case TargetPlatform.android_x86:
return applicationBinary == null
- ? await AndroidApk.fromCurrentDirectory()
+ ? await AndroidApk.fromAndroidProject(new FlutterProject(fs.currentDirectory).android)
: new AndroidApk.fromApk(applicationBinary);
case TargetPlatform.ios:
return applicationBinary == null
@@ -344,7 +344,7 @@
case TargetPlatform.android_arm64:
case TargetPlatform.android_x64:
case TargetPlatform.android_x86:
- android ??= await AndroidApk.fromCurrentDirectory();
+ android ??= await AndroidApk.fromAndroidProject(new FlutterProject(fs.currentDirectory).android);
return android;
case TargetPlatform.ios:
iOS ??= new IOSApp.fromCurrentDirectory();
diff --git a/packages/flutter_tools/lib/src/commands/build_apk.dart b/packages/flutter_tools/lib/src/commands/build_apk.dart
index e6e2cc5..3dda93a 100644
--- a/packages/flutter_tools/lib/src/commands/build_apk.dart
+++ b/packages/flutter_tools/lib/src/commands/build_apk.dart
@@ -5,6 +5,8 @@
import 'dart:async';
import '../android/apk.dart';
+import '../base/file_system.dart';
+import '../project.dart';
import 'build.dart';
class BuildApkCommand extends BuildSubCommand {
@@ -44,6 +46,6 @@
@override
Future<Null> runCommand() async {
await super.runCommand();
- await buildApk(buildInfo: getBuildInfo(), target: targetFile);
+ await buildApk(project: new FlutterProject(fs.currentDirectory),target: targetFile, buildInfo: getBuildInfo());
}
}
diff --git a/packages/flutter_tools/lib/src/commands/create.dart b/packages/flutter_tools/lib/src/commands/create.dart
index 0c69f18..7c97cf3 100644
--- a/packages/flutter_tools/lib/src/commands/create.dart
+++ b/packages/flutter_tools/lib/src/commands/create.dart
@@ -168,20 +168,19 @@
printStatus('Creating project ${fs.path.relative(dirPath)}...');
int generatedFileCount = 0;
- String appPath = dirPath;
+ final FlutterProject project = new FlutterProject.fromPath(dirPath);
switch (template) {
case 'app':
- generatedFileCount += await _generateApp(dirPath, templateContext);
+ generatedFileCount += await _generateApp(project, templateContext);
break;
case 'module':
- generatedFileCount += await _generateModule(dirPath, templateContext);
+ generatedFileCount += await _generateModule(project, templateContext);
break;
case 'package':
- generatedFileCount += await _generatePackage(dirPath, templateContext);
+ generatedFileCount += await _generatePackage(project, templateContext);
break;
case 'plugin':
- appPath = fs.path.join(dirPath, 'example');
- generatedFileCount += await _generatePlugin(dirPath, appPath, templateContext);
+ generatedFileCount += await _generatePlugin(project, templateContext);
break;
}
printStatus('Wrote $generatedFileCount files.');
@@ -194,7 +193,8 @@
printStatus('Your module code is in lib/main.dart in the $relativePath directory.');
} else {
// Run doctor; tell the user the next steps.
- final String relativeAppPath = fs.path.relative(appPath);
+ final FlutterProject app = project.hasExampleApp ? project.example : project;
+ final String relativeAppPath = fs.path.relative(app.directory.path);
final String relativePluginPath = fs.path.relative(dirPath);
if (doctor.canLaunchAnything) {
// Let them know a summary of the state of their tooling.
@@ -233,60 +233,59 @@
}
}
- Future<int> _generateModule(String path, Map<String, dynamic> templateContext) async {
+ Future<int> _generateModule(FlutterProject project, Map<String, dynamic> templateContext) async {
int generatedCount = 0;
final String description = argResults.wasParsed('description')
? argResults['description']
: 'A new flutter module project.';
templateContext['description'] = description;
- generatedCount += _renderTemplate(fs.path.join('module', 'common'), path, templateContext);
+ generatedCount += _renderTemplate(fs.path.join('module', 'common'), project.directory, templateContext);
if (argResults['pub']) {
await pubGet(
context: PubContext.create,
- directory: path,
+ directory: project.directory.path,
offline: argResults['offline'],
);
- final FlutterProject project = new FlutterProject.fromPath(path);
await project.ensureReadyForPlatformSpecificTooling();
}
return generatedCount;
}
- Future<int> _generatePackage(String dirPath, Map<String, dynamic> templateContext) async {
+ Future<int> _generatePackage(FlutterProject project, Map<String, dynamic> templateContext) async {
int generatedCount = 0;
final String description = argResults.wasParsed('description')
? argResults['description']
: 'A new flutter package project.';
templateContext['description'] = description;
- generatedCount += _renderTemplate('package', dirPath, templateContext);
+ generatedCount += _renderTemplate('package', project.directory, templateContext);
if (argResults['pub']) {
await pubGet(
context: PubContext.createPackage,
- directory: dirPath,
+ directory: project.directory.path,
offline: argResults['offline'],
);
}
return generatedCount;
}
- Future<int> _generatePlugin(String dirPath, String appPath, Map<String, dynamic> templateContext) async {
+ Future<int> _generatePlugin(FlutterProject project, Map<String, dynamic> templateContext) async {
int generatedCount = 0;
final String description = argResults.wasParsed('description')
? argResults['description']
: 'A new flutter plugin project.';
templateContext['description'] = description;
- generatedCount += _renderTemplate('plugin', dirPath, templateContext);
+ generatedCount += _renderTemplate('plugin', project.directory, templateContext);
if (argResults['pub']) {
await pubGet(
context: PubContext.createPlugin,
- directory: dirPath,
+ directory: project.directory.path,
offline: argResults['offline'],
);
}
if (android_sdk.androidSdk != null)
- await gradle.updateLocalProperties(projectPath: dirPath);
+ await gradle.updateLocalProperties(project: project);
final String projectName = templateContext['projectName'];
final String organization = templateContext['organization'];
@@ -299,27 +298,27 @@
templateContext['pluginProjectName'] = projectName;
templateContext['androidPluginIdentifier'] = androidPluginIdentifier;
- generatedCount += await _generateApp(appPath, templateContext);
+ generatedCount += await _generateApp(project.example, templateContext);
return generatedCount;
}
- Future<int> _generateApp(String projectPath, Map<String, dynamic> templateContext) async {
+ Future<int> _generateApp(FlutterProject project, Map<String, dynamic> templateContext) async {
int generatedCount = 0;
- generatedCount += _renderTemplate('create', projectPath, templateContext);
- generatedCount += _injectGradleWrapper(projectPath);
+ generatedCount += _renderTemplate('create', project.directory, templateContext);
+ generatedCount += _injectGradleWrapper(project);
if (argResults['with-driver-test']) {
- final String testPath = fs.path.join(projectPath, 'test_driver');
- generatedCount += _renderTemplate('driver', testPath, templateContext);
+ final Directory testDirectory = project.directory.childDirectory('test_driver');
+ generatedCount += _renderTemplate('driver', testDirectory, templateContext);
}
if (argResults['pub']) {
- await pubGet(context: PubContext.create, directory: projectPath, offline: argResults['offline']);
- await new FlutterProject.fromPath(projectPath).ensureReadyForPlatformSpecificTooling();
+ await pubGet(context: PubContext.create, directory: project.directory.path, offline: argResults['offline']);
+ await project.ensureReadyForPlatformSpecificTooling();
}
if (android_sdk.androidSdk != null)
- await gradle.updateLocalProperties(projectPath: projectPath);
+ await gradle.updateLocalProperties(project: project);
return generatedCount;
}
@@ -362,16 +361,16 @@
};
}
- int _renderTemplate(String templateName, String dirPath, Map<String, dynamic> context) {
+ int _renderTemplate(String templateName, Directory directory, Map<String, dynamic> context) {
final Template template = new Template.fromName(templateName);
- return template.render(fs.directory(dirPath), context, overwriteExisting: false);
+ return template.render(directory, context, overwriteExisting: false);
}
- int _injectGradleWrapper(String projectDir) {
+ int _injectGradleWrapper(FlutterProject project) {
int filesCreated = 0;
copyDirectorySync(
cache.getArtifactDirectory('gradle_wrapper'),
- fs.directory(fs.path.join(projectDir, 'android')),
+ project.android.directory,
(File sourceFile, File destinationFile) {
filesCreated++;
final String modes = sourceFile.statSync().modeString();
diff --git a/packages/flutter_tools/lib/src/commands/daemon.dart b/packages/flutter_tools/lib/src/commands/daemon.dart
index 140b04b..0d1a3d5 100644
--- a/packages/flutter_tools/lib/src/commands/daemon.dart
+++ b/packages/flutter_tools/lib/src/commands/daemon.dart
@@ -327,7 +327,7 @@
Future<AppInstance> startApp(
Device device, String projectDirectory, String target, String route,
DebuggingOptions options, bool enableHotReload, {
- String applicationBinary,
+ File applicationBinary,
@required bool trackWidgetCreation,
String projectRootPath,
String packagesFilePath,
diff --git a/packages/flutter_tools/lib/src/commands/inject_plugins.dart b/packages/flutter_tools/lib/src/commands/inject_plugins.dart
index 832b642..6a1bb94 100644
--- a/packages/flutter_tools/lib/src/commands/inject_plugins.dart
+++ b/packages/flutter_tools/lib/src/commands/inject_plugins.dart
@@ -5,9 +5,9 @@
import 'dart:async';
import '../base/file_system.dart';
-import '../flutter_manifest.dart';
import '../globals.dart';
import '../plugins.dart';
+import '../project.dart';
import '../runner/flutter_command.dart';
class InjectPluginsCommand extends FlutterCommand {
@@ -26,10 +26,9 @@
@override
Future<Null> runCommand() async {
- final String projectPath = fs.currentDirectory.path;
- final FlutterManifest manifest = await FlutterManifest.createFromPath(projectPath);
- injectPlugins(projectPath: projectPath, manifest: manifest);
- final bool result = hasPlugins();
+ final FlutterProject project = new FlutterProject(fs.currentDirectory);
+ await injectPlugins(project);
+ final bool result = hasPlugins(project);
if (result) {
printStatus('GeneratedPluginRegistrants successfully written.');
} else {
diff --git a/packages/flutter_tools/lib/src/commands/run.dart b/packages/flutter_tools/lib/src/commands/run.dart
index eafdd1e..730be16 100644
--- a/packages/flutter_tools/lib/src/commands/run.dart
+++ b/packages/flutter_tools/lib/src/commands/run.dart
@@ -289,10 +289,13 @@
notifyingLogger: new NotifyingLogger(), logToStdout: true);
AppInstance app;
try {
+ final String applicationBinaryPath = argResults['use-application-binary'];
app = await daemon.appDomain.startApp(
devices.first, fs.currentDirectory.path, targetFile, route,
_createDebuggingOptions(), hotMode,
- applicationBinary: argResults['use-application-binary'],
+ applicationBinary: applicationBinaryPath == null
+ ? null
+ : fs.file(applicationBinaryPath),
trackWidgetCreation: argResults['track-widget-creation'],
projectRootPath: argResults['project-root'],
packagesFilePath: globalResults['packages'],
diff --git a/packages/flutter_tools/lib/src/ios/cocoapods.dart b/packages/flutter_tools/lib/src/ios/cocoapods.dart
index 9904812..d6dc48c 100644
--- a/packages/flutter_tools/lib/src/ios/cocoapods.dart
+++ b/packages/flutter_tools/lib/src/ios/cocoapods.dart
@@ -15,8 +15,8 @@
import '../base/process_manager.dart';
import '../base/version.dart';
import '../cache.dart';
-import '../flutter_manifest.dart';
import '../globals.dart';
+import '../project.dart';
import 'xcodeproj.dart';
const String noCocoaPodsConsequence = '''
@@ -81,18 +81,18 @@
Future<bool> get isCocoaPodsInitialized => fs.isDirectory(fs.path.join(homeDirPath, '.cocoapods', 'repos', 'master'));
Future<bool> processPods({
- @required Directory appIosDirectory,
+ @required IosProject iosProject,
// For backward compatibility with previously created Podfile only.
@required String iosEngineDir,
bool isSwift = false,
bool dependenciesChanged = true,
}) async {
- if (!(await appIosDirectory.childFile('Podfile').exists())) {
+ if (!(await iosProject.podfile.exists())) {
throwToolExit('Podfile missing');
}
if (await _checkPodCondition()) {
- if (_shouldRunPodInstall(appIosDirectory, dependenciesChanged)) {
- await _runPodInstall(appIosDirectory, iosEngineDir);
+ if (_shouldRunPodInstall(iosProject, dependenciesChanged)) {
+ await _runPodInstall(iosProject, iosEngineDir);
return true;
}
}
@@ -151,18 +151,18 @@
/// Ensures the `ios` sub-project of the Flutter project at [appDirectory]
/// contains a suitable `Podfile` and that its `Flutter/Xxx.xcconfig` files
/// include pods configuration.
- void setupPodfile(String appDirectory, FlutterManifest manifest) {
+ void setupPodfile(IosProject iosProject) {
if (!xcodeProjectInterpreter.isInstalled) {
// Don't do anything for iOS when host platform doesn't support it.
return;
}
- if (!fs.directory(fs.path.join(appDirectory, 'ios')).existsSync()) {
+ if (!iosProject.directory.existsSync()) {
return;
}
- final String podfilePath = fs.path.join(appDirectory, 'ios', 'Podfile');
- if (!fs.file(podfilePath).existsSync()) {
+ final File podfile = iosProject.podfile;
+ if (!podfile.existsSync()) {
final bool isSwift = xcodeProjectInterpreter.getBuildSettings(
- fs.path.join(appDirectory, 'ios', 'Runner.xcodeproj'),
+ iosProject.directory.childFile('Runner.xcodeproj').path,
'Runner',
).containsKey('SWIFT_VERSION');
final File podfileTemplate = fs.file(fs.path.join(
@@ -173,15 +173,14 @@
'cocoapods',
isSwift ? 'Podfile-swift' : 'Podfile-objc',
));
- podfileTemplate.copySync(podfilePath);
+ podfileTemplate.copySync(podfile.path);
}
-
- _addPodsDependencyToFlutterXcconfig(appDirectory, 'Debug');
- _addPodsDependencyToFlutterXcconfig(appDirectory, 'Release');
+ _addPodsDependencyToFlutterXcconfig(iosProject, 'Debug');
+ _addPodsDependencyToFlutterXcconfig(iosProject, 'Release');
}
- void _addPodsDependencyToFlutterXcconfig(String appDirectory, String mode) {
- final File file = fs.file(fs.path.join(appDirectory, 'ios', 'Flutter', '$mode.xcconfig'));
+ void _addPodsDependencyToFlutterXcconfig(IosProject iosProject, String mode) {
+ final File file = iosProject.xcodeConfigFor(mode);
if (file.existsSync()) {
final String content = file.readAsStringSync();
final String include = '#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.${mode
@@ -192,12 +191,11 @@
}
/// Ensures that pod install is deemed needed on next check.
- void invalidatePodInstallOutput(String appDirectory) {
- final File manifest = fs.file(
- fs.path.join(appDirectory, 'ios', 'Pods', 'Manifest.lock'),
- );
- if (manifest.existsSync())
- manifest.deleteSync();
+ void invalidatePodInstallOutput(IosProject iosProject) {
+ final File manifestLock = iosProject.podManifestLock;
+ if (manifestLock.existsSync()) {
+ manifestLock.deleteSync();
+ }
}
// Check if you need to run pod install.
@@ -206,24 +204,25 @@
// 2. Podfile.lock doesn't exist or is older than Podfile
// 3. Pods/Manifest.lock doesn't exist (It is deleted when plugins change)
// 4. Podfile.lock doesn't match Pods/Manifest.lock.
- bool _shouldRunPodInstall(Directory appIosDirectory, bool dependenciesChanged) {
+ bool _shouldRunPodInstall(IosProject iosProject, bool dependenciesChanged) {
if (dependenciesChanged)
return true;
- final File podfileFile = appIosDirectory.childFile('Podfile');
- final File podfileLockFile = appIosDirectory.childFile('Podfile.lock');
- final File manifestLockFile =
- appIosDirectory.childFile(fs.path.join('Pods', 'Manifest.lock'));
+
+ final File podfileFile = iosProject.podfile;
+ final File podfileLockFile = iosProject.podfileLock;
+ final File manifestLockFile = iosProject.podManifestLock;
+
return !podfileLockFile.existsSync()
|| !manifestLockFile.existsSync()
|| podfileLockFile.statSync().modified.isBefore(podfileFile.statSync().modified)
|| podfileLockFile.readAsStringSync() != manifestLockFile.readAsStringSync();
}
- Future<Null> _runPodInstall(Directory appIosDirectory, String engineDirectory) async {
+ Future<Null> _runPodInstall(IosProject iosProject, String engineDirectory) async {
final Status status = logger.startProgress('Running pod install...', expectSlowOperation: true);
final ProcessResult result = await processManager.run(
<String>['pod', 'install', '--verbose'],
- workingDirectory: appIosDirectory.path,
+ workingDirectory: iosProject.directory.path,
environment: <String, String>{
// For backward compatibility with previously created Podfile only.
'FLUTTER_FRAMEWORK_DIR': engineDirectory,
@@ -244,7 +243,7 @@
}
}
if (result.exitCode != 0) {
- invalidatePodInstallOutput(appIosDirectory.parent.path);
+ invalidatePodInstallOutput(iosProject);
_diagnosePodInstallFailure(result);
throwToolExit('Error running pod install');
}
diff --git a/packages/flutter_tools/lib/src/ios/mac.dart b/packages/flutter_tools/lib/src/ios/mac.dart
index 85d4d87..63c8da9 100644
--- a/packages/flutter_tools/lib/src/ios/mac.dart
+++ b/packages/flutter_tools/lib/src/ios/mac.dart
@@ -20,9 +20,9 @@
import '../base/process_manager.dart';
import '../base/utils.dart';
import '../build_info.dart';
-import '../flutter_manifest.dart';
import '../globals.dart';
import '../plugins.dart';
+import '../project.dart';
import '../services.dart';
import 'cocoapods.dart';
import 'code_signing.dart';
@@ -233,18 +233,15 @@
final Directory appDirectory = fs.directory(app.appDirectory);
await _addServicesToBundle(appDirectory);
- final FlutterManifest manifest = await FlutterManifest.createFromPath(
- fs.currentDirectory.childFile('pubspec.yaml').path,
- );
- updateGeneratedXcodeProperties(
- projectPath: fs.currentDirectory.path,
- buildInfo: buildInfo,
+ final FlutterProject project = new FlutterProject(fs.currentDirectory);
+ await updateGeneratedXcodeProperties(
+ project: project,
targetOverride: targetOverride,
previewDart2: buildInfo.previewDart2,
- manifest: manifest,
+ buildInfo: buildInfo,
);
- if (hasPlugins()) {
+ if (hasPlugins(project)) {
final String iosPath = fs.path.join(fs.currentDirectory.path, app.appDirectory);
// If the Xcode project, Podfile, or Generated.xcconfig have changed since
// last run, pods should be updated.
@@ -258,7 +255,7 @@
properties: <String, String>{},
);
final bool didPodInstall = await cocoaPods.processPods(
- appIosDirectory: appDirectory,
+ iosProject: project.ios,
iosEngineDir: flutterFrameworkDir(buildInfo.mode),
isSwift: app.isSwift,
dependenciesChanged: !await fingerprinter.doesFingerprintMatch()
diff --git a/packages/flutter_tools/lib/src/ios/xcodeproj.dart b/packages/flutter_tools/lib/src/ios/xcodeproj.dart
index b9bf73d..4f7f6b5 100644
--- a/packages/flutter_tools/lib/src/ios/xcodeproj.dart
+++ b/packages/flutter_tools/lib/src/ios/xcodeproj.dart
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+import 'dart:async';
+
import 'package:meta/meta.dart';
import '../artifacts.dart';
@@ -17,6 +19,7 @@
import '../cache.dart';
import '../flutter_manifest.dart';
import '../globals.dart';
+import '../project.dart';
final RegExp _settingExpr = new RegExp(r'(\w+)\s*=\s*(.*)$');
final RegExp _varExpr = new RegExp(r'\$\((.*)\)');
@@ -25,27 +28,18 @@
return fs.path.normalize(fs.path.dirname(artifacts.getArtifactPath(Artifact.flutterFramework, TargetPlatform.ios, mode)));
}
-String _generatedXcodePropertiesPath({@required String projectPath, @required FlutterManifest manifest}) {
- if (manifest.isModule) {
- return fs.path.join(projectPath, '.ios', 'Flutter', 'Generated.xcconfig');
- } else {
- return fs.path.join(projectPath, 'ios', 'Flutter', 'Generated.xcconfig');
- }
-}
-
/// Writes default Xcode properties files in the Flutter project at [projectPath],
/// if project is an iOS project and such files are out of date or do not
/// already exist.
-void generateXcodeProperties({String projectPath, FlutterManifest manifest}) {
- if (manifest.isModule || fs.isDirectorySync(fs.path.join(projectPath, 'ios'))) {
- final File propertiesFile = fs.file(_generatedXcodePropertiesPath(projectPath: projectPath, manifest: manifest));
- if (!Cache.instance.fileOlderThanToolsStamp(propertiesFile)) {
+Future<void> generateXcodeProperties({FlutterProject project}) async {
+ if ((await project.manifest).isModule ||
+ project.ios.directory.existsSync()) {
+ if (!Cache.instance.fileOlderThanToolsStamp(await project.generatedXcodePropertiesFile)) {
return;
}
- updateGeneratedXcodeProperties(
- projectPath: projectPath,
- manifest: manifest,
+ await updateGeneratedXcodeProperties(
+ project: project,
buildInfo: BuildInfo.debug,
targetOverride: bundle.defaultMainPath,
previewDart2: true,
@@ -57,13 +51,12 @@
///
/// targetOverride: Optional parameter, if null or unspecified the default value
/// from xcode_backend.sh is used 'lib/main.dart'.
-void updateGeneratedXcodeProperties({
- @required String projectPath,
- @required FlutterManifest manifest,
+Future<void> updateGeneratedXcodeProperties({
+ @required FlutterProject project,
@required BuildInfo buildInfo,
String targetOverride,
@required bool previewDart2,
-}) {
+}) async {
final StringBuffer localsBuffer = new StringBuffer();
localsBuffer.writeln('// This is a generated file; do not edit or check into version control.');
@@ -72,7 +65,7 @@
localsBuffer.writeln('FLUTTER_ROOT=$flutterRoot');
// This holds because requiresProjectRoot is true for this command
- localsBuffer.writeln('FLUTTER_APPLICATION_PATH=${fs.path.normalize(projectPath)}');
+ localsBuffer.writeln('FLUTTER_APPLICATION_PATH=${fs.path.normalize(project.directory.path)}');
// Relative to FLUTTER_APPLICATION_PATH, which is [Directory.current].
if (targetOverride != null)
@@ -86,6 +79,7 @@
localsBuffer.writeln('SYMROOT=\${SOURCE_ROOT}/../${getIosBuildDirectory()}');
+ final FlutterManifest manifest = await project.manifest;
if (!manifest.isModule) {
// For module projects we do not want to write the FLUTTER_FRAMEWORK_DIR
// explicitly. Rather we rely on the xcode backend script and the Podfile
@@ -125,9 +119,9 @@
localsBuffer.writeln('TRACK_WIDGET_CREATION=true');
}
- final File localsFile = fs.file(_generatedXcodePropertiesPath(projectPath: projectPath, manifest: manifest));
- localsFile.createSync(recursive: true);
- localsFile.writeAsStringSync(localsBuffer.toString());
+ final File generatedXcodePropertiesFile = await project.generatedXcodePropertiesFile;
+ generatedXcodePropertiesFile.createSync(recursive: true);
+ generatedXcodePropertiesFile.writeAsStringSync(localsBuffer.toString());
}
XcodeProjectInterpreter get xcodeProjectInterpreter => context[XcodeProjectInterpreter];
diff --git a/packages/flutter_tools/lib/src/plugins.dart b/packages/flutter_tools/lib/src/plugins.dart
index d9e2946..484d897 100644
--- a/packages/flutter_tools/lib/src/plugins.dart
+++ b/packages/flutter_tools/lib/src/plugins.dart
@@ -2,15 +2,16 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-import 'package:meta/meta.dart';
+import 'dart:async';
+
import 'package:mustache/mustache.dart' as mustache;
import 'package:yaml/yaml.dart';
import 'base/file_system.dart';
import 'dart/package_map.dart';
-import 'flutter_manifest.dart';
import 'globals.dart';
import 'ios/cocoapods.dart';
+import 'project.dart';
void _renderTemplateToFile(String template, dynamic context, String filePath) {
final String renderedTemplate =
@@ -69,11 +70,11 @@
return new Plugin.fromYaml(name, packageRootPath, flutterConfig['plugin']);
}
-List<Plugin> findPlugins(String directory) {
+List<Plugin> findPlugins(FlutterProject project) {
final List<Plugin> plugins = <Plugin>[];
Map<String, Uri> packages;
try {
- final String packagesFile = fs.path.join(directory, PackageMap.globalPackagesPath);
+ final String packagesFile = fs.path.join(project.directory.path, PackageMap.globalPackagesPath);
packages = new PackageMap(packagesFile).map;
} on FormatException catch (e) {
printTrace('Invalid .packages file: $e');
@@ -89,9 +90,9 @@
}
/// Returns true if .flutter-plugins has changed, otherwise returns false.
-bool _writeFlutterPluginsList(String directory, List<Plugin> plugins) {
- final File pluginsFile = fs.file(fs.path.join(directory, '.flutter-plugins'));
- final String oldContents = _readFlutterPluginsList(directory);
+bool _writeFlutterPluginsList(FlutterProject project, List<Plugin> plugins) {
+ final File pluginsFile = project.flutterPluginsFile;
+ final String oldContents = _readFlutterPluginsList(project);
final String pluginManifest =
plugins.map((Plugin p) => '${p.name}=${escapePath(p.path)}').join('\n');
if (pluginManifest.isNotEmpty) {
@@ -100,15 +101,16 @@
if (pluginsFile.existsSync())
pluginsFile.deleteSync();
}
- final String newContents = _readFlutterPluginsList(directory);
+ final String newContents = _readFlutterPluginsList(project);
return oldContents != newContents;
}
/// Returns the contents of the `.flutter-plugins` file in [directory], or
/// null if that file does not exist.
-String _readFlutterPluginsList(String directory) {
- final File pluginsFile = fs.file(fs.path.join(directory, '.flutter-plugins'));
- return pluginsFile.existsSync() ? pluginsFile.readAsStringSync() : null;
+String _readFlutterPluginsList(FlutterProject project) {
+ return project.flutterPluginsFile.existsSync()
+ ? project.flutterPluginsFile.readAsStringSync()
+ : null;
}
const String _androidPluginRegistryTemplate = '''package io.flutter.plugins;
@@ -142,7 +144,7 @@
}
''';
-void _writeAndroidPluginRegistrant(String directory, List<Plugin> plugins) {
+Future<void> _writeAndroidPluginRegistrant(FlutterProject project, List<Plugin> plugins) async {
final List<Map<String, dynamic>> androidPlugins = plugins
.where((Plugin p) => p.androidPackage != null && p.pluginClass != null)
.map((Plugin p) => <String, dynamic>{
@@ -155,8 +157,19 @@
'plugins': androidPlugins,
};
- final String javaSourcePath = fs.path.join(directory, 'src', 'main', 'java');
- final String registryPath = fs.path.join(javaSourcePath, 'io', 'flutter', 'plugins', 'GeneratedPluginRegistrant.java');
+ final String javaSourcePath = fs.path.join(
+ (await project.androidPluginRegistrantHost).path,
+ 'src',
+ 'main',
+ 'java',
+ );
+ final String registryPath = fs.path.join(
+ javaSourcePath,
+ 'io',
+ 'flutter',
+ 'plugins',
+ 'GeneratedPluginRegistrant.java',
+ );
_renderTemplateToFile(_androidPluginRegistryTemplate, context, registryPath);
}
@@ -221,7 +234,7 @@
end
''';
-void _writeIOSPluginRegistrant(String directory, FlutterManifest manifest, List<Plugin> plugins) {
+Future<void> _writeIOSPluginRegistrant(FlutterProject project, List<Plugin> plugins) async {
final List<Map<String, dynamic>> iosPlugins = plugins
.where((Plugin p) => p.pluginClass != null)
.map((Plugin p) => <String, dynamic>{
@@ -234,10 +247,8 @@
'plugins': iosPlugins,
};
- if (manifest.isModule) {
- // In a module create the GeneratedPluginRegistrant as a pod to be included
- // from a hosting app.
- final String registryDirectory = fs.path.join(directory, 'Flutter', 'FlutterPluginRegistrant');
+ final String registryDirectory = (await project.iosPluginRegistrantHost).path;
+ if ((await project.manifest).isModule) {
final String registryClassesDirectory = fs.path.join(registryDirectory, 'Classes');
_renderTemplateToFile(
_iosPluginRegistrantPodspecTemplate,
@@ -255,57 +266,37 @@
fs.path.join(registryClassesDirectory, 'GeneratedPluginRegistrant.m'),
);
} else {
- // For a non-module create the GeneratedPluginRegistrant as source files
- // directly in the ios project.
- final String runnerDirectory = fs.path.join(directory, 'Runner');
_renderTemplateToFile(
_iosPluginRegistryHeaderTemplate,
context,
- fs.path.join(runnerDirectory, 'GeneratedPluginRegistrant.h'),
+ fs.path.join(registryDirectory, 'GeneratedPluginRegistrant.h'),
);
_renderTemplateToFile(
_iosPluginRegistryImplementationTemplate,
context,
- fs.path.join(runnerDirectory, 'GeneratedPluginRegistrant.m'),
+ fs.path.join(registryDirectory, 'GeneratedPluginRegistrant.m'),
);
}
}
-class InjectPluginsResult{
- InjectPluginsResult({
- @required this.hasPlugin,
- @required this.hasChanged,
- });
- /// True if any flutter plugin exists, otherwise false.
- final bool hasPlugin;
- /// True if plugins have changed since last build.
- final bool hasChanged;
-}
-
/// Injects plugins found in `pubspec.yaml` into the platform-specific projects.
-void injectPlugins({@required String projectPath, @required FlutterManifest manifest}) {
- final List<Plugin> plugins = findPlugins(projectPath);
- final bool changed = _writeFlutterPluginsList(projectPath, plugins);
- if (manifest.isModule) {
- _writeAndroidPluginRegistrant(fs.path.join(projectPath, '.android', 'Flutter'), plugins);
- } else if (fs.isDirectorySync(fs.path.join(projectPath, 'android', 'app'))) {
- _writeAndroidPluginRegistrant(fs.path.join(projectPath, 'android', 'app'), plugins);
- }
- if (manifest.isModule) {
- _writeIOSPluginRegistrant(fs.path.join(projectPath, '.ios'), manifest, plugins);
- } else if (fs.isDirectorySync(fs.path.join(projectPath, 'ios'))) {
- _writeIOSPluginRegistrant(fs.path.join(projectPath, 'ios'), manifest, plugins);
+Future<void> injectPlugins(FlutterProject project) async {
+ final List<Plugin> plugins = findPlugins(project);
+ final bool changed = _writeFlutterPluginsList(project, plugins);
+ await _writeAndroidPluginRegistrant(project, plugins);
+ await _writeIOSPluginRegistrant(project, plugins);
+
+ if (project.ios.directory.existsSync()) {
final CocoaPods cocoaPods = new CocoaPods();
if (plugins.isNotEmpty)
- cocoaPods.setupPodfile(projectPath, manifest);
+ cocoaPods.setupPodfile(project.ios);
if (changed)
- cocoaPods.invalidatePodInstallOutput(projectPath);
+ cocoaPods.invalidatePodInstallOutput(project.ios);
}
}
/// Returns whether the Flutter project at the specified [directory]
/// has any plugin dependencies.
-bool hasPlugins({String directory}) {
- directory ??= fs.currentDirectory.path;
- return _readFlutterPluginsList(directory) != null;
+bool hasPlugins(FlutterProject project) {
+ return _readFlutterPluginsList(project) != null;
}
diff --git a/packages/flutter_tools/lib/src/project.dart b/packages/flutter_tools/lib/src/project.dart
index d3f2e66..ad506d2 100644
--- a/packages/flutter_tools/lib/src/project.dart
+++ b/packages/flutter_tools/lib/src/project.dart
@@ -5,7 +5,6 @@
import 'dart:async';
import 'dart:convert';
-
import 'android/gradle.dart' as gradle;
import 'base/file_system.dart';
import 'bundle.dart' as bundle;
@@ -67,6 +66,57 @@
/// The generated IosModule sub project of this module project.
IosModuleProject get iosModule => new IosModuleProject(directory.childDirectory('.ios'));
+ Future<File> get androidLocalPropertiesFile {
+ return _androidLocalPropertiesFile ??= manifest.then<File>((FlutterManifest manifest) {
+ return directory.childDirectory(manifest.isModule ? '.android' : 'android')
+ .childFile('local.properties');
+ });
+ }
+ Future<File> _androidLocalPropertiesFile;
+
+ Future<File> get generatedXcodePropertiesFile {
+ return _generatedXcodeProperties ??= manifest.then<File>((FlutterManifest manifest) {
+ return directory.childDirectory(manifest.isModule ? '.ios' : 'ios')
+ .childDirectory('Flutter')
+ .childFile('Generated.xcconfig');
+ });
+ }
+ Future<File> _generatedXcodeProperties;
+
+ File get flutterPluginsFile {
+ return _flutterPluginsFile ??= directory.childFile('.flutter-plugins');
+ }
+ File _flutterPluginsFile;
+
+ Future<Directory> get androidPluginRegistrantHost async {
+ return _androidPluginRegistrantHost ??= manifest.then((FlutterManifest manifest) {
+ if (manifest.isModule) {
+ return directory.childDirectory('.android').childDirectory('Flutter');
+ } else {
+ return directory.childDirectory('android').childDirectory('app');
+ }
+ });
+ }
+ Future<Directory> _androidPluginRegistrantHost;
+
+ Future<Directory> get iosPluginRegistrantHost async {
+ return _iosPluginRegistrantHost ??= manifest.then((FlutterManifest manifest) {
+ if (manifest.isModule) {
+ // In a module create the GeneratedPluginRegistrant as a pod to be included
+ // from a hosting app.
+ return directory
+ .childDirectory('.ios')
+ .childDirectory('Flutter')
+ .childDirectory('FlutterPluginRegistrant');
+ } else {
+ // For a non-module create the GeneratedPluginRegistrant as source files
+ // directly in the iOS project.
+ return directory.childDirectory('ios').childDirectory('Runner');
+ }
+ });
+ }
+ Future<Directory> _iosPluginRegistrantHost;
+
/// Returns true if this project has an example application
bool get hasExampleApp => _exampleDirectory.childFile('pubspec.yaml').existsSync();
@@ -86,11 +136,11 @@
}
final FlutterManifest manifest = await this.manifest;
if (manifest.isModule) {
- await androidModule.ensureReadyForPlatformSpecificTooling(manifest);
- await iosModule.ensureReadyForPlatformSpecificTooling(manifest);
+ await androidModule.ensureReadyForPlatformSpecificTooling(this);
+ await iosModule.ensureReadyForPlatformSpecificTooling();
}
- xcode.generateXcodeProperties(projectPath: directory.path, manifest: manifest);
- injectPlugins(projectPath: directory.path, manifest: manifest);
+ await xcode.generateXcodeProperties(project: this);
+ await injectPlugins(this);
}
}
@@ -101,6 +151,20 @@
final Directory directory;
+ /// The xcode config file for [mode].
+ File xcodeConfigFor(String mode) {
+ return directory.childDirectory('Flutter').childFile('$mode.xcconfig');
+ }
+
+ /// The 'Podfile'.
+ File get podfile => directory.childFile('Podfile');
+
+ /// The 'Podfile.lock'.
+ File get podfileLock => directory.childFile('Podfile.lock');
+
+ /// The 'Manifest.lock'.
+ File get podManifestLock => directory.childDirectory('Pods').childFile('Manifest.lock');
+
Future<String> productBundleIdentifier() {
final File projectFile = directory.childDirectory('Runner.xcodeproj').childFile('project.pbxproj');
return _firstMatchInFile(projectFile, _productBundleIdPattern).then((Match match) => match?.group(1));
@@ -114,7 +178,7 @@
final Directory directory;
- Future<void> ensureReadyForPlatformSpecificTooling(FlutterManifest manifest) async {
+ Future<void> ensureReadyForPlatformSpecificTooling() async {
if (_shouldRegenerate()) {
final Template template = new Template.fromName(fs.path.join('module', 'ios'));
template.render(directory, <String, dynamic>{}, printStatusWhenWriting: false);
@@ -133,6 +197,29 @@
AndroidProject(this.directory);
+ File get gradleManifestFile {
+ return _gradleManifestFile ??= isUsingGradle()
+ ? fs.file(fs.path.join(directory.path, 'app', 'src', 'main', 'AndroidManifest.xml'))
+ : directory.childFile('AndroidManifest.xml');
+ }
+ File _gradleManifestFile;
+
+
+ File get gradleAppOutV1File {
+ return _gradleAppOutV1File ??= gradleAppOutV1Directory.childFile('app-debug.apk');
+ }
+ File _gradleAppOutV1File;
+
+ Directory get gradleAppOutV1Directory {
+ return _gradleAppOutV1Directory ??= fs.directory(fs.path.join(directory.path, 'app', 'build', 'outputs', 'apk'));
+ }
+ Directory _gradleAppOutV1Directory;
+
+
+ bool isUsingGradle() {
+ return directory.childFile('build.gradle').existsSync();
+ }
+
final Directory directory;
Future<String> applicationId() {
@@ -153,15 +240,15 @@
final Directory directory;
- Future<void> ensureReadyForPlatformSpecificTooling(FlutterManifest manifest) async {
+ Future<void> ensureReadyForPlatformSpecificTooling(FlutterProject project) async {
if (_shouldRegenerate()) {
final Template template = new Template.fromName(fs.path.join('module', 'android'));
template.render(directory, <String, dynamic>{
- 'androidIdentifier': manifest.moduleDescriptor['androidPackage'],
+ 'androidIdentifier': (await project.manifest).moduleDescriptor['androidPackage'],
}, printStatusWhenWriting: false);
gradle.injectGradleWrapper(directory);
}
- gradle.updateLocalPropertiesSync(directory, manifest);
+ await gradle.updateLocalProperties(project: project, requireAndroidSdk: false);
}
bool _shouldRegenerate() {
diff --git a/packages/flutter_tools/lib/src/resident_runner.dart b/packages/flutter_tools/lib/src/resident_runner.dart
index 0d6f6cb..ca16780 100644
--- a/packages/flutter_tools/lib/src/resident_runner.dart
+++ b/packages/flutter_tools/lib/src/resident_runner.dart
@@ -6,7 +6,6 @@
import 'package:meta/meta.dart';
-import 'android/gradle.dart';
import 'application_package.dart';
import 'artifacts.dart';
import 'asset.dart';
@@ -24,6 +23,7 @@
import 'devfs.dart';
import 'device.dart';
import 'globals.dart';
+import 'project.dart';
import 'run_cold.dart';
import 'run_hot.dart';
import 'vmservice.dart';
@@ -814,15 +814,11 @@
new DartDependencySetBuilder(mainPath, packagesFilePath);
final DependencyChecker dependencyChecker =
new DependencyChecker(dartDependencySetBuilder, assetBundle);
- final String path = device.package.packagePath;
- if (path == null)
+ if (device.package.packagesFile == null || !device.package.packagesFile.existsSync()) {
return true;
- final FileStat stat = fs.file(path).statSync();
- if (stat.type != FileSystemEntityType.FILE) // ignore: deprecated_member_use
- return true;
- if (!fs.file(path).existsSync())
- return true;
- final DateTime lastBuildTime = stat.modified;
+ }
+ final DateTime lastBuildTime = device.package.packagesFile.statSync().modified;
+
return dependencyChecker.check(lastBuildTime);
}
@@ -906,11 +902,9 @@
case TargetPlatform.android_arm64:
case TargetPlatform.android_x64:
case TargetPlatform.android_x86:
- String manifest = 'android/AndroidManifest.xml';
- if (isProjectUsingGradle()) {
- manifest = gradleManifestPath;
- }
- return 'Is your project missing an $manifest?\nConsider running "flutter create ." to create one.';
+ final FlutterProject project = new FlutterProject(fs.currentDirectory);
+ final String manifestPath = fs.path.relative(project.android.gradleManifestFile.path);
+ return 'Is your project missing an $manifestPath?\nConsider running "flutter create ." to create one.';
case TargetPlatform.ios:
return 'Is your project missing an ios/Runner/Info.plist?\nConsider running "flutter create ." to create one.';
default:
diff --git a/packages/flutter_tools/lib/src/run_cold.dart b/packages/flutter_tools/lib/src/run_cold.dart
index 6273196..a7fddb2 100644
--- a/packages/flutter_tools/lib/src/run_cold.dart
+++ b/packages/flutter_tools/lib/src/run_cold.dart
@@ -30,7 +30,7 @@
ipv6: ipv6);
final bool traceStartup;
- final String applicationBinary;
+ final File applicationBinary;
@override
Future<int> run({
diff --git a/packages/flutter_tools/lib/src/run_hot.dart b/packages/flutter_tools/lib/src/run_hot.dart
index 886140a..f28cf49 100644
--- a/packages/flutter_tools/lib/src/run_hot.dart
+++ b/packages/flutter_tools/lib/src/run_hot.dart
@@ -64,7 +64,7 @@
ipv6: ipv6);
final bool benchmarkMode;
- final String applicationBinary;
+ final File applicationBinary;
final bool hostIsIde;
Set<String> _dartDependencies;
final String dillOutputPath;
diff --git a/packages/flutter_tools/lib/src/tester/flutter_tester.dart b/packages/flutter_tools/lib/src/tester/flutter_tester.dart
index 6d247d1..9fb1973 100644
--- a/packages/flutter_tools/lib/src/tester/flutter_tester.dart
+++ b/packages/flutter_tools/lib/src/tester/flutter_tester.dart
@@ -22,21 +22,21 @@
import '../version.dart';
class FlutterTesterApp extends ApplicationPackage {
- final String _directory;
+ final Directory _directory;
factory FlutterTesterApp.fromCurrentDirectory() {
- return new FlutterTesterApp._(fs.currentDirectory.path);
+ return new FlutterTesterApp._(fs.currentDirectory);
}
- FlutterTesterApp._(String directory)
+ FlutterTesterApp._(Directory directory)
: _directory = directory,
- super(id: directory);
+ super(id: directory.path);
@override
- String get name => fs.path.basename(_directory);
+ String get name => _directory.basename;
@override
- String get packagePath => fs.path.join(_directory, '.packages');
+ File get packagesFile => _directory.childFile('.packages');
}
// TODO(scheglov): This device does not currently work with full restarts.