Add more instructions and handling for first time iOS run (#10521) * Before tests * Add the part to trust the cert on the device * flip the error checks since some are more specific and are more actionable * add tests * review
diff --git a/packages/flutter_tools/lib/src/commands/build_ios.dart b/packages/flutter_tools/lib/src/commands/build_ios.dart index 93792ec..eb72d4a 100644 --- a/packages/flutter_tools/lib/src/commands/build_ios.dart +++ b/packages/flutter_tools/lib/src/commands/build_ios.dart
@@ -45,7 +45,7 @@ if (getCurrentHostPlatform() != HostPlatform.darwin_x64) throwToolExit('Building for iOS is only supported on the Mac.'); - final IOSApp app = applicationPackages.getPackageForPlatform(TargetPlatform.ios); + final BuildableIOSApp app = applicationPackages.getPackageForPlatform(TargetPlatform.ios); if (app == null) throwToolExit('Application not configured for iOS'); @@ -73,7 +73,7 @@ ); if (!result.success) { - await diagnoseXcodeBuildFailure(result); + await diagnoseXcodeBuildFailure(result, app); throwToolExit('Encountered error while building for $logTarget.'); }
diff --git a/packages/flutter_tools/lib/src/ios/code_signing.dart b/packages/flutter_tools/lib/src/ios/code_signing.dart index 5a917db..169332d 100644 --- a/packages/flutter_tools/lib/src/ios/code_signing.dart +++ b/packages/flutter_tools/lib/src/ios/code_signing.dart
@@ -14,34 +14,60 @@ import '../base/terminal.dart'; import '../globals.dart'; +/// User message when no development certificates are found in the keychain. +/// +/// The user likely never did any iOS development. const String noCertificatesInstruction = ''' ═══════════════════════════════════════════════════════════════════════════════════ No valid code signing certificates were found -Please ensure that you have a valid Development Team with valid iOS Development Certificates -associated with your Apple ID by: - 1- Opening the Xcode application - 2- Go to Xcode->Preferences->Accounts - 3- Make sure that you're signed in with your Apple ID via the '+' button on the bottom left - 4- Make sure that you have development certificates available by signing up to Apple - Developer Program and/or downloading available profiles as needed. +You can connect to your Apple Developer account by signing in with your Apple ID in Xcode +and create an iOS Development Certificate as well as a Provisioning Profile for your project by: +$fixWithDevelopmentTeamInstruction + 5- Trust your newly created Development Certificate on your iOS device + via Settings > General > Device Management > [your new certificate] > Trust + For more information, please visit: https://developer.apple.com/library/content/documentation/IDEs/Conceptual/AppDistributionGuide/MaintainingCertificates/MaintainingCertificates.html Or run on an iOS simulator without code signing ═══════════════════════════════════════════════════════════════════════════════════'''; +/// User message when there are no provisioning profile for the current app bundle identifier. +/// +/// The user did iOS development but never on this project and/or device. +const String noProvisioningProfileInstruction = ''' +═══════════════════════════════════════════════════════════════════════════════════ +No Provisioning Profile was found for your project's Bundle Identifier or your device. +You can create a new Provisioning Profile for your project in Xcode for your +team by: +$fixWithDevelopmentTeamInstruction + +For more information, please visit: + https://flutter.io/setup/#deploy-to-ios-devices + +Or run on an iOS simulator without code signing +═══════════════════════════════════════════════════════════════════════════════════'''; +/// Fallback error message for signing issues. +/// +/// Couldn't auto sign the app but can likely solved by retracing the signing flow in Xcode. const String noDevelopmentTeamInstruction = ''' ═══════════════════════════════════════════════════════════════════════════════════ Building a deployable 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 +$fixWithDevelopmentTeamInstruction + +For more information, please visit: + https://flutter.io/setup/#deploy-to-ios-devices + +Or run on an iOS simulator without code signing +═══════════════════════════════════════════════════════════════════════════════════'''; +const String fixWithDevelopmentTeamInstruction = ''' + 1- Open the Flutter project's Xcode target with open ios/Runner.xcworkspace 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 -═══════════════════════════════════════════════════════════════════════════════════'''; + 3- In the 'General' tab, make sure a 'Development Team' is selected. You may need to add + your Apple ID first. + 4- Build or run your project again'''; final RegExp _securityFindIdentityDeveloperIdentityExtractionPattern = new RegExp(r'^\s*\d+\).+"(.+Developer.+)"$');
diff --git a/packages/flutter_tools/lib/src/ios/devices.dart b/packages/flutter_tools/lib/src/ios/devices.dart index 0b4d0be..a1cb175 100644 --- a/packages/flutter_tools/lib/src/ios/devices.dart +++ b/packages/flutter_tools/lib/src/ios/devices.dart
@@ -208,7 +208,7 @@ final XcodeBuildResult buildResult = await buildXcodeProject(app: app, mode: mode, target: mainPath, buildForDevice: true); if (!buildResult.success) { printError('Could not build the precompiled application for the device.'); - await diagnoseXcodeBuildFailure(buildResult); + await diagnoseXcodeBuildFailure(buildResult, app); printError(''); return new LaunchResult.failed(); } @@ -242,7 +242,7 @@ // the port picked and scrape that later. } - if (debuggingOptions.enableSoftwareRendering) + if (debuggingOptions.enableSoftwareRendering) launchArguments.add('--enable-software-rendering'); if (platformArgs['trace-startup'] ?? false)
diff --git a/packages/flutter_tools/lib/src/ios/mac.dart b/packages/flutter_tools/lib/src/ios/mac.dart index 84f6aab..16430aa 100644 --- a/packages/flutter_tools/lib/src/ios/mac.dart +++ b/packages/flutter_tools/lib/src/ios/mac.dart
@@ -147,7 +147,7 @@ } String developmentTeam; - if (codesign && mode != BuildMode.release && buildForDevice) + if (codesign && buildForDevice) developmentTeam = await getCodeSigningIdentityDevelopmentTeam(app); // Before the build, all service definitions must be updated and the dylibs @@ -246,51 +246,40 @@ } } -Future<Null> diagnoseXcodeBuildFailure(XcodeBuildResult result) async { - final File plistFile = fs.file('ios/Runner/Info.plist'); - if (plistFile.existsSync()) { - final String plistContent = plistFile.readAsStringSync(); - if (plistContent.contains('com.yourcompany')) { - printError(''); - printError('It appears that your application still contains the default signing identifier.'); - printError("Try replacing 'com.yourcompany' with your signing id"); - printError('in ${plistFile.absolute.path}'); - return; - } +Future<Null> diagnoseXcodeBuildFailure(XcodeBuildResult result, BuildableIOSApp app) async { + if (result.xcodeBuildExecution != null && + result.xcodeBuildExecution.buildForPhysicalDevice && + result.stdout?.contains('BCEROR') == true && + // May need updating if Xcode changes its outputs. + result.stdout?.contains('Xcode couldn\'t find a provisioning profile matching') == true) { + printError(noProvisioningProfileInstruction, emphasis: true); + return; + } + if (result.xcodeBuildExecution != null && + result.xcodeBuildExecution.buildForPhysicalDevice && + // 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). + !(app.buildSettings?.containsKey('DEVELOPMENT_TEAM')) == true || app.buildSettings?.containsKey('PROVISIONING_PROFILE') == true) { + printError(noDevelopmentTeamInstruction, emphasis: true); + return; + } + if (app.id?.contains('com.yourcompany') ?? false) { + printError(''); + printError('It appears that your application still contains the default signing identifier.'); + printError("Try replacing 'com.yourcompany' with your signing id in Xcode:"); + printError(' open ios/Runner.xcworkspace'); + return; } if (result.stdout?.contains('Code Sign error') == true) { printError(''); printError('It appears that there was a problem signing your application prior to installation on the device.'); printError(''); - if (plistFile.existsSync()) { - printError('Verify that the CFBundleIdentifier in the Info.plist file is your signing id'); - printError(' ${plistFile.absolute.path}'); - printError(''); - } - printError("Try launching Xcode and selecting 'Product > Build' to fix the problem:"); - printError(" open ios/Runner.xcworkspace"); + printError('Verify that the Bundle Identifier in your project is your signing id in Xcode'); + printError(' open ios/Runner.xcworkspace'); + printError(''); + printError("Also try selecting 'Product > Build' to fix the problem:"); 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')) { - final 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(noDevelopmentTeamInstruction, emphasis: true); - } - } - } } class XcodeBuildResult {