Unverified Commit 57d78cc7 authored by Sigurd Meldgaard's avatar Sigurd Meldgaard Committed by GitHub

Use FlutterProject to locate files (#18913)

parent e7832a38
...@@ -21,6 +21,7 @@ import '../base/utils.dart'; ...@@ -21,6 +21,7 @@ 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';
...@@ -241,7 +242,7 @@ class AndroidDevice extends Device { ...@@ -241,7 +242,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.apkPath}.sha1'); final File shaFile = fs.file('${apk.file.path}.sha1');
return shaFile.existsSync() ? shaFile.readAsStringSync() : ''; return shaFile.existsSync() ? shaFile.readAsStringSync() : '';
} }
...@@ -269,16 +270,16 @@ class AndroidDevice extends Device { ...@@ -269,16 +270,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 (!fs.isFileSync(apk.apkPath)) { if (!apk.file.existsSync()) {
printError('"${apk.apkPath}" does not exist.'); printError('"${apk.file.path}" 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.apkPath}...', expectSlowOperation: true); final Status status = logger.startProgress('Installing ${apk.file.path}...', expectSlowOperation: true);
final RunResult installResult = await runAsync(adbCommandForDevice(<String>['install', '-t', '-r', apk.apkPath])); final RunResult installResult = await runAsync(adbCommandForDevice(<String>['install', '-t', '-r', apk.file.path]));
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.
...@@ -374,12 +375,13 @@ class AndroidDevice extends Device { ...@@ -374,12 +375,13 @@ 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.fromCurrentDirectory(); package = await AndroidApk.fromAndroidProject(new FlutterProject(fs.currentDirectory).android);
} }
printTrace("Stopping app '${package.name}' on $name."); printTrace("Stopping app '${package.name}' on $name.");
......
...@@ -4,17 +4,22 @@ ...@@ -4,17 +4,22 @@
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({
String target, @required FlutterProject project,
@required String target,
BuildInfo buildInfo = BuildInfo.debug BuildInfo buildInfo = BuildInfo.debug
}) async { }) async {
if (!isProjectUsingGradle()) { if (!project.android.isUsingGradle()) {
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'
...@@ -33,5 +38,9 @@ Future<Null> buildApk({ ...@@ -33,5 +38,9 @@ Future<Null> buildApk({
throwToolExit('Try re-installing or updating your Android SDK.'); throwToolExit('Try re-installing or updating your Android SDK.');
} }
return buildGradleProject(buildInfo, target); return buildGradleProject(
project: project,
buildInfo: buildInfo,
target: target,
);
} }
...@@ -4,6 +4,8 @@ ...@@ -4,6 +4,8 @@
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';
...@@ -14,16 +16,13 @@ import '../base/platform.dart'; ...@@ -14,16 +16,13 @@ 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 ');
...@@ -45,9 +44,6 @@ final RegExp ndkMessageFilter = new RegExp(r'^(?!NDK is missing a ".*" directory ...@@ -45,9 +44,6 @@ 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');
...@@ -69,18 +65,17 @@ FlutterPluginVersion get flutterPluginVersion { ...@@ -69,18 +65,17 @@ FlutterPluginVersion get flutterPluginVersion {
return FlutterPluginVersion.none; return FlutterPluginVersion.none;
} }
/// Returns the path to the apk file created by [buildGradleProject], relative /// Returns the apk file created by [buildGradleProject]
/// to current directory. Future<File> getGradleAppOut(AndroidProject androidProject) async {
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 gradleAppOutV1; return androidProject.gradleAppOutV1File;
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.path.relative(fs.path.join((await _gradleProject()).apkDirectory, 'app.apk')); return fs.file((await _gradleProject()).apkDirectory.childFile('app.apk'));
} }
return null; return null;
} }
...@@ -94,12 +89,13 @@ Future<GradleProject> _gradleProject() async { ...@@ -94,12 +89,13 @@ 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();
await updateLocalProperties(); final FlutterProject flutterProject = new FlutterProject(fs.currentDirectory);
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: 'android', workingDirectory: flutterProject.android.directory.path,
environment: _gradleEnv, environment: _gradleEnv,
); );
final String properties = runResult.stdout.trim(); final String properties = runResult.stdout.trim();
...@@ -117,7 +113,7 @@ Future<GradleProject> _readGradleProject() async { ...@@ -117,7 +113,7 @@ Future<GradleProject> _readGradleProject() async {
} }
} }
// Fall back to the default // Fall back to the default
return new GradleProject(<String>['debug', 'profile', 'release'], <String>[], gradleAppOutDirV1); return new GradleProject(<String>['debug', 'profile', 'release'], <String>[], flutterProject.android.gradleAppOutV1Directory);
} }
void handleKnownGradleExceptions(String exceptionString) { void handleKnownGradleExceptions(String exceptionString) {
...@@ -199,28 +195,19 @@ distributionUrl=https\\://services.gradle.org/distributions/gradle-$gradleVersio ...@@ -199,28 +195,19 @@ 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 { ///
final Directory android = (projectPath == null) /// If [requireSdk] is `true` this will fail with a tool-exit if no Android Sdk
? fs.directory('android') /// is found.
: fs.directory(fs.path.join(projectPath, 'android')); Future<void> updateLocalProperties({
final String flutterManifest = (projectPath == null) @required FlutterProject project,
? fs.path.join(bundle.defaultManifestPath) BuildInfo buildInfo,
: fs.path.join(projectPath, bundle.defaultManifestPath); bool requireAndroidSdk = true,
if (androidSdk == null) { }) async {
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);
}
/// Overwrite local.properties in the specified directory, if needed. final File localProperties = await project.androidLocalPropertiesFile;
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;
...@@ -238,6 +225,8 @@ void updateLocalPropertiesSync(Directory android, FlutterManifest manifest, [Bui ...@@ -238,6 +225,8 @@ void updateLocalPropertiesSync(Directory android, FlutterManifest manifest, [Bui
} }
} }
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));
...@@ -254,7 +243,11 @@ void updateLocalPropertiesSync(Directory android, FlutterManifest manifest, [Bui ...@@ -254,7 +243,11 @@ void updateLocalPropertiesSync(Directory android, FlutterManifest manifest, [Bui
settings.writeContents(localProperties); settings.writeContents(localProperties);
} }
Future<Null> buildGradleProject(BuildInfo buildInfo, String target) async { Future<Null> buildGradleProject({
@required FlutterProject project,
@required BuildInfo buildInfo,
@required String target,
}) async {
// Update the local.properties file with the build mode, version name and code. // 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
...@@ -263,7 +256,7 @@ Future<Null> buildGradleProject(BuildInfo buildInfo, String target) async { ...@@ -263,7 +256,7 @@ Future<Null> buildGradleProject(BuildInfo buildInfo, String target) async {
// 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(buildInfo: buildInfo); await updateLocalProperties(project: project, buildInfo: buildInfo);
final String gradle = await _ensureGradle(); final String gradle = await _ensureGradle();
...@@ -271,7 +264,7 @@ Future<Null> buildGradleProject(BuildInfo buildInfo, String target) async { ...@@ -271,7 +264,7 @@ Future<Null> buildGradleProject(BuildInfo buildInfo, String target) async {
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(gradle); return _buildGradleProjectV1(project, 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:
...@@ -279,7 +272,7 @@ Future<Null> buildGradleProject(BuildInfo buildInfo, String target) async { ...@@ -279,7 +272,7 @@ Future<Null> buildGradleProject(BuildInfo buildInfo, String target) async {
} }
} }
Future<Null> _buildGradleProjectV1(String gradle) async { Future<Null> _buildGradleProjectV1(FlutterProject project, 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(
...@@ -293,7 +286,7 @@ Future<Null> _buildGradleProjectV1(String gradle) async { ...@@ -293,7 +286,7 @@ Future<Null> _buildGradleProjectV1(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 $gradleAppOutV1.'); printStatus('Built ${fs.path.relative(project.android.gradleAppOutV1File.path)}.');
} }
Future<Null> _buildGradleProjectV2(String gradle, BuildInfo buildInfo, String target) async { Future<Null> _buildGradleProjectV2(String gradle, BuildInfo buildInfo, String target) async {
...@@ -371,10 +364,10 @@ Future<Null> _buildGradleProjectV2(String gradle, BuildInfo buildInfo, String ta ...@@ -371,10 +364,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(fs.path.join(project.apkDirectory, 'app.apk')); apkFile.copySync(project.apkDirectory.childFile('app.apk').path);
printTrace('calculateSha: ${project.apkDirectory}/app.apk'); printTrace('calculateSha: ${project.apkDirectory}/app.apk');
final File apkShaFile = fs.file(fs.path.join(project.apkDirectory, 'app.apk.sha1')); final File apkShaFile = project.apkDirectory.childFile('app.apk.sha1');
apkShaFile.writeAsStringSync(calculateSha(apkFile)); apkShaFile.writeAsStringSync(calculateSha(apkFile));
String appSize; String appSize;
...@@ -390,15 +383,15 @@ File _findApkFile(GradleProject project, BuildInfo buildInfo) { ...@@ -390,15 +383,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, apkFileName)); File apkFile = fs.file(fs.path.join(project.apkDirectory.path, apkFileName));
if (apkFile.existsSync()) if (apkFile.existsSync())
return apkFile; return apkFile;
apkFile = fs.file(fs.path.join(project.apkDirectory, buildInfo.modeName, apkFileName)); apkFile = fs.file(fs.path.join(project.apkDirectory.path, buildInfo.modeName, apkFileName));
if (apkFile.existsSync()) 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, buildInfo.flavor, buildInfo.modeName, apkFileName)); apkFile = fs.file(fs.path.join(project.apkDirectory.path, buildInfo.flavor, buildInfo.modeName, apkFileName));
if (apkFile.existsSync()) if (apkFile.existsSync())
return apkFile; return apkFile;
} }
...@@ -453,13 +446,13 @@ class GradleProject { ...@@ -453,13 +446,13 @@ class GradleProject {
return new GradleProject( return new GradleProject(
buildTypes.toList(), buildTypes.toList(),
productFlavors.toList(), productFlavors.toList(),
fs.path.normalize(fs.path.join(buildDir, 'outputs', 'apk')), fs.directory(fs.path.join(buildDir, 'outputs', 'apk')),
); );
} }
final List<String> buildTypes; final List<String> buildTypes;
final List<String> productFlavors; final List<String> productFlavors;
final String apkDirectory; final Directory apkDirectory;
String _buildTypeFor(BuildInfo buildInfo) { String _buildTypeFor(BuildInfo buildInfo) {
if (buildTypes.contains(buildInfo.modeName)) if (buildTypes.contains(buildInfo.modeName))
......
...@@ -18,6 +18,7 @@ import 'globals.dart'; ...@@ -18,6 +18,7 @@ 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 {
...@@ -31,7 +32,7 @@ abstract class ApplicationPackage { ...@@ -31,7 +32,7 @@ abstract class ApplicationPackage {
String get displayName => name; String get displayName => name;
String get packagePath => null; File get packagesFile => null;
@override @override
String toString() => displayName; String toString() => displayName;
...@@ -39,21 +40,21 @@ abstract class ApplicationPackage { ...@@ -39,21 +40,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 String apkPath; final File file;
/// 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.apkPath, @required this.file,
@required this.launchActivity @required this.launchActivity
}) : assert(apkPath != null), }) : assert(file != 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(String applicationBinary) { factory AndroidApk.fromApk(File apk) {
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\'.');
...@@ -64,7 +65,7 @@ class AndroidApk extends ApplicationPackage { ...@@ -64,7 +65,7 @@ class AndroidApk extends ApplicationPackage {
aaptPath, aaptPath,
'dump', 'dump',
'xmltree', 'xmltree',
applicationBinary, apk.path,
'AndroidManifest.xml', 'AndroidManifest.xml',
]; ];
...@@ -72,47 +73,46 @@ class AndroidApk extends ApplicationPackage { ...@@ -72,47 +73,46 @@ class AndroidApk extends ApplicationPackage {
.parseFromXmlDump(runCheckedSync(aaptArgs)); .parseFromXmlDump(runCheckedSync(aaptArgs));
if (data == null) { if (data == null) {
printError('Unable to read manifest info from $applicationBinary.'); printError('Unable to read manifest info from ${apk.path}.');
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 $applicationBinary.'); printError('Unable to read manifest info from ${apk.path}.');
return null; return null;
} }
return new AndroidApk( return new AndroidApk(
id: data.packageName, id: data.packageName,
apkPath: applicationBinary, file: apk,
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> fromCurrentDirectory() async { static Future<AndroidApk> fromAndroidProject(AndroidProject androidProject) async {
String manifestPath; File apkFile;
String apkPath;
if (isProjectUsingGradle()) { if (androidProject.isUsingGradle()) {
apkPath = await getGradleAppOut(); apkFile = await getGradleAppOut(androidProject);
if (fs.file(apkPath).existsSync()) { if (apkFile.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(apkPath); return new AndroidApk.fromApk(apkFile);
} }
// 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 {
manifestPath = fs.path.join('android', 'AndroidManifest.xml'); apkFile = fs.file(fs.path.join(getAndroidBuildDirectory(), 'app.apk'));
apkPath = fs.path.join(getAndroidBuildDirectory(), 'app.apk');
} }
if (!fs.isFileSync(manifestPath)) final File manifest = androidProject.gradleManifestFile;
if (!manifest.existsSync())
return null; return null;
final String manifestString = fs.file(manifestPath).readAsStringSync(); final String manifestString = manifest.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,
apkPath: apkPath, file: apkFile,
launchActivity: launchActivity launchActivity: launchActivity
); );
} }
@override @override
String get packagePath => apkPath; File get packagesFile => file;
@override @override
String get name => fs.path.basename(apkPath); String get name => file.basename;
} }
/// 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(String applicationBinary) { factory IOSApp.fromPrebuiltApp(File applicationBinary) {
final FileSystemEntityType entityType = fs.typeSync(applicationBinary); final FileSystemEntityType entityType = fs.typeSync(applicationBinary.path);
if (entityType == FileSystemEntityType.notFound) { if (entityType == FileSystemEntityType.notFound) {
printError( printError(
'File "$applicationBinary" does not exist. Use an app bundle or an ipa.'); 'File "${applicationBinary.path}" does not exist. Use an app bundle or an ipa.');
return null; 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" is not an app bundle.'); printError('Folder "${applicationBinary.path}" 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(TargetPlatform platform, { Future<ApplicationPackage> getApplicationPackageForPlatform(
String applicationBinary TargetPlatform platform,
}) async { {File applicationBinary}) 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.fromCurrentDirectory() ? await AndroidApk.fromAndroidProject(new FlutterProject(fs.currentDirectory).android)
: 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.fromCurrentDirectory(); android ??= await AndroidApk.fromAndroidProject(new FlutterProject(fs.currentDirectory).android);
return android; return android;
case TargetPlatform.ios: case TargetPlatform.ios:
iOS ??= new IOSApp.fromCurrentDirectory(); iOS ??= new IOSApp.fromCurrentDirectory();
......
...@@ -5,6 +5,8 @@ ...@@ -5,6 +5,8 @@
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 {
...@@ -44,6 +46,6 @@ class BuildApkCommand extends BuildSubCommand { ...@@ -44,6 +46,6 @@ class BuildApkCommand extends BuildSubCommand {
@override @override
Future<Null> runCommand() async { Future<Null> runCommand() async {
await super.runCommand(); await super.runCommand();
await buildApk(buildInfo: getBuildInfo(), target: targetFile); await buildApk(project: new FlutterProject(fs.currentDirectory),target: targetFile, buildInfo: getBuildInfo());
} }
} }
...@@ -168,20 +168,19 @@ class CreateCommand extends FlutterCommand { ...@@ -168,20 +168,19 @@ class CreateCommand extends FlutterCommand {
printStatus('Creating project ${fs.path.relative(dirPath)}...'); printStatus('Creating project ${fs.path.relative(dirPath)}...');
int generatedFileCount = 0; int generatedFileCount = 0;
String appPath = dirPath; final FlutterProject project = new FlutterProject.fromPath(dirPath);
switch (template) { switch (template) {
case 'app': case 'app':
generatedFileCount += await _generateApp(dirPath, templateContext); generatedFileCount += await _generateApp(project, templateContext);
break; break;
case 'module': case 'module':
generatedFileCount += await _generateModule(dirPath, templateContext); generatedFileCount += await _generateModule(project, templateContext);
break; break;
case 'package': case 'package':
generatedFileCount += await _generatePackage(dirPath, templateContext); generatedFileCount += await _generatePackage(project, templateContext);
break; break;
case 'plugin': case 'plugin':
appPath = fs.path.join(dirPath, 'example'); generatedFileCount += await _generatePlugin(project, templateContext);
generatedFileCount += await _generatePlugin(dirPath, appPath, templateContext);
break; break;
} }
printStatus('Wrote $generatedFileCount files.'); printStatus('Wrote $generatedFileCount files.');
...@@ -194,7 +193,8 @@ class CreateCommand extends FlutterCommand { ...@@ -194,7 +193,8 @@ 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 String relativeAppPath = fs.path.relative(appPath); final FlutterProject app = project.hasExampleApp ? project.example : project;
final String relativeAppPath = fs.path.relative(app.directory.path);
final String relativePluginPath = fs.path.relative(dirPath); 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,60 +233,59 @@ To edit platform code in an IDE see https://flutter.io/developing-packages/#edit ...@@ -233,60 +233,59 @@ To edit platform code in an IDE see https://flutter.io/developing-packages/#edit
} }
} }
Future<int> _generateModule(String path, Map<String, dynamic> templateContext) async { Future<int> _generateModule(FlutterProject project, 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'), path, templateContext); generatedCount += _renderTemplate(fs.path.join('module', 'common'), project.directory, templateContext);
if (argResults['pub']) { if (argResults['pub']) {
await pubGet( await pubGet(
context: PubContext.create, context: PubContext.create,
directory: path, directory: project.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(String dirPath, Map<String, dynamic> templateContext) async { Future<int> _generatePackage(FlutterProject project, 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', dirPath, templateContext); generatedCount += _renderTemplate('package', project.directory, templateContext);
if (argResults['pub']) { if (argResults['pub']) {
await pubGet( await pubGet(
context: PubContext.createPackage, context: PubContext.createPackage,
directory: dirPath, directory: project.directory.path,
offline: argResults['offline'], offline: argResults['offline'],
); );
} }
return generatedCount; return generatedCount;
} }
Future<int> _generatePlugin(String dirPath, String appPath, Map<String, dynamic> templateContext) async { Future<int> _generatePlugin(FlutterProject project, Map<String, dynamic> templateContext) async {
int generatedCount = 0; 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', dirPath, templateContext); generatedCount += _renderTemplate('plugin', project.directory, templateContext);
if (argResults['pub']) { if (argResults['pub']) {
await pubGet( await pubGet(
context: PubContext.createPlugin, context: PubContext.createPlugin,
directory: dirPath, directory: project.directory.path,
offline: argResults['offline'], offline: argResults['offline'],
); );
} }
if (android_sdk.androidSdk != null) if (android_sdk.androidSdk != null)
await gradle.updateLocalProperties(projectPath: dirPath); await gradle.updateLocalProperties(project: project);
final String projectName = templateContext['projectName']; final String projectName = templateContext['projectName'];
final String organization = templateContext['organization']; final String organization = templateContext['organization'];
...@@ -299,27 +298,27 @@ To edit platform code in an IDE see https://flutter.io/developing-packages/#edit ...@@ -299,27 +298,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(appPath, templateContext); generatedCount += await _generateApp(project.example, templateContext);
return generatedCount; return generatedCount;
} }
Future<int> _generateApp(String projectPath, Map<String, dynamic> templateContext) async { Future<int> _generateApp(FlutterProject project, Map<String, dynamic> templateContext) async {
int generatedCount = 0; int generatedCount = 0;
generatedCount += _renderTemplate('create', projectPath, templateContext); generatedCount += _renderTemplate('create', project.directory, templateContext);
generatedCount += _injectGradleWrapper(projectPath); generatedCount += _injectGradleWrapper(project);
if (argResults['with-driver-test']) { if (argResults['with-driver-test']) {
final String testPath = fs.path.join(projectPath, 'test_driver'); final Directory testDirectory = project.directory.childDirectory('test_driver');
generatedCount += _renderTemplate('driver', testPath, templateContext); generatedCount += _renderTemplate('driver', testDirectory, templateContext);
} }
if (argResults['pub']) { if (argResults['pub']) {
await pubGet(context: PubContext.create, directory: projectPath, offline: argResults['offline']); await pubGet(context: PubContext.create, directory: project.directory.path, offline: argResults['offline']);
await new FlutterProject.fromPath(projectPath).ensureReadyForPlatformSpecificTooling(); await project.ensureReadyForPlatformSpecificTooling();
} }
if (android_sdk.androidSdk != null) if (android_sdk.androidSdk != null)
await gradle.updateLocalProperties(projectPath: projectPath); await gradle.updateLocalProperties(project: project);
return generatedCount; return generatedCount;
} }
...@@ -362,16 +361,16 @@ To edit platform code in an IDE see https://flutter.io/developing-packages/#edit ...@@ -362,16 +361,16 @@ To edit platform code in an IDE see https://flutter.io/developing-packages/#edit
}; };
} }
int _renderTemplate(String templateName, String dirPath, Map<String, dynamic> context) { int _renderTemplate(String templateName, Directory directory, Map<String, dynamic> context) {
final Template template = new Template.fromName(templateName); final Template template = new Template.fromName(templateName);
return template.render(fs.directory(dirPath), context, overwriteExisting: false); return template.render(directory, context, overwriteExisting: false);
} }
int _injectGradleWrapper(String projectDir) { int _injectGradleWrapper(FlutterProject project) {
int filesCreated = 0; int filesCreated = 0;
copyDirectorySync( copyDirectorySync(
cache.getArtifactDirectory('gradle_wrapper'), cache.getArtifactDirectory('gradle_wrapper'),
fs.directory(fs.path.join(projectDir, 'android')), project.android.directory,
(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, {
String applicationBinary, File 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,10 +26,9 @@ class InjectPluginsCommand extends FlutterCommand { ...@@ -26,10 +26,9 @@ class InjectPluginsCommand extends FlutterCommand {
@override @override
Future<Null> runCommand() async { Future<Null> runCommand() async {
final String projectPath = fs.currentDirectory.path; final FlutterProject project = new FlutterProject(fs.currentDirectory);
final FlutterManifest manifest = await FlutterManifest.createFromPath(projectPath); await injectPlugins(project);
injectPlugins(projectPath: projectPath, manifest: manifest); final bool result = hasPlugins(project);
final bool result = hasPlugins();
if (result) { if (result) {
printStatus('GeneratedPluginRegistrants successfully written.'); printStatus('GeneratedPluginRegistrants successfully written.');
} else { } else {
......
...@@ -289,10 +289,13 @@ class RunCommand extends RunCommandBase { ...@@ -289,10 +289,13 @@ 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: argResults['use-application-binary'], applicationBinary: applicationBinaryPath == null
? 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 Directory appIosDirectory, @required IosProject iosProject,
// 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 appIosDirectory.childFile('Podfile').exists())) { if (!(await iosProject.podfile.exists())) {
throwToolExit('Podfile missing'); throwToolExit('Podfile missing');
} }
if (await _checkPodCondition()) { if (await _checkPodCondition()) {
if (_shouldRunPodInstall(appIosDirectory, dependenciesChanged)) { if (_shouldRunPodInstall(iosProject, dependenciesChanged)) {
await _runPodInstall(appIosDirectory, iosEngineDir); await _runPodInstall(iosProject, 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(String appDirectory, FlutterManifest manifest) { void setupPodfile(IosProject iosProject) {
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 (!fs.directory(fs.path.join(appDirectory, 'ios')).existsSync()) { if (!iosProject.directory.existsSync()) {
return; return;
} }
final String podfilePath = fs.path.join(appDirectory, 'ios', 'Podfile'); final File podfile = iosProject.podfile;
if (!fs.file(podfilePath).existsSync()) { if (!podfile.existsSync()) {
final bool isSwift = xcodeProjectInterpreter.getBuildSettings( final bool isSwift = xcodeProjectInterpreter.getBuildSettings(
fs.path.join(appDirectory, 'ios', 'Runner.xcodeproj'), iosProject.directory.childFile('Runner.xcodeproj').path,
'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,15 +173,14 @@ class CocoaPods { ...@@ -173,15 +173,14 @@ class CocoaPods {
'cocoapods', 'cocoapods',
isSwift ? 'Podfile-swift' : 'Podfile-objc', isSwift ? 'Podfile-swift' : 'Podfile-objc',
)); ));
podfileTemplate.copySync(podfilePath); podfileTemplate.copySync(podfile.path);
} }
_addPodsDependencyToFlutterXcconfig(iosProject, 'Debug');
_addPodsDependencyToFlutterXcconfig(appDirectory, 'Debug'); _addPodsDependencyToFlutterXcconfig(iosProject, 'Release');
_addPodsDependencyToFlutterXcconfig(appDirectory, 'Release');
} }
void _addPodsDependencyToFlutterXcconfig(String appDirectory, String mode) { void _addPodsDependencyToFlutterXcconfig(IosProject iosProject, String mode) {
final File file = fs.file(fs.path.join(appDirectory, 'ios', 'Flutter', '$mode.xcconfig')); final File file = iosProject.xcodeConfigFor(mode);
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
...@@ -192,12 +191,11 @@ class CocoaPods { ...@@ -192,12 +191,11 @@ class CocoaPods {
} }
/// Ensures that pod install is deemed needed on next check. /// Ensures that pod install is deemed needed on next check.
void invalidatePodInstallOutput(String appDirectory) { void invalidatePodInstallOutput(IosProject iosProject) {
final File manifest = fs.file( final File manifestLock = iosProject.podManifestLock;
fs.path.join(appDirectory, 'ios', 'Pods', 'Manifest.lock'), if (manifestLock.existsSync()) {
); manifestLock.deleteSync();
if (manifest.existsSync()) }
manifest.deleteSync();
} }
// Check if you need to run pod install. // Check if you need to run pod install.
...@@ -206,24 +204,25 @@ class CocoaPods { ...@@ -206,24 +204,25 @@ 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(Directory appIosDirectory, bool dependenciesChanged) { bool _shouldRunPodInstall(IosProject iosProject, bool dependenciesChanged) {
if (dependenciesChanged) if (dependenciesChanged)
return true; return true;
final File podfileFile = appIosDirectory.childFile('Podfile');
final File podfileLockFile = appIosDirectory.childFile('Podfile.lock'); final File podfileFile = iosProject.podfile;
final File manifestLockFile = final File podfileLockFile = iosProject.podfileLock;
appIosDirectory.childFile(fs.path.join('Pods', 'Manifest.lock')); final File manifestLockFile = iosProject.podManifestLock;
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(Directory appIosDirectory, String engineDirectory) async { Future<Null> _runPodInstall(IosProject iosProject, 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: appIosDirectory.path, workingDirectory: iosProject.directory.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,
...@@ -244,7 +243,7 @@ class CocoaPods { ...@@ -244,7 +243,7 @@ class CocoaPods {
} }
} }
if (result.exitCode != 0) { if (result.exitCode != 0) {
invalidatePodInstallOutput(appIosDirectory.parent.path); invalidatePodInstallOutput(iosProject);
_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,18 +221,15 @@ Future<XcodeBuildResult> buildXcodeProject({ ...@@ -221,18 +221,15 @@ Future<XcodeBuildResult> buildXcodeProject({
final Directory appDirectory = fs.directory(app.appDirectory); final Directory appDirectory = fs.directory(app.appDirectory);
await _addServicesToBundle(appDirectory); await _addServicesToBundle(appDirectory);
final FlutterManifest manifest = await FlutterManifest.createFromPath( final FlutterProject project = new FlutterProject(fs.currentDirectory);
fs.currentDirectory.childFile('pubspec.yaml').path, await updateGeneratedXcodeProperties(
); project: project,
updateGeneratedXcodeProperties(
projectPath: fs.currentDirectory.path,
buildInfo: buildInfo,
targetOverride: targetOverride, targetOverride: targetOverride,
previewDart2: buildInfo.previewDart2, previewDart2: buildInfo.previewDart2,
manifest: manifest, buildInfo: buildInfo,
); );
if (hasPlugins()) { if (hasPlugins(project)) {
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.
...@@ -246,7 +243,7 @@ Future<XcodeBuildResult> buildXcodeProject({ ...@@ -246,7 +243,7 @@ Future<XcodeBuildResult> buildXcodeProject({
properties: <String, String>{}, properties: <String, String>{},
); );
final bool didPodInstall = await cocoaPods.processPods( final bool didPodInstall = await cocoaPods.processPods(
appIosDirectory: appDirectory, iosProject: project.ios,
iosEngineDir: flutterFrameworkDir(buildInfo.mode), iosEngineDir: flutterFrameworkDir(buildInfo.mode),
isSwift: app.isSwift, isSwift: app.isSwift,
dependenciesChanged: !await fingerprinter.doesFingerprintMatch() dependenciesChanged: !await fingerprinter.doesFingerprintMatch()
......
...@@ -2,6 +2,8 @@ ...@@ -2,6 +2,8 @@
// 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';
...@@ -17,6 +19,7 @@ import '../bundle.dart' as bundle; ...@@ -17,6 +19,7 @@ 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'\$\((.*)\)');
...@@ -25,27 +28,18 @@ String flutterFrameworkDir(BuildMode mode) { ...@@ -25,27 +28,18 @@ 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.
void generateXcodeProperties({String projectPath, FlutterManifest manifest}) { Future<void> generateXcodeProperties({FlutterProject project}) async {
if (manifest.isModule || fs.isDirectorySync(fs.path.join(projectPath, 'ios'))) { if ((await project.manifest).isModule ||
final File propertiesFile = fs.file(_generatedXcodePropertiesPath(projectPath: projectPath, manifest: manifest)); project.ios.directory.existsSync()) {
if (!Cache.instance.fileOlderThanToolsStamp(propertiesFile)) { if (!Cache.instance.fileOlderThanToolsStamp(await project.generatedXcodePropertiesFile)) {
return; return;
} }
updateGeneratedXcodeProperties( await updateGeneratedXcodeProperties(
projectPath: projectPath, project: project,
manifest: manifest,
buildInfo: BuildInfo.debug, buildInfo: BuildInfo.debug,
targetOverride: bundle.defaultMainPath, targetOverride: bundle.defaultMainPath,
previewDart2: true, previewDart2: true,
...@@ -57,13 +51,12 @@ void generateXcodeProperties({String projectPath, FlutterManifest manifest}) { ...@@ -57,13 +51,12 @@ void generateXcodeProperties({String projectPath, FlutterManifest manifest}) {
/// ///
/// 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'.
void updateGeneratedXcodeProperties({ Future<void> updateGeneratedXcodeProperties({
@required String projectPath, @required FlutterProject project,
@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.');
...@@ -72,7 +65,7 @@ void updateGeneratedXcodeProperties({ ...@@ -72,7 +65,7 @@ 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(projectPath)}'); localsBuffer.writeln('FLUTTER_APPLICATION_PATH=${fs.path.normalize(project.directory.path)}');
// Relative to FLUTTER_APPLICATION_PATH, which is [Directory.current]. // Relative to FLUTTER_APPLICATION_PATH, which is [Directory.current].
if (targetOverride != null) if (targetOverride != null)
...@@ -86,6 +79,7 @@ void updateGeneratedXcodeProperties({ ...@@ -86,6 +79,7 @@ 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
...@@ -125,9 +119,9 @@ void updateGeneratedXcodeProperties({ ...@@ -125,9 +119,9 @@ void updateGeneratedXcodeProperties({
localsBuffer.writeln('TRACK_WIDGET_CREATION=true'); localsBuffer.writeln('TRACK_WIDGET_CREATION=true');
} }
final File localsFile = fs.file(_generatedXcodePropertiesPath(projectPath: projectPath, manifest: manifest)); final File generatedXcodePropertiesFile = await project.generatedXcodePropertiesFile;
localsFile.createSync(recursive: true); generatedXcodePropertiesFile.createSync(recursive: true);
localsFile.writeAsStringSync(localsBuffer.toString()); generatedXcodePropertiesFile.writeAsStringSync(localsBuffer.toString());
} }
XcodeProjectInterpreter get xcodeProjectInterpreter => context[XcodeProjectInterpreter]; XcodeProjectInterpreter get xcodeProjectInterpreter => context[XcodeProjectInterpreter];
......
...@@ -2,15 +2,16 @@ ...@@ -2,15 +2,16 @@
// 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 'package:meta/meta.dart'; import 'dart:async';
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 =
...@@ -69,11 +70,11 @@ Plugin _pluginFromPubspec(String name, Uri packageRoot) { ...@@ -69,11 +70,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(String directory) { List<Plugin> findPlugins(FlutterProject project) {
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(directory, PackageMap.globalPackagesPath); final String packagesFile = fs.path.join(project.directory.path, 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');
...@@ -89,9 +90,9 @@ List<Plugin> findPlugins(String directory) { ...@@ -89,9 +90,9 @@ List<Plugin> findPlugins(String directory) {
} }
/// Returns true if .flutter-plugins has changed, otherwise returns false. /// Returns true if .flutter-plugins has changed, otherwise returns false.
bool _writeFlutterPluginsList(String directory, List<Plugin> plugins) { bool _writeFlutterPluginsList(FlutterProject project, List<Plugin> plugins) {
final File pluginsFile = fs.file(fs.path.join(directory, '.flutter-plugins')); final File pluginsFile = project.flutterPluginsFile;
final String oldContents = _readFlutterPluginsList(directory); final String oldContents = _readFlutterPluginsList(project);
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) {
...@@ -100,15 +101,16 @@ bool _writeFlutterPluginsList(String directory, List<Plugin> plugins) { ...@@ -100,15 +101,16 @@ bool _writeFlutterPluginsList(String directory, List<Plugin> plugins) {
if (pluginsFile.existsSync()) if (pluginsFile.existsSync())
pluginsFile.deleteSync(); pluginsFile.deleteSync();
} }
final String newContents = _readFlutterPluginsList(directory); final String newContents = _readFlutterPluginsList(project);
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(String directory) { String _readFlutterPluginsList(FlutterProject project) {
final File pluginsFile = fs.file(fs.path.join(directory, '.flutter-plugins')); return project.flutterPluginsFile.existsSync()
return pluginsFile.existsSync() ? pluginsFile.readAsStringSync() : null; ? project.flutterPluginsFile.readAsStringSync()
: null;
} }
const String _androidPluginRegistryTemplate = '''package io.flutter.plugins; const String _androidPluginRegistryTemplate = '''package io.flutter.plugins;
...@@ -142,7 +144,7 @@ public final class GeneratedPluginRegistrant { ...@@ -142,7 +144,7 @@ public final class GeneratedPluginRegistrant {
} }
'''; ''';
void _writeAndroidPluginRegistrant(String directory, List<Plugin> plugins) { Future<void> _writeAndroidPluginRegistrant(FlutterProject project, List<Plugin> plugins) async {
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>{
...@@ -155,8 +157,19 @@ void _writeAndroidPluginRegistrant(String directory, List<Plugin> plugins) { ...@@ -155,8 +157,19 @@ void _writeAndroidPluginRegistrant(String directory, List<Plugin> plugins) {
'plugins': androidPlugins, 'plugins': androidPlugins,
}; };
final String javaSourcePath = fs.path.join(directory, 'src', 'main', 'java'); final String javaSourcePath = fs.path.join(
final String registryPath = fs.path.join(javaSourcePath, 'io', 'flutter', 'plugins', 'GeneratedPluginRegistrant.java'); (await project.androidPluginRegistrantHost).path,
'src',
'main',
'java',
);
final String registryPath = fs.path.join(
javaSourcePath,
'io',
'flutter',
'plugins',
'GeneratedPluginRegistrant.java',
);
_renderTemplateToFile(_androidPluginRegistryTemplate, context, registryPath); _renderTemplateToFile(_androidPluginRegistryTemplate, context, registryPath);
} }
...@@ -221,7 +234,7 @@ Depends on all your plugins, and provides a function to register them. ...@@ -221,7 +234,7 @@ Depends on all your plugins, and provides a function to register them.
end end
'''; ''';
void _writeIOSPluginRegistrant(String directory, FlutterManifest manifest, List<Plugin> plugins) { Future<void> _writeIOSPluginRegistrant(FlutterProject project, List<Plugin> plugins) async {
final List<Map<String, dynamic>> iosPlugins = plugins 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>{
...@@ -234,10 +247,8 @@ void _writeIOSPluginRegistrant(String directory, FlutterManifest manifest, List< ...@@ -234,10 +247,8 @@ void _writeIOSPluginRegistrant(String directory, FlutterManifest manifest, List<
'plugins': iosPlugins, 'plugins': iosPlugins,
}; };
if (manifest.isModule) { final String registryDirectory = (await project.iosPluginRegistrantHost).path;
// In a module create the GeneratedPluginRegistrant as a pod to be included if ((await project.manifest).isModule) {
// 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,
...@@ -255,57 +266,37 @@ void _writeIOSPluginRegistrant(String directory, FlutterManifest manifest, List< ...@@ -255,57 +266,37 @@ void _writeIOSPluginRegistrant(String directory, FlutterManifest manifest, List<
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(runnerDirectory, 'GeneratedPluginRegistrant.h'), fs.path.join(registryDirectory, 'GeneratedPluginRegistrant.h'),
); );
_renderTemplateToFile( _renderTemplateToFile(
_iosPluginRegistryImplementationTemplate, _iosPluginRegistryImplementationTemplate,
context, context,
fs.path.join(runnerDirectory, 'GeneratedPluginRegistrant.m'), fs.path.join(registryDirectory, 'GeneratedPluginRegistrant.m'),
); );
} }
} }
class InjectPluginsResult{
InjectPluginsResult({
@required this.hasPlugin,
@required this.hasChanged,
});
/// True if any flutter plugin exists, otherwise false.
final bool hasPlugin;
/// True if plugins have changed since last build.
final bool hasChanged;
}
/// Injects plugins found in `pubspec.yaml` into the platform-specific projects. /// Injects plugins found in `pubspec.yaml` into the platform-specific projects.
void injectPlugins({@required String projectPath, @required FlutterManifest manifest}) { Future<void> injectPlugins(FlutterProject project) async {
final List<Plugin> plugins = findPlugins(projectPath); final List<Plugin> plugins = findPlugins(project);
final bool changed = _writeFlutterPluginsList(projectPath, plugins); final bool changed = _writeFlutterPluginsList(project, plugins);
if (manifest.isModule) { await _writeAndroidPluginRegistrant(project, plugins);
_writeAndroidPluginRegistrant(fs.path.join(projectPath, '.android', 'Flutter'), plugins); await _writeIOSPluginRegistrant(project, plugins);
} else if (fs.isDirectorySync(fs.path.join(projectPath, 'android', 'app'))) {
_writeAndroidPluginRegistrant(fs.path.join(projectPath, 'android', 'app'), plugins); if (project.ios.directory.existsSync()) {
}
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(projectPath, manifest); cocoaPods.setupPodfile(project.ios);
if (changed) if (changed)
cocoaPods.invalidatePodInstallOutput(projectPath); cocoaPods.invalidatePodInstallOutput(project.ios);
} }
} }
/// 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({String directory}) { bool hasPlugins(FlutterProject project) {
directory ??= fs.currentDirectory.path; return _readFlutterPluginsList(project) != null;
return _readFlutterPluginsList(directory) != null;
} }
...@@ -5,7 +5,6 @@ ...@@ -5,7 +5,6 @@
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;
...@@ -67,6 +66,57 @@ class FlutterProject { ...@@ -67,6 +66,57 @@ 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();
...@@ -86,11 +136,11 @@ class FlutterProject { ...@@ -86,11 +136,11 @@ class FlutterProject {
} }
final FlutterManifest manifest = await this.manifest; final FlutterManifest manifest = await this.manifest;
if (manifest.isModule) { if (manifest.isModule) {
await androidModule.ensureReadyForPlatformSpecificTooling(manifest); await androidModule.ensureReadyForPlatformSpecificTooling(this);
await iosModule.ensureReadyForPlatformSpecificTooling(manifest); await iosModule.ensureReadyForPlatformSpecificTooling();
} }
xcode.generateXcodeProperties(projectPath: directory.path, manifest: manifest); await xcode.generateXcodeProperties(project: this);
injectPlugins(projectPath: directory.path, manifest: manifest); await injectPlugins(this);
} }
} }
...@@ -101,6 +151,20 @@ class IosProject { ...@@ -101,6 +151,20 @@ 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));
...@@ -114,7 +178,7 @@ class IosModuleProject { ...@@ -114,7 +178,7 @@ class IosModuleProject {
final Directory directory; final Directory directory;
Future<void> ensureReadyForPlatformSpecificTooling(FlutterManifest manifest) async { Future<void> ensureReadyForPlatformSpecificTooling() 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);
...@@ -133,6 +197,29 @@ class AndroidProject { ...@@ -133,6 +197,29 @@ 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() {
...@@ -153,15 +240,15 @@ class AndroidModuleProject { ...@@ -153,15 +240,15 @@ class AndroidModuleProject {
final Directory directory; final Directory directory;
Future<void> ensureReadyForPlatformSpecificTooling(FlutterManifest manifest) async { Future<void> ensureReadyForPlatformSpecificTooling(FlutterProject project) 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': manifest.moduleDescriptor['androidPackage'], 'androidIdentifier': (await project.manifest).moduleDescriptor['androidPackage'],
}, printStatusWhenWriting: false); }, printStatusWhenWriting: false);
gradle.injectGradleWrapper(directory); gradle.injectGradleWrapper(directory);
} }
gradle.updateLocalPropertiesSync(directory, manifest); await gradle.updateLocalProperties(project: project, requireAndroidSdk: false);
} }
bool _shouldRegenerate() { bool _shouldRegenerate() {
......
...@@ -6,7 +6,6 @@ import 'dart:async'; ...@@ -6,7 +6,6 @@ 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';
...@@ -24,6 +23,7 @@ import 'dependency_checker.dart'; ...@@ -24,6 +23,7 @@ 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,15 +814,11 @@ abstract class ResidentRunner { ...@@ -814,15 +814,11 @@ 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);
final String path = device.package.packagePath; if (device.package.packagesFile == null || !device.package.packagesFile.existsSync()) {
if (path == null)
return true; return true;
final FileStat stat = fs.file(path).statSync(); }
if (stat.type != FileSystemEntityType.FILE) // ignore: deprecated_member_use final DateTime lastBuildTime = device.package.packagesFile.statSync().modified;
return true;
if (!fs.file(path).existsSync())
return true;
final DateTime lastBuildTime = stat.modified;
return dependencyChecker.check(lastBuildTime); return dependencyChecker.check(lastBuildTime);
} }
...@@ -906,11 +902,9 @@ String getMissingPackageHintForPlatform(TargetPlatform platform) { ...@@ -906,11 +902,9 @@ 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:
String manifest = 'android/AndroidManifest.xml'; final FlutterProject project = new FlutterProject(fs.currentDirectory);
if (isProjectUsingGradle()) { final String manifestPath = fs.path.relative(project.android.gradleManifestFile.path);
manifest = gradleManifestPath; return 'Is your project missing an $manifestPath?\nConsider running "flutter create ." to create one.';
}
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 String applicationBinary; final File 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 String applicationBinary; final File 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 String _directory; final Directory _directory;
factory FlutterTesterApp.fromCurrentDirectory() { factory FlutterTesterApp.fromCurrentDirectory() {
return new FlutterTesterApp._(fs.currentDirectory.path); return new FlutterTesterApp._(fs.currentDirectory);
} }
FlutterTesterApp._(String directory) FlutterTesterApp._(Directory directory)
: _directory = directory, : _directory = directory,
super(id: directory); super(id: directory.path);
@override @override
String get name => fs.path.basename(_directory); String get name => _directory.basename;
@override @override
String get packagePath => fs.path.join(_directory, '.packages'); File get packagesFile => _directory.childFile('.packages');
} }
// TODO(scheglov): This device does not currently work with full restarts. // TODO(scheglov): This device does not currently work with full restarts.
......
...@@ -11,6 +11,7 @@ import 'package:flutter_tools/src/base/file_system.dart'; ...@@ -11,6 +11,7 @@ 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';
...@@ -31,7 +32,7 @@ void main() { ...@@ -31,7 +32,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(); await updateLocalProperties(project: new FlutterProject(fs.currentDirectory));
} on Exception catch (e) { } on Exception catch (e) {
shouldBeToolExit = e; shouldBeToolExit = e;
} }
...@@ -69,7 +70,10 @@ someProperty: someValue ...@@ -69,7 +70,10 @@ someProperty: someValue
buildDir: /Users/some/apps/hello/build/app buildDir: /Users/some/apps/hello/build/app
someOtherProperty: someOtherValue someOtherProperty: someOtherValue
'''); ''');
expect(project.apkDirectory, fs.path.normalize('/Users/some/apps/hello/build/app/outputs/apk')); expect(
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('''
...@@ -110,27 +114,27 @@ someOtherProperty: someOtherValue ...@@ -110,27 +114,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>[], '/some/dir'); final GradleProject project = new GradleProject(<String>['debug', 'profile', 'release'], <String>[], fs.directory('/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'], '/some/dir'); final GradleProject project = new GradleProject(<String>['debug', 'profile', 'release'], <String>['free', 'paid'], fs.directory('/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>[], '/some/dir'); final GradleProject project = new GradleProject(<String>['debug', 'profile', 'release'], <String>[], fs.directory('/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'], '/some/dir'); final GradleProject project = new GradleProject(<String>['debug', 'profile', 'release'], <String>['free', 'paid'], fs.directory('/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);
...@@ -185,7 +189,10 @@ someOtherProperty: someOtherValue ...@@ -185,7 +189,10 @@ someOtherProperty: someOtherValue
writeSchemaFile(fs, schemaData); writeSchemaFile(fs, schemaData);
try { try {
await updateLocalProperties(projectPath: 'path/to/project', buildInfo: buildInfo); await updateLocalProperties(
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('not_existing.ipa'); new IOSApp.fromPrebuiltApp(fs.file('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('regular_folder'); new IOSApp.fromPrebuiltApp(fs.file('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('bundle.app'); final PrebuiltIOSApp iosApp = new IOSApp.fromPrebuiltApp(fs.file('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('bundle.app'); final PrebuiltIOSApp iosApp = new IOSApp.fromPrebuiltApp(fs.file('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('bundle.app'); final PrebuiltIOSApp iosApp = new IOSApp.fromPrebuiltApp(fs.file('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('app.ipa'); final PrebuiltIOSApp iosApp = new IOSApp.fromPrebuiltApp(fs.file('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('app.ipa'); final PrebuiltIOSApp iosApp = new IOSApp.fromPrebuiltApp(fs.file('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('app.ipa'); final PrebuiltIOSApp iosApp = new IOSApp.fromPrebuiltApp(fs.file('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,11 +289,9 @@ Information about project "Runner": ...@@ -289,11 +289,9 @@ Information about project "Runner":
previewDart2: true, previewDart2: true,
targetPlatform: TargetPlatform.ios, targetPlatform: TargetPlatform.ios,
); );
final FlutterManifest manifest = final FlutterProject project = new FlutterProject.fromPath('path/to/project');
await new FlutterProject.fromPath('path/to/project').manifest; await updateGeneratedXcodeProperties(
updateGeneratedXcodeProperties( project: project,
projectPath: 'path/to/project',
manifest: manifest,
buildInfo: buildInfo, buildInfo: buildInfo,
previewDart2: true, previewDart2: true,
); );
...@@ -313,11 +311,9 @@ Information about project "Runner": ...@@ -313,11 +311,9 @@ Information about project "Runner":
trackWidgetCreation: true, trackWidgetCreation: true,
targetPlatform: TargetPlatform.ios, targetPlatform: TargetPlatform.ios,
); );
final FlutterManifest manifest = final FlutterProject project = new FlutterProject.fromPath('path/to/project');
await new FlutterProject.fromPath('path/to/project').manifest; await updateGeneratedXcodeProperties(
updateGeneratedXcodeProperties( project: project,
projectPath: 'path/to/project',
manifest: manifest,
buildInfo: buildInfo, buildInfo: buildInfo,
previewDart2: true, previewDart2: true,
); );
...@@ -336,11 +332,9 @@ Information about project "Runner": ...@@ -336,11 +332,9 @@ Information about project "Runner":
previewDart2: true, previewDart2: true,
targetPlatform: TargetPlatform.ios, targetPlatform: TargetPlatform.ios,
); );
final FlutterManifest manifest = final FlutterProject project = new FlutterProject.fromPath('path/to/project');
await new FlutterProject.fromPath('path/to/project').manifest; await updateGeneratedXcodeProperties(
updateGeneratedXcodeProperties( project: project,
projectPath: 'path/to/project',
manifest: manifest,
buildInfo: buildInfo, buildInfo: buildInfo,
previewDart2: true, previewDart2: true,
); );
...@@ -360,11 +354,9 @@ Information about project "Runner": ...@@ -360,11 +354,9 @@ Information about project "Runner":
targetPlatform: TargetPlatform.ios, targetPlatform: TargetPlatform.ios,
); );
final FlutterManifest manifest = final FlutterProject project = new FlutterProject.fromPath('path/to/project');
await new FlutterProject.fromPath('path/to/project').manifest; await updateGeneratedXcodeProperties(
updateGeneratedXcodeProperties( project: project,
projectPath: 'path/to/project',
manifest: manifest,
buildInfo: buildInfo, buildInfo: buildInfo,
previewDart2: true, previewDart2: true,
); );
...@@ -412,11 +404,8 @@ Information about project "Runner": ...@@ -412,11 +404,8 @@ Information about project "Runner":
const String schemaData = '{}'; const String schemaData = '{}';
writeSchemaFile(fs, schemaData); writeSchemaFile(fs, schemaData);
final FlutterManifest manifest = await updateGeneratedXcodeProperties(
await new FlutterProject.fromPath('path/to/project').manifest; project: new FlutterProject.fromPath('path/to/project'),
updateGeneratedXcodeProperties(
projectPath: 'path/to/project',
manifest: manifest,
buildInfo: buildInfo, buildInfo: buildInfo,
previewDart2: false, previewDart2: false,
); );
......
...@@ -129,13 +129,6 @@ void testInMemory(String description, Future<Null> testMethod()) { ...@@ -129,13 +129,6 @@ 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',
apkPath: '/mock/path/to/android/SkyShell.apk', file: fs.file('/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.packagePath, fs.path.join(projectPath, '.packages')); expect(app.packagesFile.path, 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