Revert "Move plugin injection to just after pub get (#14560)" (#14734)

This reverts commit b3e4976ca20dc878bd8a484b877b66351bed86e4.
diff --git a/dev/devicelab/bin/tasks/plugin_test.dart b/dev/devicelab/bin/tasks/plugin_test.dart
deleted file mode 100644
index 3217961..0000000
--- a/dev/devicelab/bin/tasks/plugin_test.dart
+++ /dev/null
@@ -1,12 +0,0 @@
-// Copyright (c) 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-import 'dart:async';
-
-import 'package:flutter_devicelab/tasks/plugin_tests.dart';
-import 'package:flutter_devicelab/framework/framework.dart';
-
-Future<Null> main() async {
-  await task(new PluginTest('apk'));
-}
diff --git a/dev/devicelab/bin/tasks/plugin_test_ios.dart b/dev/devicelab/bin/tasks/plugin_test_ios.dart
deleted file mode 100644
index 492e7d6..0000000
--- a/dev/devicelab/bin/tasks/plugin_test_ios.dart
+++ /dev/null
@@ -1,12 +0,0 @@
-// Copyright (c) 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-import 'dart:async';
-
-import 'package:flutter_devicelab/tasks/plugin_tests.dart';
-import 'package:flutter_devicelab/framework/framework.dart';
-
-Future<Null> main() async {
-  await task(new PluginTest('ios'));
-}
diff --git a/dev/devicelab/bin/tasks/plugin_test_win.dart b/dev/devicelab/bin/tasks/plugin_test_win.dart
deleted file mode 100644
index 3217961..0000000
--- a/dev/devicelab/bin/tasks/plugin_test_win.dart
+++ /dev/null
@@ -1,12 +0,0 @@
-// Copyright (c) 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-import 'dart:async';
-
-import 'package:flutter_devicelab/tasks/plugin_tests.dart';
-import 'package:flutter_devicelab/framework/framework.dart';
-
-Future<Null> main() async {
-  await task(new PluginTest('apk'));
-}
diff --git a/dev/devicelab/lib/tasks/plugin_tests.dart b/dev/devicelab/lib/tasks/plugin_tests.dart
deleted file mode 100644
index 1e06a4f..0000000
--- a/dev/devicelab/lib/tasks/plugin_tests.dart
+++ /dev/null
@@ -1,73 +0,0 @@
-// Copyright (c) 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-import 'dart:async';
-import 'dart:io';
-
-import 'package:path/path.dart' as path;
-import 'package:flutter_devicelab/framework/framework.dart';
-import 'package:flutter_devicelab/framework/utils.dart';
-
-/// Defines task that creates new Flutter project, adds a plugin, and then
-/// builds the specified [buildTarget].
-class PluginTest {
-  final String buildTarget;
-
-  PluginTest(this.buildTarget);
-
-  Future<TaskResult> call() async {
-    section('Create Flutter project');
-    final Directory tmp = await Directory.systemTemp.createTemp('plugin');
-    final FlutterProject project = await FlutterProject.create(tmp, 'hello');
-    try {
-      section('Add plugin');
-      await project.addPlugin('path_provider');
-
-      section('Build');
-      await project.build(buildTarget);
-
-      return new TaskResult.success(null);
-    } catch (e) {
-      return new TaskResult.failure(e.toString());
-    } finally {
-      await project.delete();
-    }
-  }
-}
-
-class FlutterProject {
-  FlutterProject(this.parent, this.name);
-
-  final Directory parent;
-  final String name;
-
-  static Future<FlutterProject> create(Directory directory, String name) async {
-    await inDirectory(directory, () async {
-      await flutter('create', options: <String>[name]);
-    });
-    return new FlutterProject(directory, name);
-  }
-
-  String get rootPath => path.join(parent.path, name);
-
-  Future<Null> addPlugin(String plugin) async {
-    final File pubspec = new File(path.join(rootPath, 'pubspec.yaml'));
-    String content = await pubspec.readAsString();
-    content = content.replaceFirst(
-      '\ndependencies:\n',
-      '\ndependencies:\n  $plugin:\n',
-    );
-    await pubspec.writeAsString(content, flush: true);
-  }
-
-  Future<Null> build(String target) async {
-    await inDirectory(new Directory(rootPath), () async {
-      await flutter('build', options: <String>[target]);
-    });
-  }
-
-  Future<Null> delete() async {
-    await parent.delete(recursive: true);
-  }
-}
diff --git a/dev/devicelab/manifest.yaml b/dev/devicelab/manifest.yaml
index 27a0bfc..63b3d1f 100644
--- a/dev/devicelab/manifest.yaml
+++ b/dev/devicelab/manifest.yaml
@@ -237,13 +237,6 @@
     stage: devicelab
     required_agent_capabilities: ["linux/android"]
 
-  plugin_test:
-    description: >
-      Checks that the project template works and supports plugins.
-    stage: devicelab
-    required_agent_capabilities: ["linux/android"]
-    flaky: true
-
   flutter_gallery_instrumentation_test:
     description: >
       Same as flutter_gallery__transition_perf but uses Android instrumentation
@@ -260,13 +253,6 @@
     stage: devicelab_ios
     required_agent_capabilities: ["mac/ios"]
 
-  plugin_test_ios:
-    description: >
-      Checks that the project template works and supports plugins on iOS.
-    stage: devicelab_ios
-    required_agent_capabilities: ["mac/ios"]
-    flaky: true
-
   external_ui_integration_test_ios:
     description: >
       Checks that external UIs work on iOS.
@@ -361,13 +347,6 @@
     stage: devicelab_win
     required_agent_capabilities: ["windows/android"]
 
-  plugin_test_win:
-    description: >
-      Checks that the project template works and supports plugins on Windows.
-    stage: devicelab_win
-    required_agent_capabilities: ["windows/android"]
-    flaky: true
-
   hot_mode_dev_cycle_win__benchmark:
     description: >
       Measures the performance of Dart VM hot patching feature on Windows.
diff --git a/packages/flutter_tools/lib/src/android/gradle.dart b/packages/flutter_tools/lib/src/android/gradle.dart
index 8312408..e9598b6 100644
--- a/packages/flutter_tools/lib/src/android/gradle.dart
+++ b/packages/flutter_tools/lib/src/android/gradle.dart
@@ -16,6 +16,7 @@
 import '../build_info.dart';
 import '../cache.dart';
 import '../globals.dart';
+import '../plugins.dart';
 import 'android_sdk.dart';
 import 'android_studio.dart';
 
@@ -93,6 +94,7 @@
 Future<GradleProject> _readGradleProject() async {
   final String gradle = await _ensureGradle();
   updateLocalProperties();
+  injectPlugins();
   try {
     final Status status = logger.startProgress('Resolving dependencies...', expectSlowOperation: true);
     final RunResult runResult = await runCheckedAsync(
diff --git a/packages/flutter_tools/lib/src/application_package.dart b/packages/flutter_tools/lib/src/application_package.dart
index ea4e9dc3..f98dd46a 100644
--- a/packages/flutter_tools/lib/src/application_package.dart
+++ b/packages/flutter_tools/lib/src/application_package.dart
@@ -181,11 +181,11 @@
     if (id == null)
       return null;
     final String projectPath = fs.path.join('ios', 'Runner.xcodeproj');
-    final Map<String, String> buildSettings = xcodeProjectInterpreter.getBuildSettings(projectPath, 'Runner');
+    final Map<String, String> buildSettings = getXcodeBuildSettings(projectPath, 'Runner');
     id = substituteXcodeVariables(id, buildSettings);
 
     return new BuildableIOSApp(
-      appDirectory: 'ios',
+      appDirectory: fs.path.join('ios'),
       projectBundleId: id,
       buildSettings: buildSettings,
     );
diff --git a/packages/flutter_tools/lib/src/commands/create.dart b/packages/flutter_tools/lib/src/commands/create.dart
index 5956021..643a452 100644
--- a/packages/flutter_tools/lib/src/commands/create.dart
+++ b/packages/flutter_tools/lib/src/commands/create.dart
@@ -14,10 +14,14 @@
 import '../base/file_system.dart';
 import '../base/os.dart';
 import '../base/utils.dart';
+import '../build_info.dart';
 import '../cache.dart';
 import '../dart/pub.dart';
 import '../doctor.dart';
+import '../flx.dart' as flx;
 import '../globals.dart';
+import '../ios/xcodeproj.dart';
+import '../plugins.dart';
 import '../project.dart';
 import '../runner/flutter_command.dart';
 import '../template.dart';
@@ -228,9 +232,17 @@
     printStatus('Wrote $generatedCount files.');
     printStatus('');
 
+    updateXcodeGeneratedProperties(
+      projectPath: appPath,
+      buildInfo: BuildInfo.debug,
+      target: flx.defaultMainPath,
+      hasPlugins: generatePlugin,
+      previewDart2: false,
+    );
+
     if (argResults['pub']) {
       await pubGet(context: PubContext.create, directory: appPath, offline: argResults['offline']);
-      new FlutterProject(fs.directory(appPath)).ensureReadyForPlatformSpecificTooling();
+      injectPlugins(directory: appPath);
     }
 
     if (android_sdk.androidSdk != null)
diff --git a/packages/flutter_tools/lib/src/commands/inject_plugins.dart b/packages/flutter_tools/lib/src/commands/inject_plugins.dart
index 6886937..f1df432 100644
--- a/packages/flutter_tools/lib/src/commands/inject_plugins.dart
+++ b/packages/flutter_tools/lib/src/commands/inject_plugins.dart
@@ -24,8 +24,7 @@
 
   @override
   Future<Null> runCommand() async {
-    injectPlugins();
-    final bool result = hasPlugins();
+    final bool result = injectPlugins().hasPlugin;
     if (result) {
       printStatus('GeneratedPluginRegistrants successfully written.');
     } else {
diff --git a/packages/flutter_tools/lib/src/commands/packages.dart b/packages/flutter_tools/lib/src/commands/packages.dart
index 3600289..44aafbc 100644
--- a/packages/flutter_tools/lib/src/commands/packages.dart
+++ b/packages/flutter_tools/lib/src/commands/packages.dart
@@ -5,10 +5,8 @@
 import 'dart:async';
 
 import '../base/common.dart';
-import '../base/file_system.dart';
 import '../base/os.dart';
 import '../dart/pub.dart';
-import '../project.dart';
 import '../runner/flutter_command.dart';
 
 class PackagesCommand extends FlutterCommand {
@@ -77,7 +75,6 @@
       offline: argResults['offline'],
       checkLastModified: false,
     );
-    new FlutterProject(fs.directory(target)).ensureReadyForPlatformSpecificTooling();
   }
 }
 
diff --git a/packages/flutter_tools/lib/src/ios/cocoapods.dart b/packages/flutter_tools/lib/src/ios/cocoapods.dart
index 1d558d4..da63cdc 100644
--- a/packages/flutter_tools/lib/src/ios/cocoapods.dart
+++ b/packages/flutter_tools/lib/src/ios/cocoapods.dart
@@ -16,7 +16,6 @@
 import '../base/version.dart';
 import '../cache.dart';
 import '../globals.dart';
-import 'xcodeproj.dart';
 
 const String noCocoaPodsConsequence = '''
   CocoaPods is used to retrieve the iOS platform side's plugin code that responds to your plugin usage on the Dart side.
@@ -61,13 +60,13 @@
     // For backward compatibility with previously created Podfile only.
     @required String iosEngineDir,
     bool isSwift: false,
-    bool flutterPodChanged: true,
+    bool pluginOrFlutterPodChanged: true,
   }) async {
-    if (!(await appIosDir.childFile('Podfile').exists())) {
-      throwToolExit('Podfile missing');
-    }
     if (await _checkPodCondition()) {
-      if (_shouldRunPodInstall(appIosDir.path, flutterPodChanged))
+      if (!fs.file(fs.path.join(appIosDir.path, 'Podfile')).existsSync()) {
+        await _createPodfile(appIosDir, isSwift);
+      } // TODO(xster): Add more logic for handling merge conflicts.
+      if (_shouldRunPodInstall(appIosDir.path, pluginOrFlutterPodChanged))
         await _runPodInstall(appIosDir, iosEngineDir);
     }
   }
@@ -100,69 +99,39 @@
     return true;
   }
 
-  /// Ensures the `ios` sub-project of the Flutter project at [directory]
-  /// contains a suitable `Podfile` and that its `Flutter/Xxx.xcconfig` files
-  /// include pods configuration.
-  void setupPodfile(String directory) {
-    if (!xcodeProjectInterpreter.canInterpretXcodeProjects) {
-      // Don't do anything for iOS when host platform doesn't support it.
-      return;
-    }
-    final String podfilePath = fs.path.join(directory, 'ios', 'Podfile');
-    if (!fs.file(podfilePath).existsSync()) {
-      final bool isSwift = xcodeProjectInterpreter.getBuildSettings(
-        fs.path.join(directory, 'ios', 'Runner.xcodeproj'),
-        'Runner',
-      ).containsKey('SWIFT_VERSION');
-      final File podfileTemplate = fs.file(fs.path.join(
-        Cache.flutterRoot,
-        'packages',
-        'flutter_tools',
-        'templates',
-        'cocoapods',
-        isSwift ? 'Podfile-swift' : 'Podfile-objc',
-      ));
-      podfileTemplate.copySync(podfilePath);
-    }
-    _addPodsDependencyToFlutterXcconfig(directory, 'Debug');
-    _addPodsDependencyToFlutterXcconfig(directory, 'Release');
-  }
-
-  void _addPodsDependencyToFlutterXcconfig(String directory, String mode) {
-    final File file = fs.file(fs.path.join(directory, 'ios', 'Flutter', '$mode.xcconfig'));
-    if (file.existsSync()) {
-      final String content = file.readAsStringSync();
-      final String include = '#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.${mode
-          .toLowerCase()}.xcconfig"';
-      if (!content.contains(include))
-        file.writeAsStringSync('$include\n$content', flush: true);
-    }
-  }
-
-  /// Ensures that pod install is deemed needed on next check.
-  void invalidatePodInstallOutput(String directory) {
-    final File manifest = fs.file(
-      fs.path.join(directory, 'ios', 'Pods', 'Manifest.lock'),
-    );
-    if (manifest.existsSync())
-      manifest.deleteSync();
+  Future<Null> _createPodfile(Directory bundle, bool isSwift) async {
+    final File podfileTemplate = fs.file(fs.path.join(
+      Cache.flutterRoot,
+      'packages',
+      'flutter_tools',
+      'templates',
+      'cocoapods',
+      isSwift ? 'Podfile-swift' : 'Podfile-objc',
+    ));
+    podfileTemplate.copySync(fs.path.join(bundle.path, 'Podfile'));
   }
 
   // Check if you need to run pod install.
   // The pod install will run if any of below is true.
-  // 1. The flutter.framework has changed (debug/release/profile)
-  // 2. The podfile.lock doesn't exist
-  // 3. The Pods/Manifest.lock doesn't exist (It is deleted when plugins change)
-  // 4. The podfile.lock doesn't match Pods/Manifest.lock.
-  bool _shouldRunPodInstall(String appDir, bool flutterPodChanged) {
-    if (flutterPodChanged)
+  // 1. Any plugins changed (add/update/delete)
+  // 2. The flutter.framework has changed (debug/release/profile)
+  // 3. The podfile.lock doesn't exists
+  // 4. The Pods/manifest.lock doesn't exists
+  // 5. The podfile.lock doesn't match Pods/manifest.lock.
+  bool _shouldRunPodInstall(String appDir, bool pluginOrFlutterPodChanged) {
+    if (pluginOrFlutterPodChanged)
       return true;
-    // Check if podfile.lock and Pods/Manifest.lock exist and match.
+    // Check if podfile.lock and Pods/Manifest.lock exists and matches.
     final File podfileLockFile = fs.file(fs.path.join(appDir, 'Podfile.lock'));
-    final File manifestLockFile = fs.file(fs.path.join(appDir, 'Pods', 'Manifest.lock'));
-    return !podfileLockFile.existsSync()
+    final File manifestLockFile =
+        fs.file(fs.path.join(appDir, 'Pods', 'Manifest.lock'));
+    if (!podfileLockFile.existsSync()
         || !manifestLockFile.existsSync()
-        || podfileLockFile.readAsStringSync() != manifestLockFile.readAsStringSync();
+        || podfileLockFile.readAsStringSync() !=
+            manifestLockFile.readAsStringSync()) {
+      return true;
+    }
+    return false;
   }
 
   Future<Null> _runPodInstall(Directory bundle, String engineDirectory) async {
diff --git a/packages/flutter_tools/lib/src/ios/mac.dart b/packages/flutter_tools/lib/src/ios/mac.dart
index 9f174f0..621186d 100644
--- a/packages/flutter_tools/lib/src/ios/mac.dart
+++ b/packages/flutter_tools/lib/src/ios/mac.dart
@@ -217,7 +217,7 @@
     return new XcodeBuildResult(success: false);
   }
 
-  final XcodeProjectInfo projectInfo = xcodeProjectInterpreter.getInfo(app.appDirectory);
+  final XcodeProjectInfo projectInfo = new XcodeProjectInfo.fromProjectSync(app.appDirectory);
   if (!projectInfo.targets.contains('Runner')) {
     printError('The Xcode project does not define target "Runner" which is needed by Flutter tooling.');
     printError('Open Xcode to fix the problem:');
@@ -254,22 +254,26 @@
   // copied over to a location that is suitable for Xcodebuild to find them.
   final Directory appDirectory = fs.directory(app.appDirectory);
   await _addServicesToBundle(appDirectory);
+  final InjectPluginsResult injectPluginsResult = injectPlugins();
+  final bool hasFlutterPlugins = injectPluginsResult.hasPlugin;
   final String previousGeneratedXcconfig = readGeneratedXcconfig(app.appDirectory);
 
-  updateGeneratedXcodeProperties(
+  updateXcodeGeneratedProperties(
     projectPath: fs.currentDirectory.path,
     buildInfo: buildInfo,
     target: target,
+    hasPlugins: hasFlutterPlugins,
     previewDart2: buildInfo.previewDart2,
   );
 
-  if (hasPlugins()) {
+  if (hasFlutterPlugins) {
     final String currentGeneratedXcconfig = readGeneratedXcconfig(app.appDirectory);
     await cocoaPods.processPods(
-      appIosDir: appDirectory,
-      iosEngineDir: flutterFrameworkDir(buildInfo.mode),
-      isSwift: app.isSwift,
-      flutterPodChanged: (previousGeneratedXcconfig != currentGeneratedXcconfig),
+        appIosDir: appDirectory,
+        iosEngineDir: flutterFrameworkDir(buildInfo.mode),
+        isSwift: app.isSwift,
+        pluginOrFlutterPodChanged: (injectPluginsResult.hasChanged
+            || previousGeneratedXcconfig != currentGeneratedXcconfig),
     );
   }
 
@@ -415,7 +419,7 @@
 
 String readGeneratedXcconfig(String appPath) {
   final String generatedXcconfigPath =
-      fs.path.join(fs.currentDirectory.path, appPath, 'Flutter', 'Generated.xcconfig');
+      fs.path.join(fs.currentDirectory.path, appPath, 'Flutter','Generated.xcconfig');
   final File generatedXcconfigFile = fs.file(generatedXcconfigPath);
   if (!generatedXcconfigFile.existsSync())
     return null;
diff --git a/packages/flutter_tools/lib/src/ios/xcodeproj.dart b/packages/flutter_tools/lib/src/ios/xcodeproj.dart
index 9a50d30..1bc8e79 100644
--- a/packages/flutter_tools/lib/src/ios/xcodeproj.dart
+++ b/packages/flutter_tools/lib/src/ios/xcodeproj.dart
@@ -5,13 +5,11 @@
 import 'package:meta/meta.dart';
 
 import '../artifacts.dart';
-import '../base/context.dart';
 import '../base/file_system.dart';
 import '../base/process.dart';
 import '../base/utils.dart';
 import '../build_info.dart';
 import '../cache.dart';
-import '../flx.dart' as flx;
 import '../globals.dart';
 
 final RegExp _settingExpr = new RegExp(r'(\w+)\s*=\s*(.*)$');
@@ -21,28 +19,11 @@
   return fs.path.normalize(fs.path.dirname(artifacts.getArtifactPath(Artifact.flutterFramework, TargetPlatform.ios, mode)));
 }
 
-String _generatedXcodePropertiesPath(String projectPath) {
-  return fs.path.join(projectPath, 'ios', 'Flutter', 'Generated.xcconfig');
-}
-
-/// Writes default Xcode properties files in the Flutter project at
-/// [projectPath], if such files do not already exist.
-void generateXcodeProperties(String projectPath) {
-  if (fs.file(_generatedXcodePropertiesPath(projectPath)).existsSync())
-    return;
-  updateGeneratedXcodeProperties(
-      projectPath: projectPath,
-      buildInfo: BuildInfo.debug,
-      target: flx.defaultMainPath,
-      previewDart2: false,
-  );
-}
-
-/// Writes or rewrites Xcode property files with the specified information.
-void updateGeneratedXcodeProperties({
+void updateXcodeGeneratedProperties({
   @required String projectPath,
   @required BuildInfo buildInfo,
   @required String target,
+  @required bool hasPlugins,
   @required bool previewDart2,
 }) {
   final StringBuffer localsBuffer = new StringBuffer();
@@ -77,42 +58,21 @@
     localsBuffer.writeln('PREVIEW_DART_2=true');
   }
 
-  final File localsFile = fs.file(_generatedXcodePropertiesPath(projectPath));
+  // Add dependency to CocoaPods' generated project only if plugins are used.
+  if (hasPlugins)
+    localsBuffer.writeln('#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"');
+
+  final File localsFile = fs.file(fs.path.join(projectPath, 'ios', 'Flutter', 'Generated.xcconfig'));
   localsFile.createSync(recursive: true);
   localsFile.writeAsStringSync(localsBuffer.toString());
 }
 
-XcodeProjectInterpreter get xcodeProjectInterpreter => context.putIfAbsent(
-  XcodeProjectInterpreter,
-  () => const XcodeProjectInterpreter(),
-);
-
-/// Interpreter of Xcode projects settings.
-class XcodeProjectInterpreter {
-  static const String _executable = '/usr/bin/xcodebuild';
-
-  const XcodeProjectInterpreter();
-
-  bool get canInterpretXcodeProjects => fs.isFileSync(_executable);
-
-  Map<String, String> getBuildSettings(String projectPath, String target) {
-    final String out = runCheckedSync(<String>[
-      _executable,
-      '-project',
-      fs.path.absolute(projectPath),
-      '-target',
-      target,
-      '-showBuildSettings'
-    ], workingDirectory: projectPath);
-    return parseXcodeBuildSettings(out);
-  }
-
-  XcodeProjectInfo getInfo(String projectPath) {
-    final String out = runCheckedSync(<String>[
-      _executable, '-list',
-    ], workingDirectory: projectPath);
-    return new XcodeProjectInfo.fromXcodeBuildOutput(out);
-  }
+Map<String, String> getXcodeBuildSettings(String xcodeProjPath, String target) {
+  final String absProjPath = fs.path.absolute(xcodeProjPath);
+  final String out = runCheckedSync(<String>[
+    '/usr/bin/xcodebuild', '-project', absProjPath, '-target', target, '-showBuildSettings'
+  ]);
+  return parseXcodeBuildSettings(out);
 }
 
 Map<String, String> parseXcodeBuildSettings(String showBuildSettingsOutput) {
@@ -141,6 +101,13 @@
 class XcodeProjectInfo {
   XcodeProjectInfo(this.targets, this.buildConfigurations, this.schemes);
 
+  factory XcodeProjectInfo.fromProjectSync(String projectPath) {
+    final String out = runCheckedSync(<String>[
+      '/usr/bin/xcodebuild', '-list',
+    ], workingDirectory: projectPath);
+    return new XcodeProjectInfo.fromXcodeBuildOutput(out);
+  }
+
   factory XcodeProjectInfo.fromXcodeBuildOutput(String output) {
     final List<String> targets = <String>[];
     final List<String> buildConfigurations = <String>[];
diff --git a/packages/flutter_tools/lib/src/plugins.dart b/packages/flutter_tools/lib/src/plugins.dart
index 697cfdc..0d03f04 100644
--- a/packages/flutter_tools/lib/src/plugins.dart
+++ b/packages/flutter_tools/lib/src/plugins.dart
@@ -9,7 +9,6 @@
 import 'base/file_system.dart';
 import 'dart/package_map.dart';
 import 'globals.dart';
-import 'ios/cocoapods.dart';
 
 class Plugin {
   final String name;
@@ -81,25 +80,21 @@
 
 /// Returns true if .flutter-plugins has changed, otherwise returns false.
 bool _writeFlutterPluginsList(String directory, List<Plugin> plugins) {
-  final File pluginsFile = fs.file(fs.path.join(directory, '.flutter-plugins'));
-  final String oldContents = _readFlutterPluginsList(directory);
+  final File pluginsProperties = fs.file(fs.path.join(directory, '.flutter-plugins'));
+  final String previousFlutterPlugins =
+      pluginsProperties.existsSync() ? pluginsProperties.readAsStringSync() : null;
   final String pluginManifest =
       plugins.map((Plugin p) => '${p.name}=${escapePath(p.path)}').join('\n');
   if (pluginManifest.isNotEmpty) {
-    pluginsFile.writeAsStringSync('$pluginManifest\n', flush: true);
+    pluginsProperties.writeAsStringSync('$pluginManifest\n');
   } else {
-    if (pluginsFile.existsSync())
-      pluginsFile.deleteSync();
+    if (pluginsProperties.existsSync()) {
+      pluginsProperties.deleteSync();
+    }
   }
-  final String newContents = _readFlutterPluginsList(directory);
-  return oldContents != newContents;
-}
-
-/// Returns the contents of the `.flutter-plugins` file in [directory], or
-/// null if that file does not exist.
-String _readFlutterPluginsList(String directory) {
-  final File pluginsFile = fs.file(fs.path.join(directory, '.flutter-plugins'));
-  return pluginsFile.existsSync() ? pluginsFile.readAsStringSync() : null;
+  final String currentFlutterPlugins =
+      pluginsProperties.existsSync() ? pluginsProperties.readAsStringSync() : null;
+  return currentFlutterPlugins != previousFlutterPlugins;
 }
 
 const String _androidPluginRegistryTemplate = '''package io.flutter.plugins;
@@ -133,7 +128,7 @@
 }
 ''';
 
-void _writeAndroidPluginRegistrant(String directory, List<Plugin> plugins) {
+void _writeAndroidPluginRegistry(String directory, List<Plugin> plugins) {
   final List<Map<String, dynamic>> androidPlugins = plugins
       .where((Plugin p) => p.androidPackage != null && p.pluginClass != null)
       .map((Plugin p) => <String, dynamic>{
@@ -192,7 +187,7 @@
 @end
 ''';
 
-void _writeIOSPluginRegistrant(String directory, List<Plugin> plugins) {
+void _writeIOSPluginRegistry(String directory, List<Plugin> plugins) {
   final List<Map<String, dynamic>> iosPlugins = plugins
       .where((Plugin p) => p.pluginClass != null)
       .map((Plugin p) => <String, dynamic>{
@@ -215,6 +210,7 @@
   registryHeaderFile.writeAsStringSync(pluginRegistryHeader);
   final File registryImplementationFile = registryDirectory.childFile('GeneratedPluginRegistrant.m');
   registryImplementationFile.writeAsStringSync(pluginRegistryImplementation);
+
 }
 
 class InjectPluginsResult{
@@ -228,30 +224,17 @@
   final bool hasChanged;
 }
 
-/// Injects plugins found in `pubspec.yaml` into the platform-specific projects.
-void injectPlugins({String directory}) {
+/// Finds Flutter plugins in the pubspec.yaml, creates platform injection
+/// registries classes and add them to the build dependencies.
+///
+/// Returns whether any Flutter plugins are added and whether they changed.
+InjectPluginsResult injectPlugins({String directory}) {
   directory ??= fs.currentDirectory.path;
-  if (fs.file(fs.path.join(directory, 'example', 'pubspec.yaml')).existsSync()) {
-    // Switch to example app if in plugin project template.
-    directory = fs.path.join(directory, 'example');
-  }
   final List<Plugin> plugins = _findPlugins(directory);
-  final bool changed = _writeFlutterPluginsList(directory, plugins);
+  final bool hasPluginsChanged = _writeFlutterPluginsList(directory, plugins);
   if (fs.isDirectorySync(fs.path.join(directory, 'android')))
-    _writeAndroidPluginRegistrant(directory, plugins);
-  if (fs.isDirectorySync(fs.path.join(directory, 'ios'))) {
-    _writeIOSPluginRegistrant(directory, plugins);
-    final CocoaPods cocoaPods = const CocoaPods();
-    if (plugins.isNotEmpty)
-      cocoaPods.setupPodfile(directory);
-    if (changed)
-      cocoaPods.invalidatePodInstallOutput(directory);
-  }
-}
-
-/// Returns whether the Flutter project at the specified [directory]
-/// has any plugin dependencies.
-bool hasPlugins({String directory}) {
-  directory ??= fs.currentDirectory.path;
-  return _readFlutterPluginsList(directory) != null;
+    _writeAndroidPluginRegistry(directory, plugins);
+  if (fs.isDirectorySync(fs.path.join(directory, 'ios')))
+    _writeIOSPluginRegistry(directory, plugins);
+  return new InjectPluginsResult(hasPlugin: plugins.isNotEmpty, hasChanged: hasPluginsChanged);
 }
diff --git a/packages/flutter_tools/lib/src/project.dart b/packages/flutter_tools/lib/src/project.dart
index 7800f2a..1fd1b4f 100644
--- a/packages/flutter_tools/lib/src/project.dart
+++ b/packages/flutter_tools/lib/src/project.dart
@@ -4,11 +4,7 @@
 
 import 'dart:async';
 import 'dart:convert';
-
 import 'base/file_system.dart';
-import 'ios/xcodeproj.dart';
-import 'plugins.dart';
-
 
 /// Represents the contents of a Flutter project at the specified [directory].
 class FlutterProject {
@@ -47,25 +43,8 @@
   /// The Android sub project of this project.
   AndroidProject get android => new AndroidProject(directory.childDirectory('android'));
 
-  /// Returns true if this project is a plugin project.
-  bool get isPluginProject => directory.childDirectory('example').childFile('pubspec.yaml').existsSync();
-
   /// The example sub project of this (plugin) project.
   FlutterProject get example => new FlutterProject(directory.childDirectory('example'));
-
-  /// Generates project files necessary to make Gradle builds work on Android
-  /// and CocoaPods+Xcode work on iOS.
-  void ensureReadyForPlatformSpecificTooling() {
-    if (!directory.existsSync()) {
-      return;
-    }
-    if (isPluginProject) {
-      example.ensureReadyForPlatformSpecificTooling();
-    } else {
-      injectPlugins(directory: directory.path);
-      generateXcodeProperties(directory.path);
-    }
-  }
 }
 
 /// Represents the contents of the ios/ folder of a Flutter project.
diff --git a/packages/flutter_tools/lib/src/runner/flutter_command.dart b/packages/flutter_tools/lib/src/runner/flutter_command.dart
index ca48a1a..9d08b3e 100644
--- a/packages/flutter_tools/lib/src/runner/flutter_command.dart
+++ b/packages/flutter_tools/lib/src/runner/flutter_command.dart
@@ -21,7 +21,6 @@
 import '../doctor.dart';
 import '../flx.dart' as flx;
 import '../globals.dart';
-import '../project.dart';
 import '../usage.dart';
 import 'flutter_command_runner.dart';
 
@@ -273,10 +272,8 @@
     if (shouldUpdateCache)
       await cache.updateAll();
 
-    if (shouldRunPub) {
+    if (shouldRunPub)
       await pubGet(context: PubContext.getVerifyContext(name));
-      new FlutterProject(fs.currentDirectory).ensureReadyForPlatformSpecificTooling();
-    }
 
     setupApplicationPackages();
 
diff --git a/packages/flutter_tools/test/commands/packages_test.dart b/packages/flutter_tools/test/commands/packages_test.dart
index 42bd5c2..86bbc28 100644
--- a/packages/flutter_tools/test/commands/packages_test.dart
+++ b/packages/flutter_tools/test/commands/packages_test.dart
@@ -29,19 +29,9 @@
       temp.deleteSync(recursive: true);
     });
 
-    Future<String> createProjectWithPlugin(String plugin) async {
+    Future<String> runCommand(String verb, { List<String> args }) async {
       final String projectPath = await createProject(temp);
-      final File pubspec = fs.file(fs.path.join(projectPath, 'pubspec.yaml'));
-      String content = await pubspec.readAsString();
-      content = content.replaceFirst(
-        '\ndependencies:\n',
-        '\ndependencies:\n  $plugin:\n',
-      );
-      await pubspec.writeAsString(content, flush: true);
-      return projectPath;
-    }
 
-    Future<Null> runCommandIn(String projectPath, String verb, { List<String> args }) async {
       final PackagesCommand command = new PackagesCommand();
       final CommandRunner<Null> runner = createTestCommandRunner(command);
 
@@ -51,138 +41,31 @@
       commandArgs.add(projectPath);
 
       await runner.run(commandArgs);
+
+      return projectPath;
     }
 
     void expectExists(String projectPath, String relPath) {
       expect(fs.isFileSync(fs.path.join(projectPath, relPath)), true);
     }
 
-    void expectContains(String projectPath, String relPath, String substring) {
-      expectExists(projectPath, relPath);
-      expect(
-        fs.file(fs.path.join(projectPath, relPath)).readAsStringSync(),
-        contains(substring),
-      );
-    }
-
-    void expectNotExists(String projectPath, String relPath) {
-      expect(fs.isFileSync(fs.path.join(projectPath, relPath)), false);
-    }
-
-    void expectNotContains(String projectPath, String relPath, String substring) {
-      expectExists(projectPath, relPath);
-      expect(
-        fs.file(fs.path.join(projectPath, relPath)).readAsStringSync(),
-        isNot(contains(substring)),
-      );
-    }
-
-    const List<String> pubOutput = const <String>[
-      '.packages',
-      'pubspec.lock',
-    ];
-
-    const List<String> pluginRegistrants = const <String>[
-      'ios/Runner/GeneratedPluginRegistrant.h',
-      'ios/Runner/GeneratedPluginRegistrant.m',
-      'android/app/src/main/java/io/flutter/plugins/GeneratedPluginRegistrant.java',
-    ];
-
-    const List<String> pluginWitnesses = const <String>[
-      '.flutter-plugins',
-      'ios/Podfile',
-    ];
-
-    const Map<String, String> pluginContentWitnesses = const <String, String>{
-      'ios/Flutter/Debug.xcconfig': '#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"',
-      'ios/Flutter/Release.xcconfig': '#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"',
-    };
-
-    void expectDependenciesResolved(String projectPath) {
-      for (String output in pubOutput) {
-        expectExists(projectPath, output);
-      }
-    }
-
-    void expectZeroPluginsInjected(String projectPath) {
-      for (final String registrant in pluginRegistrants) {
-        expectExists(projectPath, registrant);
-      }
-      for (final String witness in pluginWitnesses) {
-        expectNotExists(projectPath, witness);
-      }
-      pluginContentWitnesses.forEach((String witness, String content) {
-        expectNotContains(projectPath, witness, content);
-      });
-    }
-
-    void expectPluginInjected(String projectPath) {
-      for (final String registrant in pluginRegistrants) {
-        expectExists(projectPath, registrant);
-      }
-      for (final String witness in pluginWitnesses) {
-        expectExists(projectPath, witness);
-      }
-      pluginContentWitnesses.forEach((String witness, String content) {
-        expectContains(projectPath, witness, content);
-      });
-    }
-
-    void removeGeneratedFiles(String projectPath) {
-      final Iterable<String> allFiles = <List<String>>[
-        pubOutput,
-        pluginRegistrants,
-        pluginWitnesses,
-      ].expand((List<String> list) => list);
-      for (String path in allFiles) {
-        final File file = fs.file(fs.path.join(projectPath, path));
-        if (file.existsSync())
-          file.deleteSync();
-      }
-    }
-
-    testUsingContext('get fetches packages', () async {
-      final String projectPath = await createProject(temp);
-
-      removeGeneratedFiles(projectPath);
-
-      await runCommandIn(projectPath, 'get');
-
-      expectDependenciesResolved(projectPath);
-      expectZeroPluginsInjected(projectPath);
+    // Verify that we create a project that is well-formed.
+    testUsingContext('get', () async {
+      final String projectPath = await runCommand('get');
+      expectExists(projectPath, 'lib/main.dart');
+      expectExists(projectPath, '.packages');
     }, timeout: allowForRemotePubInvocation);
 
-    testUsingContext('get --offline fetches packages', () async {
-      final String projectPath = await createProject(temp);
+    testUsingContext('get --offline', () async {
+      final String projectPath = await runCommand('get', args: <String>['--offline']);
+      expectExists(projectPath, 'lib/main.dart');
+      expectExists(projectPath, '.packages');
+    });
 
-      removeGeneratedFiles(projectPath);
-
-      await runCommandIn(projectPath, 'get', args: <String>['--offline']);
-
-      expectDependenciesResolved(projectPath);
-      expectZeroPluginsInjected(projectPath);
-    }, timeout: allowForCreateFlutterProject);
-
-    testUsingContext('upgrade fetches packages', () async {
-      final String projectPath = await createProject(temp);
-
-      removeGeneratedFiles(projectPath);
-
-      await runCommandIn(projectPath, 'upgrade');
-
-      expectDependenciesResolved(projectPath);
-      expectZeroPluginsInjected(projectPath);
-    }, timeout: allowForRemotePubInvocation);
-
-    testUsingContext('get fetches packages and injects plugin', () async {
-      final String projectPath = await createProjectWithPlugin('path_provider');
-
-      removeGeneratedFiles(projectPath);
-
-      await runCommandIn(projectPath, 'get');
-
-      expectDependenciesResolved(projectPath);
-      expectPluginInjected(projectPath);
+    testUsingContext('upgrade', () async {
+      final String projectPath = await runCommand('upgrade');
+      expectExists(projectPath, 'lib/main.dart');
+      expectExists(projectPath, '.packages');
     }, timeout: allowForRemotePubInvocation);
   });
 
diff --git a/packages/flutter_tools/test/ios/cocoapods_test.dart b/packages/flutter_tools/test/ios/cocoapods_test.dart
index 77c1e6d..531c8ab 100644
--- a/packages/flutter_tools/test/ios/cocoapods_test.dart
+++ b/packages/flutter_tools/test/ios/cocoapods_test.dart
@@ -6,11 +6,9 @@
 
 import 'package:file/file.dart';
 import 'package:file/memory.dart';
-import 'package:flutter_tools/src/base/common.dart';
 import 'package:flutter_tools/src/base/io.dart';
-import 'package:flutter_tools/src/cache.dart';
 import 'package:flutter_tools/src/ios/cocoapods.dart';
-import 'package:flutter_tools/src/ios/xcodeproj.dart';
+import 'package:flutter_tools/src/cache.dart';
 import 'package:mockito/mockito.dart';
 import 'package:process/process.dart';
 import 'package:test/test.dart';
@@ -20,7 +18,6 @@
 void main() {
   FileSystem fs;
   ProcessManager mockProcessManager;
-  MockXcodeProjectInterpreter mockXcodeProjectInterpreter;
   Directory projectUnderTest;
   CocoaPods cocoaPodsUnderTest;
 
@@ -28,9 +25,7 @@
     Cache.flutterRoot = 'flutter';
     fs = new MemoryFileSystem();
     mockProcessManager = new MockProcessManager();
-    mockXcodeProjectInterpreter = new MockXcodeProjectInterpreter();
     projectUnderTest = fs.directory(fs.path.join('project', 'ios'))..createSync(recursive: true);
-
     fs.file(fs.path.join(
       Cache.flutterRoot, 'packages', 'flutter_tools', 'templates', 'cocoapods', 'Podfile-objc'
     ))
@@ -50,122 +45,97 @@
     )).thenReturn(exitsHappy);
   });
 
-  group('Setup Podfile', () {
-    File podfile;
-    File debugConfigFile;
-    File releaseConfigFile;
-
-    setUp(() {
-      debugConfigFile = fs.file(fs.path.join('project', 'ios', 'Flutter', 'Debug.xcconfig'));
-      releaseConfigFile = fs.file(fs.path.join('project', 'ios', 'Flutter', 'Release.xcconfig'));
-      podfile = fs.file(fs.path.join('project', 'ios', 'Podfile'));
-    });
-
-    testUsingContext('creates objective-c Podfile when not present', () {
-      cocoaPodsUnderTest.setupPodfile('project');
-
-      expect(podfile.readAsStringSync(), 'Objective-C podfile template');
-    }, overrides: <Type, Generator>{
-      FileSystem: () => fs,
-    });
-
-    testUsingContext('creates swift Podfile if swift', () {
-      when(mockXcodeProjectInterpreter.canInterpretXcodeProjects).thenReturn(true);
-      when(mockXcodeProjectInterpreter.getBuildSettings(any, any)).thenReturn(<String, String>{
-        'SWIFT_VERSION': '4.0',
-      });
-
-      cocoaPodsUnderTest.setupPodfile('project');
-
-      expect(podfile.readAsStringSync(), 'Swift podfile template');
-    }, overrides: <Type, Generator>{
-      FileSystem: () => fs,
-      XcodeProjectInterpreter: () => mockXcodeProjectInterpreter,
-    });
-
-    testUsingContext('does not recreate Podfile when already present', () {
-      podfile..createSync()..writeAsStringSync('Existing Podfile');
-
-      cocoaPodsUnderTest.setupPodfile('project');
-
-      expect(podfile.readAsStringSync(), 'Existing Podfile');
-    }, overrides: <Type, Generator>{
-      FileSystem: () => fs,
-    });
-
-    testUsingContext('does not create Podfile when we cannot interpret Xcode projects', () {
-      when(mockXcodeProjectInterpreter.canInterpretXcodeProjects).thenReturn(false);
-
-      cocoaPodsUnderTest.setupPodfile('project');
-
-      expect(podfile.existsSync(), false);
-    }, overrides: <Type, Generator>{
-      FileSystem: () => fs,
-      XcodeProjectInterpreter: () => mockXcodeProjectInterpreter,
-    });
-
-    testUsingContext('includes Pod config in xcconfig files, if not present', () {
-      podfile..createSync()..writeAsStringSync('Existing Podfile');
-      debugConfigFile..createSync(recursive: true)..writeAsStringSync('Existing debug config');
-      releaseConfigFile..createSync(recursive: true)..writeAsStringSync('Existing release config');
-
-      cocoaPodsUnderTest.setupPodfile('project');
-
-      final String debugContents = debugConfigFile.readAsStringSync();
-      expect(debugContents, contains(
-          '#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"\n'));
-      expect(debugContents, contains('Existing debug config'));
-      final String releaseContents = releaseConfigFile.readAsStringSync();
-      expect(releaseContents, contains(
-          '#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"\n'));
-      expect(releaseContents, contains('Existing release config'));
-    }, overrides: <Type, Generator>{
-      FileSystem: () => fs,
-    });
-  });
-
-  group('Process pods', () {
-    testUsingContext('prints error, if CocoaPods is not installed', () async {
-      projectUnderTest.childFile('Podfile').createSync();
-      cocoaPodsUnderTest = const TestCocoaPods(false);
+  testUsingContext(
+    'create objective-c Podfile when not present',
+    () async {
       await cocoaPodsUnderTest.processPods(
         appIosDir: projectUnderTest,
         iosEngineDir: 'engine/path',
       );
-      verifyNever(mockProcessManager.run(
-        typed<List<String>>(any),
-        workingDirectory: any,
-        environment: typed<Map<String, String>>(any, named: 'environment'),
+      expect(fs.file(fs.path.join('project', 'ios', 'Podfile')).readAsStringSync() , 'Objective-C podfile template');
+      verify(mockProcessManager.run(
+        <String>['pod', 'install', '--verbose'],
+        workingDirectory: 'project/ios',
+        environment: <String, String>{'FLUTTER_FRAMEWORK_DIR': 'engine/path', 'COCOAPODS_DISABLE_STATS': 'true'},
       ));
-      expect(testLogger.errorText, contains('not installed'));
-      expect(testLogger.errorText, contains('Skipping pod install'));
-    }, overrides: <Type, Generator>{
+    },
+    overrides: <Type, Generator>{
       FileSystem: () => fs,
       ProcessManager: () => mockProcessManager,
-    });
+    },
+  );
 
-    testUsingContext('throws, if Podfile is missing.', () async {
-      cocoaPodsUnderTest = const TestCocoaPods(true);
+  testUsingContext(
+    'create swift Podfile if swift',
+    () async {
+      await cocoaPodsUnderTest.processPods(
+        appIosDir: projectUnderTest,
+        iosEngineDir: 'engine/path',
+        isSwift: true,
+      );
+      expect(fs.file(fs.path.join('project', 'ios', 'Podfile')).readAsStringSync() , 'Swift podfile template');
+      verify(mockProcessManager.run(
+        <String>['pod', 'install', '--verbose'],
+        workingDirectory: 'project/ios',
+        environment: <String, String>{'FLUTTER_FRAMEWORK_DIR': 'engine/path', 'COCOAPODS_DISABLE_STATS': 'true'},
+      ));
+    },
+    overrides: <Type, Generator>{
+      FileSystem: () => fs,
+      ProcessManager: () => mockProcessManager,
+    },
+  );
+
+  testUsingContext(
+    'do not recreate Podfile when present',
+    () async {
+      fs.file(fs.path.join('project', 'ios', 'Podfile'))
+        ..createSync()
+        ..writeAsString('Existing Podfile');
+      await cocoaPodsUnderTest.processPods(
+        appIosDir: projectUnderTest,
+        iosEngineDir: 'engine/path',
+      );
+      expect(fs.file(fs.path.join('project', 'ios', 'Podfile')).readAsStringSync() , 'Existing Podfile');
+      verify(mockProcessManager.run(
+        <String>['pod', 'install', '--verbose'],
+        workingDirectory: 'project/ios',
+        environment: <String, String>{'FLUTTER_FRAMEWORK_DIR': 'engine/path', 'COCOAPODS_DISABLE_STATS': 'true'},
+      ));
+    },
+    overrides: <Type, Generator>{
+      FileSystem: () => fs,
+      ProcessManager: () => mockProcessManager,
+    },
+  );
+
+  testUsingContext(
+    'missing CocoaPods throws',
+    () async {
+      cocoaPodsUnderTest = const TestCocoaPods(false);
       try {
         await cocoaPodsUnderTest.processPods(
           appIosDir: projectUnderTest,
           iosEngineDir: 'engine/path',
         );
-        fail('ToolExit expected');
-      } catch(e) {
-        expect(e, const isInstanceOf<ToolExit>());
+        fail('Expected tool error');
+      } catch (ToolExit) {
         verifyNever(mockProcessManager.run(
-          typed<List<String>>(any),
-          workingDirectory: any,
-          environment: typed<Map<String, String>>(any, named: 'environment'),
+          <String>['pod', 'install', '--verbose'],
+          workingDirectory: 'project/ios',
+          environment: <String, String>{'FLUTTER_FRAMEWORK_DIR': 'engine/path', 'COCOAPODS_DISABLE_STATS': 'true'},
         ));
       }
-    }, overrides: <Type, Generator>{
+    },
+    overrides: <Type, Generator>{
       FileSystem: () => fs,
       ProcessManager: () => mockProcessManager,
-    });
+    },
+  );
 
-    testUsingContext('throws, if specs repo is outdated.', () async {
+  testUsingContext(
+    'outdated specs repo should print error',
+    () async {
       fs.file(fs.path.join('project', 'ios', 'Podfile'))
         ..createSync()
         ..writeAsString('Existing Podfile');
@@ -173,10 +143,7 @@
       when(mockProcessManager.run(
         <String>['pod', 'install', '--verbose'],
         workingDirectory: 'project/ios',
-        environment: <String, String>{
-          'FLUTTER_FRAMEWORK_DIR': 'engine/path',
-          'COCOAPODS_DISABLE_STATS': 'true',
-        },
+        environment: <String, String>{'FLUTTER_FRAMEWORK_DIR': 'engine/path', 'COCOAPODS_DISABLE_STATS': 'true'},
       )).thenReturn(new ProcessResult(
         1,
         1,
@@ -200,152 +167,78 @@
         await cocoaPodsUnderTest.processPods(
           appIosDir: projectUnderTest,
           iosEngineDir: 'engine/path',
-        );
-        fail('ToolExit expected');
-      } catch (e) {
-        expect(e, const isInstanceOf<ToolExit>());
-        expect(
-          testLogger.errorText,
-          contains("CocoaPods's specs repository is too out-of-date to satisfy dependencies"),
-        );
+        );      expect(fs.file(fs.path.join('project', 'ios', 'Podfile')).readAsStringSync() , 'Existing Podfile');
+        fail('Exception expected');
+      } catch (ToolExit) {
+        expect(testLogger.errorText, contains("CocoaPods's specs repository is too out-of-date to satisfy dependencies"));
       }
-    }, overrides: <Type, Generator>{
+    },
+    overrides: <Type, Generator>{
       FileSystem: () => fs,
       ProcessManager: () => mockProcessManager,
-    });
+    },
+  );
 
-    testUsingContext('run pod install, if Podfile.lock is missing', () async {
-      projectUnderTest.childFile('Podfile')
+  testUsingContext(
+    'Run pod install if plugins or flutter framework have changes.',
+        () async {
+      fs.file(fs.path.join('project', 'ios', 'Podfile'))
         ..createSync()
         ..writeAsString('Existing Podfile');
-      projectUnderTest.childFile('Pods/Manifest.lock')
+      fs.file(fs.path.join('project', 'ios', 'Podfile.lock'))
+        ..createSync()
+        ..writeAsString('Existing lock files.');
+      fs.file(fs.path.join('project', 'ios', 'Pods','Manifest.lock'))
         ..createSync(recursive: true)
-        ..writeAsString('Existing lock file.');
+        ..writeAsString('Existing lock files.');
       await cocoaPodsUnderTest.processPods(
-        appIosDir: projectUnderTest,
-        iosEngineDir: 'engine/path',
-        flutterPodChanged: false,
+          appIosDir: projectUnderTest,
+          iosEngineDir: 'engine/path',
+          pluginOrFlutterPodChanged: true
       );
       verify(mockProcessManager.run(
         <String>['pod', 'install', '--verbose'],
         workingDirectory: 'project/ios',
         environment: <String, String>{'FLUTTER_FRAMEWORK_DIR': 'engine/path', 'COCOAPODS_DISABLE_STATS': 'true'},
       ));
-    }, overrides: <Type, Generator>{
+    },
+    overrides: <Type, Generator>{
       FileSystem: () => fs,
       ProcessManager: () => mockProcessManager,
-    });
+    },
+  );
 
-    testUsingContext('runs pod install, if Manifest.lock is missing', () async {
-      projectUnderTest.childFile('Podfile')
+  testUsingContext(
+    'Skip pod install if plugins and flutter framework remain unchanged.',
+        () async {
+      fs.file(fs.path.join('project', 'ios', 'Podfile'))
         ..createSync()
         ..writeAsString('Existing Podfile');
-      projectUnderTest.childFile('Podfile.lock')
+      fs.file(fs.path.join('project', 'ios', 'Podfile.lock'))
         ..createSync()
-        ..writeAsString('Existing lock file.');
-      await cocoaPodsUnderTest.processPods(
-        appIosDir: projectUnderTest,
-        iosEngineDir: 'engine/path',
-        flutterPodChanged: false,
-      );
-      verify(mockProcessManager.run(
-        <String>['pod', 'install', '--verbose'],
-        workingDirectory: 'project/ios',
-        environment: <String, String>{
-          'FLUTTER_FRAMEWORK_DIR': 'engine/path',
-          'COCOAPODS_DISABLE_STATS': 'true',
-        },
-      ));
-    }, overrides: <Type, Generator>{
-      FileSystem: () => fs,
-      ProcessManager: () => mockProcessManager,
-    });
-
-    testUsingContext('runs pod install, if Manifest.lock different from Podspec.lock', () async {
-      projectUnderTest.childFile('Podfile')
-        ..createSync()
-        ..writeAsString('Existing Podfile');
-      projectUnderTest.childFile('Podfile.lock')
-        ..createSync()
-        ..writeAsString('Existing lock file.');
-      projectUnderTest.childFile('Pods/Manifest.lock')
+        ..writeAsString('Existing lock files.');
+      fs.file(fs.path.join('project', 'ios', 'Pods','Manifest.lock'))
         ..createSync(recursive: true)
-        ..writeAsString('Different lock file.');
+        ..writeAsString('Existing lock files.');
       await cocoaPodsUnderTest.processPods(
-        appIosDir: projectUnderTest,
-        iosEngineDir: 'engine/path',
-        flutterPodChanged: false,
-      );
-      verify(mockProcessManager.run(
-        <String>['pod', 'install', '--verbose'],
-        workingDirectory: 'project/ios',
-        environment: <String, String>{
-          'FLUTTER_FRAMEWORK_DIR': 'engine/path',
-          'COCOAPODS_DISABLE_STATS': 'true',
-        },
-      ));
-    }, overrides: <Type, Generator>{
-      FileSystem: () => fs,
-      ProcessManager: () => mockProcessManager,
-    });
-
-    testUsingContext('runs pod install, if flutter framework changed', () async {
-      projectUnderTest.childFile('Podfile')
-        ..createSync()
-        ..writeAsString('Existing Podfile');
-      projectUnderTest.childFile('Podfile.lock')
-        ..createSync()
-        ..writeAsString('Existing lock file.');
-      projectUnderTest.childFile('Pods/Manifest.lock')
-        ..createSync(recursive: true)
-        ..writeAsString('Existing lock file.');
-      await cocoaPodsUnderTest.processPods(
-        appIosDir: projectUnderTest,
-        iosEngineDir: 'engine/path',
-        flutterPodChanged: true,
-      );
-      verify(mockProcessManager.run(
-        <String>['pod', 'install', '--verbose'],
-        workingDirectory: 'project/ios',
-        environment: <String, String>{
-          'FLUTTER_FRAMEWORK_DIR': 'engine/path',
-          'COCOAPODS_DISABLE_STATS': 'true',
-        },
-      ));
-    }, overrides: <Type, Generator>{
-      FileSystem: () => fs,
-      ProcessManager: () => mockProcessManager,
-    });
-
-    testUsingContext('skips pod install, if nothing changed', () async {
-      projectUnderTest.childFile('Podfile')
-        ..createSync()
-        ..writeAsString('Existing Podfile');
-      projectUnderTest.childFile('Podfile.lock')
-        ..createSync()
-        ..writeAsString('Existing lock file.');
-      projectUnderTest.childFile('Pods/Manifest.lock')
-        ..createSync(recursive: true)
-        ..writeAsString('Existing lock file.');
-      await cocoaPodsUnderTest.processPods(
-        appIosDir: projectUnderTest,
-        iosEngineDir: 'engine/path',
-        flutterPodChanged: false,
+          appIosDir: projectUnderTest,
+          iosEngineDir: 'engine/path',
+          pluginOrFlutterPodChanged: false
       );
       verifyNever(mockProcessManager.run(
-        typed<List<String>>(any),
-        workingDirectory: any,
-        environment: typed<Map<String, String>>(any, named: 'environment'),
+        <String>['pod', 'install', '--verbose'],
+        workingDirectory: 'project/ios',
+        environment: <String, String>{'FLUTTER_FRAMEWORK_DIR': 'engine/path', 'COCOAPODS_DISABLE_STATS': 'true'},
       ));
-    }, overrides: <Type, Generator>{
+    },
+    overrides: <Type, Generator>{
       FileSystem: () => fs,
       ProcessManager: () => mockProcessManager,
-    });
-  });
+    },
+  );
 }
 
 class MockProcessManager extends Mock implements ProcessManager {}
-class MockXcodeProjectInterpreter extends Mock implements XcodeProjectInterpreter {}
 
 class TestCocoaPods extends CocoaPods {
   const TestCocoaPods([this._hasCocoaPods = true]);
diff --git a/packages/flutter_tools/test/project_test.dart b/packages/flutter_tools/test/project_test.dart
index 6ef5bbb..2f1a3ff 100644
--- a/packages/flutter_tools/test/project_test.dart
+++ b/packages/flutter_tools/test/project_test.dart
@@ -17,29 +17,6 @@
       final Directory directory = fs.directory('myproject');
       expect(new FlutterProject(directory).directory, directory);
     });
-    group('ensure ready for platform-specific tooling', () {
-      testInMemory('does nothing, if project is not created', () async {
-        final FlutterProject project = someProject();
-        project.ensureReadyForPlatformSpecificTooling();
-        expect(project.directory.existsSync(), isFalse);
-      });
-      testInMemory('injects plugins', () async {
-        final FlutterProject project = aProjectWithIos();
-        project.ensureReadyForPlatformSpecificTooling();
-        expect(project.ios.directory.childFile('Runner/GeneratedPluginRegistrant.h').existsSync(), isTrue);
-      });
-      testInMemory('generates Xcode configuration', () async {
-        final FlutterProject project = aProjectWithIos();
-        project.ensureReadyForPlatformSpecificTooling();
-        expect(project.ios.directory.childFile('Flutter/Generated.xcconfig').existsSync(), isTrue);
-      });
-      testInMemory('generates files in plugin example project', () async {
-        final FlutterProject project = aPluginProject();
-        project.ensureReadyForPlatformSpecificTooling();
-        expect(project.example.ios.directory.childFile('Runner/GeneratedPluginRegistrant.h').existsSync(), isTrue);
-        expect(project.example.ios.directory.childFile('Flutter/Generated.xcconfig').existsSync(), isTrue);
-      });
-    });
     group('organization names set', () {
       testInMemory('is empty, if project not created', () async {
         final FlutterProject project = someProject();
@@ -94,23 +71,8 @@
   });
 }
 
-FlutterProject someProject() => new FlutterProject(fs.directory('some_project'));
-
-FlutterProject aProjectWithIos() {
-  final Directory directory = fs.directory('ios_project');
-  directory.childFile('pubspec.yaml').createSync(recursive: true);
-  directory.childFile('.packages').createSync(recursive: true);
-  directory.childDirectory('ios').createSync(recursive: true);
-  return new FlutterProject(directory);
-}
-
-FlutterProject aPluginProject() {
-  final Directory directory = fs.directory('plugin_project/example');
-  directory.childFile('pubspec.yaml').createSync(recursive: true);
-  directory.childFile('.packages').createSync(recursive: true);
-  directory.childDirectory('ios').createSync(recursive: true);
-  return new FlutterProject(directory.parent);
-}
+FlutterProject someProject() =>
+    new FlutterProject(fs.directory('some_project'));
 
 void testInMemory(String description, Future<Null> testMethod()) {
   testUsingContext(
@@ -122,13 +84,6 @@
   );
 }
 
-void addPubPackages(Directory directory) {
-  directory.childFile('pubspec.yaml')
-    ..createSync(recursive: true);
-  directory.childFile('.packages')
-    ..createSync(recursive: true);
-}
-
 void addIosWithBundleId(Directory directory, String id) {
   directory
       .childDirectory('ios')
diff --git a/packages/flutter_tools/test/src/context.dart b/packages/flutter_tools/test/src/context.dart
index dbe5188..3c5fe1b 100644
--- a/packages/flutter_tools/test/src/context.dart
+++ b/packages/flutter_tools/test/src/context.dart
@@ -19,7 +19,6 @@
 import 'package:flutter_tools/src/doctor.dart';
 import 'package:flutter_tools/src/ios/mac.dart';
 import 'package:flutter_tools/src/ios/simulators.dart';
-import 'package:flutter_tools/src/ios/xcodeproj.dart';
 import 'package:flutter_tools/src/run_hot.dart';
 import 'package:flutter_tools/src/usage.dart';
 import 'package:flutter_tools/src/version.dart';
@@ -51,7 +50,6 @@
     ..putIfAbsent(OperatingSystemUtils, () => new MockOperatingSystemUtils())
     ..putIfAbsent(PortScanner, () => new MockPortScanner())
     ..putIfAbsent(Xcode, () => new Xcode())
-    ..putIfAbsent(XcodeProjectInterpreter, () => new MockXcodeProjectInterpreter())
     ..putIfAbsent(IOSSimulatorUtils, () {
       final MockIOSSimulatorUtils mock = new MockIOSSimulatorUtils();
       when(mock.getAttachedDevices()).thenReturn(<IOSSimulator>[]);
@@ -264,25 +262,6 @@
   void printWelcome() { }
 }
 
-class MockXcodeProjectInterpreter implements XcodeProjectInterpreter {
-  @override
-  bool get canInterpretXcodeProjects => true;
-
-  @override
-  Map<String, String> getBuildSettings(String projectPath, String target) {
-    return <String, String>{};
-  }
-
-  @override
-  XcodeProjectInfo getInfo(String projectPath) {
-    return new XcodeProjectInfo(
-      <String>['Runner'],
-      <String>['Debug', 'Release'],
-      <String>['Runner'],
-    );
-  }
-}
-
 class MockFlutterVersion extends Mock implements FlutterVersion {}
 
 class MockClock extends Mock implements Clock {}