add the ability to start and stop device polling
diff --git a/packages/flutter_tools/lib/src/ios/mac.dart b/packages/flutter_tools/lib/src/ios/mac.dart
index d2aacc3..ef95ce0 100644
--- a/packages/flutter_tools/lib/src/ios/mac.dart
+++ b/packages/flutter_tools/lib/src/ios/mac.dart
@@ -2,8 +2,23 @@
 // 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:convert' show JSON;
+import 'dart:io';
+
+import 'package:path/path.dart' as path;
+
+import '../application_package.dart';
+import '../artifacts.dart';
 import '../base/context.dart';
 import '../base/process.dart';
+import '../globals.dart';
+import '../services.dart';
+import 'setup_xcodeproj.dart';
+
+String get homeDirectory => path.absolute(Platform.environment['HOME']);
+
+// TODO(devoncarew): Refactor functionality into XCode.
 
 const int kXcodeRequiredVersionMajor = 7;
 const int kXcodeRequiredVersionMinor = 2;
@@ -51,3 +66,135 @@
     return false;
   }
 }
+
+Future<bool> buildIOSXcodeProject(ApplicationPackage app, { bool buildForDevice }) async {
+  String flutterProjectPath = Directory.current.path;
+
+  if (xcodeProjectRequiresUpdate()) {
+    printTrace('Initializing the Xcode project.');
+    if ((await setupXcodeProjectHarness(flutterProjectPath)) != 0) {
+      printError('Could not initialize the Xcode project.');
+      return false;
+    }
+  } else {
+   updateXcodeLocalProperties(flutterProjectPath);
+  }
+
+  if (!_validateEngineRevision(app))
+    return false;
+
+  if (!_checkXcodeVersion())
+    return false;
+
+  // Before the build, all service definitions must be updated and the dylibs
+  // copied over to a location that is suitable for Xcodebuild to find them.
+
+  await _addServicesToBundle(new Directory(app.localPath));
+
+  List<String> commands = <String>[
+    '/usr/bin/env', 'xcrun', 'xcodebuild', '-target', 'Runner', '-configuration', 'Release'
+  ];
+
+  if (buildForDevice) {
+    commands.addAll(<String>['-sdk', 'iphoneos', '-arch', 'arm64']);
+  } else {
+    commands.addAll(<String>['-sdk', 'iphonesimulator', '-arch', 'x86_64']);
+  }
+
+  try {
+    runCheckedSync(commands, workingDirectory: app.localPath);
+    return true;
+  } catch (error) {
+    return false;
+  }
+}
+
+final RegExp _xcodeVersionRegExp = new RegExp(r'Xcode (\d+)\..*');
+final String _xcodeRequirement = 'Xcode 7.0 or greater is required to develop for iOS.';
+
+bool _checkXcodeVersion() {
+  if (!Platform.isMacOS)
+    return false;
+  try {
+    String version = runCheckedSync(<String>['xcodebuild', '-version']);
+    Match match = _xcodeVersionRegExp.firstMatch(version);
+    if (int.parse(match[1]) < 7) {
+      printError('Found "${match[0]}". $_xcodeRequirement');
+      return false;
+    }
+  } catch (e) {
+    printError('Cannot find "xcodebuid". $_xcodeRequirement');
+    return false;
+  }
+  return true;
+}
+
+bool _validateEngineRevision(ApplicationPackage app) {
+  String skyRevision = ArtifactStore.engineRevision;
+  String iosRevision = _getIOSEngineRevision(app);
+
+  if (iosRevision != skyRevision) {
+    printError("Error: incompatible sky_engine revision.");
+    printStatus('sky_engine revision: $skyRevision, iOS engine revision: $iosRevision');
+    return false;
+  } else {
+    printTrace('sky_engine revision: $skyRevision, iOS engine revision: $iosRevision');
+    return true;
+  }
+}
+
+String _getIOSEngineRevision(ApplicationPackage app) {
+  File revisionFile = new File(path.join(app.localPath, 'REVISION'));
+  if (revisionFile.existsSync()) {
+    return revisionFile.readAsStringSync().trim();
+  } else {
+    return null;
+  }
+}
+
+Future _addServicesToBundle(Directory bundle) async {
+  List<Map<String, String>> services = [];
+  printTrace("Trying to resolve native pub services.");
+
+  // Step 1: Parse the service configuration yaml files present in the service
+  //         pub packages.
+  await parseServiceConfigs(services);
+  printTrace("Found ${services.length} service definition(s).");
+
+  // Step 2: Copy framework dylibs to the correct spot for xcodebuild to pick up.
+  Directory frameworksDirectory = new Directory(path.join(bundle.path, "Frameworks"));
+  await _copyServiceFrameworks(services, frameworksDirectory);
+
+  // Step 3: Copy the service definitions manifest at the correct spot for
+  //         xcodebuild to pick up.
+  File manifestFile = new File(path.join(bundle.path, "ServiceDefinitions.json"));
+  _copyServiceDefinitionsManifest(services, manifestFile);
+}
+
+Future _copyServiceFrameworks(List<Map<String, String>> services, Directory frameworksDirectory) async {
+  printTrace("Copying service frameworks to '${path.absolute(frameworksDirectory.path)}'.");
+  frameworksDirectory.createSync(recursive: true);
+  for (Map<String, String> service in services) {
+    String dylibPath = await getServiceFromUrl(service['ios-framework'], service['root'], service['name']);
+    File dylib = new File(dylibPath);
+    printTrace("Copying ${dylib.path} into bundle.");
+    if (!dylib.existsSync()) {
+      printError("The service dylib '${dylib.path}' does not exist.");
+      continue;
+    }
+    // Shell out so permissions on the dylib are preserved.
+    runCheckedSync(['/bin/cp', dylib.path, frameworksDirectory.path]);
+  }
+}
+
+void _copyServiceDefinitionsManifest(List<Map<String, String>> services, File manifest) {
+  printTrace("Creating service definitions manifest at '${manifest.path}'");
+  List<Map<String, String>> jsonServices = services.map((Map<String, String> service) => {
+    'name': service['name'],
+    // Since we have already moved it to the Frameworks directory. Strip away
+    // the directory and basenames.
+    'framework': path.basenameWithoutExtension(service['ios-framework'])
+  }).toList();
+  Map<String, dynamic> json = { 'services' : jsonServices };
+  manifest.writeAsStringSync(JSON.encode(json), mode: FileMode.WRITE, flush: true);
+}