Add a user friendly error message when no development team is selected for physical deployment (#7879)
diff --git a/packages/flutter_tools/lib/src/ios/mac.dart b/packages/flutter_tools/lib/src/ios/mac.dart
index 95231da..2129afb 100644
--- a/packages/flutter_tools/lib/src/ios/mac.dart
+++ b/packages/flutter_tools/lib/src/ios/mac.dart
@@ -5,6 +5,7 @@
import 'dart:async';
import 'dart:convert' show JSON;
+import 'package:meta/meta.dart';
import 'package:path/path.dart' as path;
import '../application_package.dart';
@@ -113,7 +114,7 @@
updateXcodeGeneratedProperties(flutterProjectPath, mode, target);
if (!_checkXcodeVersion())
- return new XcodeBuildResult(false);
+ return new XcodeBuildResult(success: 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.
@@ -169,7 +170,16 @@
printStatus(result.stderr);
if (result.stdout.isNotEmpty)
printStatus(result.stdout);
- return new XcodeBuildResult(false, stdout: result.stdout, stderr: result.stderr);
+ return new XcodeBuildResult(
+ success: false,
+ stdout: result.stdout,
+ stderr: result.stderr,
+ xcodeBuildExecution: new XcodeBuildExecution(
+ commands,
+ app.appDirectory,
+ buildForPhysicalDevice: buildForDevice,
+ ),
+ );
} else {
// Look for 'clean build/Release-iphoneos/Runner.app'.
RegExp regexp = new RegExp(r' clean (\S*\.app)$', multiLine: true);
@@ -177,11 +187,11 @@
String outputDir;
if (match != null)
outputDir = path.join(app.appDirectory, match.group(1));
- return new XcodeBuildResult(true, output: outputDir);
+ return new XcodeBuildResult(success:true, output: outputDir);
}
}
-void diagnoseXcodeBuildFailure(XcodeBuildResult result) {
+Future<Null> diagnoseXcodeBuildFailure(XcodeBuildResult result) async {
File plistFile = fs.file('ios/Runner/Info.plist');
if (plistFile.existsSync()) {
String plistContent = plistFile.readAsStringSync();
@@ -206,15 +216,73 @@
printError(" open ios/Runner.xcodeproj");
return;
}
+ if (result.xcodeBuildExecution != null) {
+ assert(result.xcodeBuildExecution.buildForPhysicalDevice != null);
+ assert(result.xcodeBuildExecution.buildCommands != null);
+ assert(result.xcodeBuildExecution.appDirectory != null);
+ if (result.xcodeBuildExecution.buildForPhysicalDevice &&
+ result.xcodeBuildExecution.buildCommands.contains('build')) {
+ RunResult checkBuildSettings = await runAsync(
+ result.xcodeBuildExecution.buildCommands..add('-showBuildSettings'),
+ workingDirectory: result.xcodeBuildExecution.appDirectory,
+ allowReentrantFlutter: true
+ );
+ // Make sure the user has specified at least the DEVELOPMENT_TEAM (for automatic Xcode 8)
+ // signing or the PROVISIONING_PROFILE (for manual signing or Xcode 7).
+ if (checkBuildSettings.exitCode == 0 &&
+ !checkBuildSettings.stdout?.contains(new RegExp(r'\bDEVELOPMENT_TEAM\b')) == true &&
+ !checkBuildSettings.stdout?.contains(new RegExp(r'\bPROVISIONING_PROFILE\b')) == true) {
+ printError('''
+═══════════════════════════════════════════════════════════════════════════════════
+Building an iOS app requires a selected Development Team with a Provisioning Profile
+Please ensure that a Development Team is selected by:
+ 1- Opening the Flutter project's Xcode target with
+ open ios/Runner.xcodeproj
+ 2- Select the 'Runner' project in the navigator then the 'Runner' target
+ in the project settings
+ 3- In the 'General' tab, make sure a 'Development Team' is selected\n
+For more information, please visit:
+ https://flutter.io/setup/#deploy-to-ios-devices\n
+Or run on an iOS simulator
+═══════════════════════════════════════════════════════════════════════════════════''');
+ }
+ }
+ }
}
class XcodeBuildResult {
- XcodeBuildResult(this.success, {this.output, this.stdout, this.stderr});
+ XcodeBuildResult(
+ {
+ @required this.success,
+ this.output,
+ this.stdout,
+ this.stderr,
+ this.xcodeBuildExecution,
+ }
+ );
final bool success;
final String output;
final String stdout;
final String stderr;
+ /// The invocation of the build that resulted in this result instance.
+ final XcodeBuildExecution xcodeBuildExecution;
+}
+
+/// Describes an invocation of a Xcode build command.
+class XcodeBuildExecution {
+ XcodeBuildExecution(
+ this.buildCommands,
+ this.appDirectory,
+ {
+ @required this.buildForPhysicalDevice,
+ }
+ );
+
+ /// The original list of Xcode build commands used to produce this build result.
+ final List<String> buildCommands;
+ final String appDirectory;
+ final bool buildForPhysicalDevice;
}
final RegExp _xcodeVersionRegExp = new RegExp(r'Xcode (\d+)\..*');