Wire up ios-profile and ios-release. Switching between debug, profile and release starts the build process from scratch. (#4063)
diff --git a/packages/flutter_tools/lib/src/android/android_device.dart b/packages/flutter_tools/lib/src/android/android_device.dart
index de89f86..1235153 100644
--- a/packages/flutter_tools/lib/src/android/android_device.dart
+++ b/packages/flutter_tools/lib/src/android/android_device.dart
@@ -325,7 +325,8 @@
 
   @override
   Future<LaunchResult> startApp(
-    ApplicationPackage package, {
+    ApplicationPackage package,
+    BuildMode mode, {
     String mainPath,
     String route,
     DebuggingOptions debuggingOptions,
diff --git a/packages/flutter_tools/lib/src/build_info.dart b/packages/flutter_tools/lib/src/build_info.dart
index e6e6a7d..78fcbf4 100644
--- a/packages/flutter_tools/lib/src/build_info.dart
+++ b/packages/flutter_tools/lib/src/build_info.dart
@@ -60,7 +60,7 @@
     case TargetPlatform.android_x86:
       return 'android-x86';
     case TargetPlatform.ios:
-      return 'ios_release';
+      return 'ios';
     case TargetPlatform.darwin_x64:
       return 'darwin-x64';
     case TargetPlatform.linux_x64:
diff --git a/packages/flutter_tools/lib/src/cache.dart b/packages/flutter_tools/lib/src/cache.dart
index 8987009..de20ae5 100644
--- a/packages/flutter_tools/lib/src/cache.dart
+++ b/packages/flutter_tools/lib/src/cache.dart
@@ -210,7 +210,7 @@
     ];
 
     if (Platform.isMacOS)
-      dirs.add('ios_release');
+      dirs.addAll(<String>['ios', 'ios-profile', 'ios-release']);
     else if (Platform.isLinux)
       dirs.add('linux-x64');
 
diff --git a/packages/flutter_tools/lib/src/commands/build_ios.dart b/packages/flutter_tools/lib/src/commands/build_ios.dart
index df1fe21..80c9547 100644
--- a/packages/flutter_tools/lib/src/commands/build_ios.dart
+++ b/packages/flutter_tools/lib/src/commands/build_ios.dart
@@ -12,6 +12,7 @@
 
 class BuildIOSCommand extends FlutterCommand {
   BuildIOSCommand() {
+    addBuildModeFlags();
     argParser.addFlag('simulator', help: 'Build for the iOS simulator instead of the device.');
     argParser.addFlag('codesign', negatable: true, defaultsTo: true,
         help: 'Codesign the application bundle (only available on device builds).');
@@ -49,8 +50,9 @@
 
     printStatus('Building $app for $logTarget...');
 
-    bool result = await buildIOSXcodeProject(app,
-        buildForDevice: !forSimulator, codesign: shouldCodesign);
+    bool result = await buildIOSXcodeProject(app, getBuildMode(),
+        buildForDevice: !forSimulator,
+        codesign: shouldCodesign);
 
     if (!result) {
       printError('Encountered error while building for $logTarget.');
diff --git a/packages/flutter_tools/lib/src/commands/drive.dart b/packages/flutter_tools/lib/src/commands/drive.dart
index 2c13a08..96ea1bc 100644
--- a/packages/flutter_tools/lib/src/commands/drive.dart
+++ b/packages/flutter_tools/lib/src/commands/drive.dart
@@ -266,6 +266,7 @@
   printTrace('Starting application.');
   LaunchResult result = await command.device.startApp(
     package,
+    buildMode,
     mainPath: mainPath,
     route: command.route,
     debuggingOptions: new DebuggingOptions.enabled(
diff --git a/packages/flutter_tools/lib/src/commands/run.dart b/packages/flutter_tools/lib/src/commands/run.dart
index de08783..f0dfffa 100644
--- a/packages/flutter_tools/lib/src/commands/run.dart
+++ b/packages/flutter_tools/lib/src/commands/run.dart
@@ -215,6 +215,7 @@
 
   LaunchResult result = await device.startApp(
     package,
+    buildMode,
     mainPath: mainPath,
     route: route,
     debuggingOptions: debuggingOptions,
@@ -359,6 +360,7 @@
 
     LaunchResult result = await device.startApp(
       package,
+      buildMode,
       mainPath: mainPath,
       debuggingOptions: debuggingOptions,
       platformArgs: platformArgs
diff --git a/packages/flutter_tools/lib/src/device.dart b/packages/flutter_tools/lib/src/device.dart
index 954a5d5..fb8a663 100644
--- a/packages/flutter_tools/lib/src/device.dart
+++ b/packages/flutter_tools/lib/src/device.dart
@@ -175,9 +175,10 @@
   /// Start an app package on the current device.
   ///
   /// [platformArgs] allows callers to pass platform-specific arguments to the
-  /// start call.
+  /// start call. The build mode is not used by all platforms.
   Future<LaunchResult> startApp(
-    ApplicationPackage package, {
+    ApplicationPackage package,
+    BuildMode mode, {
     String mainPath,
     String route,
     DebuggingOptions debuggingOptions,
diff --git a/packages/flutter_tools/lib/src/ios/devices.dart b/packages/flutter_tools/lib/src/ios/devices.dart
index 3fa0609..1e43557 100644
--- a/packages/flutter_tools/lib/src/ios/devices.dart
+++ b/packages/flutter_tools/lib/src/ios/devices.dart
@@ -153,7 +153,8 @@
 
   @override
   Future<LaunchResult> startApp(
-    ApplicationPackage app, {
+    ApplicationPackage app,
+    BuildMode mode, {
     String mainPath,
     String route,
     DebuggingOptions debuggingOptions,
@@ -163,8 +164,8 @@
     // TODO(devoncarew): Handle startPaused, debugPort.
     printTrace('Building ${app.name} for $id');
 
-    // Step 1: Install the precompiled application if necessary.
-    bool buildResult = await buildIOSXcodeProject(app, buildForDevice: true);
+    // Step 1: Install the precompiled/DBC application if necessary.
+    bool buildResult = await buildIOSXcodeProject(app, mode, buildForDevice: true);
     if (!buildResult) {
       printError('Could not build the precompiled application for the device.');
       return new LaunchResult.failed();
diff --git a/packages/flutter_tools/lib/src/ios/mac.dart b/packages/flutter_tools/lib/src/ios/mac.dart
index 453eb43..e8d9667 100644
--- a/packages/flutter_tools/lib/src/ios/mac.dart
+++ b/packages/flutter_tools/lib/src/ios/mac.dart
@@ -11,6 +11,7 @@
 import '../application_package.dart';
 import '../base/context.dart';
 import '../base/process.dart';
+import '../build_info.dart';
 import '../cache.dart';
 import '../globals.dart';
 import '../services.dart';
@@ -96,13 +97,13 @@
   return false;
 }
 
-Future<bool> buildIOSXcodeProject(ApplicationPackage app,
+Future<bool> buildIOSXcodeProject(ApplicationPackage app, BuildMode mode,
     { bool buildForDevice, bool codesign: true }) async {
   String flutterProjectPath = Directory.current.path;
 
-  if (xcodeProjectRequiresUpdate()) {
+  if (xcodeProjectRequiresUpdate(mode)) {
     printTrace('Initializing the Xcode project.');
-    if ((await setupXcodeProjectHarness(flutterProjectPath)) != 0) {
+    if ((await setupXcodeProjectHarness(flutterProjectPath, mode)) != 0) {
       printError('Could not initialize the Xcode project.');
       return false;
     }
@@ -200,7 +201,9 @@
 String _getIOSEngineRevision(ApplicationPackage app) {
   File revisionFile = new File(path.join(app.localPath, 'REVISION'));
   if (revisionFile.existsSync()) {
-    return revisionFile.readAsStringSync().trim();
+    // The format is 'REVISION-mode'. We only need the revision.
+    String revisionStamp = revisionFile.readAsStringSync().trim();
+    return revisionStamp.split('-')[0];
   } else {
     return null;
   }
diff --git a/packages/flutter_tools/lib/src/ios/setup_xcodeproj.dart b/packages/flutter_tools/lib/src/ios/setup_xcodeproj.dart
index 558b593..01561d8 100644
--- a/packages/flutter_tools/lib/src/ios/setup_xcodeproj.dart
+++ b/packages/flutter_tools/lib/src/ios/setup_xcodeproj.dart
@@ -75,7 +75,7 @@
   localsFile.writeAsStringSync(localsBuffer.toString());
 }
 
-bool xcodeProjectRequiresUpdate() {
+bool xcodeProjectRequiresUpdate(BuildMode mode) {
   File revisionFile = new File(path.join(Directory.current.path, 'ios', '.generated', 'REVISION'));
 
   // If the revision stamp does not exist, the Xcode project definitely requires
@@ -85,8 +85,9 @@
     return true;
   }
 
-  if (revisionFile.readAsStringSync() != Cache.engineRevision) {
-    printTrace("The revision stamp and the Flutter engine revision differ. Project needs to be updated.");
+  if (revisionFile.readAsStringSync() != '${Cache.engineRevision}-${getModeName(mode)}') {
+    printTrace("The revision stamp and the Flutter engine revision differ or the build mode has changed.");
+    printTrace("Project needs to be updated.");
     return true;
   }
 
@@ -94,12 +95,12 @@
   return false;
 }
 
-Future<int> setupXcodeProjectHarness(String flutterProjectPath) async {
+Future<int> setupXcodeProjectHarness(String flutterProjectPath, BuildMode mode) async {
   // Step 1: Fetch the archive from the cloud
   String iosFilesPath = path.join(flutterProjectPath, 'ios');
   String xcodeprojPath = path.join(iosFilesPath, '.generated');
 
-  Directory toolDir = tools.getEngineArtifactsDirectory(TargetPlatform.ios, BuildMode.debug);
+  Directory toolDir = tools.getEngineArtifactsDirectory(TargetPlatform.ios, mode);
   File archiveFile = new File(path.join(toolDir.path, 'FlutterXcode.zip'));
   List<int> archiveBytes = archiveFile.readAsBytesSync();
 
@@ -121,7 +122,7 @@
   // Step 4: Write the REVISION file
   File revisionFile = new File(path.join(xcodeprojPath, 'REVISION'));
   revisionFile.createSync();
-  revisionFile.writeAsStringSync(Cache.engineRevision);
+  revisionFile.writeAsStringSync('${Cache.engineRevision}-${getModeName(mode)}');
 
   // Step 5: Tell the user the location of the generated project.
   printStatus('Xcode project created in $iosFilesPath/.');
diff --git a/packages/flutter_tools/lib/src/ios/simulators.dart b/packages/flutter_tools/lib/src/ios/simulators.dart
index 494511f..bf3afd0 100644
--- a/packages/flutter_tools/lib/src/ios/simulators.dart
+++ b/packages/flutter_tools/lib/src/ios/simulators.dart
@@ -433,7 +433,8 @@
 
   @override
   Future<LaunchResult> startApp(
-    ApplicationPackage app, {
+    ApplicationPackage app,
+    BuildMode mode, {
     String mainPath,
     String route,
     DebuggingOptions debuggingOptions,
@@ -531,7 +532,8 @@
 
   Future<bool> _buildAndInstallApplicationBundle(ApplicationPackage app) async {
     // Step 1: Build the Xcode project.
-    bool buildResult = await buildIOSXcodeProject(app, buildForDevice: false);
+    // The build mode for the simulator is always debug.
+    bool buildResult = await buildIOSXcodeProject(app, BuildMode.debug, buildForDevice: false);
     if (!buildResult) {
       printError('Could not build the application for the simulator.');
       return false;