Unverified Commit 6a8f9041 authored by Sigurd Meldgaard's avatar Sigurd Meldgaard Committed by GitHub

Revert "Use FlutterProject to locate files (#18913)" (#19409)

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