Skip to content

Commit 1755819

Browse files
author
Chris Yang
authored
Log XCResult before other build issues (#100787)
1 parent 74cdc42 commit 1755819

File tree

5 files changed

+421
-130
lines changed

5 files changed

+421
-130
lines changed

packages/flutter_tools/lib/src/ios/mac.dart

Lines changed: 84 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -574,37 +574,14 @@ Future<void> diagnoseXcodeBuildFailure(XcodeBuildResult result, Usage flutterUsa
574574
).send();
575575
}
576576

577-
// Building for iOS Simulator, but the linked and embedded framework 'App.framework' was built for iOS.
578-
// or
579-
// Building for iOS, but the linked and embedded framework 'App.framework' was built for iOS Simulator.
580-
if ((result.stdout?.contains('Building for iOS') ?? false)
581-
&& (result.stdout?.contains('but the linked and embedded framework') ?? false)
582-
&& (result.stdout?.contains('was built for iOS') ?? false)) {
583-
logger.printError('');
584-
logger.printError('Your Xcode project requires migration. See https://flutter.dev/docs/development/ios-project-migration for details.');
585-
logger.printError('');
586-
logger.printError('You can temporarily work around this issue by running:');
587-
logger.printError(' flutter clean');
588-
return;
589-
}
590-
if (xcodeBuildExecution != null
591-
&& xcodeBuildExecution.environmentType == EnvironmentType.physical
592-
&& (result.stdout?.contains('BCEROR') ?? false)
593-
// May need updating if Xcode changes its outputs.
594-
&& (result.stdout?.contains("Xcode couldn't find a provisioning profile matching") ?? false)) {
595-
logger.printError(noProvisioningProfileInstruction, emphasis: true);
596-
return;
597-
}
598-
// Make sure the user has specified one of:
599-
// * DEVELOPMENT_TEAM (automatic signing)
600-
// * PROVISIONING_PROFILE (manual signing)
601-
if (xcodeBuildExecution != null &&
602-
xcodeBuildExecution.environmentType == EnvironmentType.physical &&
603-
!<String>['DEVELOPMENT_TEAM', 'PROVISIONING_PROFILE'].any(
604-
xcodeBuildExecution.buildSettings.containsKey)) {
605-
logger.printError(noDevelopmentTeamInstruction, emphasis: true);
606-
return;
577+
// Handle errors.
578+
final bool issueDetected = _handleIssues(result.xcResult, logger, xcodeBuildExecution);
579+
580+
if (!issueDetected && xcodeBuildExecution != null) {
581+
// Fallback to use stdout to detect and print issues.
582+
_parseIssueInStdout(xcodeBuildExecution, logger, result);
607583
}
584+
608585
if (xcodeBuildExecution != null
609586
&& xcodeBuildExecution.environmentType == EnvironmentType.physical
610587
&& (xcodeBuildExecution.buildSettings['PRODUCT_BUNDLE_IDENTIFIER']?.contains('com.example') ?? false)) {
@@ -614,19 +591,6 @@ Future<void> diagnoseXcodeBuildFailure(XcodeBuildResult result, Usage flutterUsa
614591
logger.printError(' open ios/Runner.xcworkspace');
615592
return;
616593
}
617-
618-
// Handle xcresult errors.
619-
final XCResult? xcResult = result.xcResult;
620-
if (xcResult == null) {
621-
return;
622-
}
623-
if (!xcResult.parseSuccess) {
624-
globals.printTrace('XCResult parsing error: ${xcResult.parsingErrorMessage}');
625-
return;
626-
}
627-
for (final XCResultIssue issue in xcResult.issues) {
628-
_handleXCResultIssue(issue: issue, logger: logger);
629-
}
630594
}
631595

632596
/// xcodebuild <buildaction> parameter (see man xcodebuild for details).
@@ -724,7 +688,7 @@ bool upgradePbxProjWithFlutterAssets(IosProject project, Logger logger) {
724688
return true;
725689
}
726690

727-
void _handleXCResultIssue({required XCResultIssue issue, required Logger logger}) {
691+
_XCResultIssueHandlingResult _handleXCResultIssue({required XCResultIssue issue, required Logger logger}) {
728692
// Issue summary from xcresult.
729693
final StringBuffer issueSummaryBuffer = StringBuffer();
730694
issueSummaryBuffer.write(issue.subType ?? 'Unknown');
@@ -744,16 +708,89 @@ void _handleXCResultIssue({required XCResultIssue issue, required Logger logger}
744708
break;
745709
}
746710

747-
// Add more custom output for flutter users.
748-
if (issue.message != null && issue.message!.toLowerCase().contains('provisioning profile')) {
711+
final String? message = issue.message;
712+
if (message == null) {
713+
return _XCResultIssueHandlingResult(requiresProvisioningProfile: false, hasProvisioningProfileIssue: false);
714+
}
715+
716+
// Add more error messages for flutter users for some special errors.
717+
if (message.toLowerCase().contains('requires a provisioning profile.')) {
718+
return _XCResultIssueHandlingResult(requiresProvisioningProfile: true, hasProvisioningProfileIssue: true);
719+
} else if (message.toLowerCase().contains('provisioning profile')) {
720+
return _XCResultIssueHandlingResult(requiresProvisioningProfile: false, hasProvisioningProfileIssue: true);
721+
}
722+
return _XCResultIssueHandlingResult(requiresProvisioningProfile: false, hasProvisioningProfileIssue: false);
723+
}
724+
725+
// Returns `true` if at least one issue is detected.
726+
bool _handleIssues(XCResult? xcResult, Logger logger, XcodeBuildExecution? xcodeBuildExecution) {
727+
bool requiresProvisioningProfile = false;
728+
bool hasProvisioningProfileIssue = false;
729+
bool issueDetected = false;
730+
731+
if (xcResult != null && xcResult.parseSuccess) {
732+
for (final XCResultIssue issue in xcResult.issues) {
733+
final _XCResultIssueHandlingResult handlingResult = _handleXCResultIssue(issue: issue, logger: logger);
734+
if (handlingResult.hasProvisioningProfileIssue) {
735+
hasProvisioningProfileIssue = true;
736+
}
737+
if (handlingResult.requiresProvisioningProfile) {
738+
requiresProvisioningProfile = true;
739+
}
740+
issueDetected = true;
741+
}
742+
} else if (xcResult != null) {
743+
globals.printTrace('XCResult parsing error: ${xcResult.parsingErrorMessage}');
744+
}
745+
746+
if (requiresProvisioningProfile) {
747+
logger.printError(noProvisioningProfileInstruction, emphasis: true);
748+
} else if (_missingDevelopmentTeam(xcodeBuildExecution)) {
749+
issueDetected = true;
750+
logger.printError(noDevelopmentTeamInstruction, emphasis: true);
751+
} else if (hasProvisioningProfileIssue) {
749752
logger.printError('');
750753
logger.printError('It appears that there was a problem signing your application prior to installation on the device.');
751754
logger.printError('');
752755
logger.printError('Verify that the Bundle Identifier in your project is your signing id in Xcode');
753756
logger.printError(' open ios/Runner.xcworkspace');
754757
logger.printError('');
755-
logger.printError("Also try selecting 'Product > Build' to fix the problem:");
758+
logger.printError("Also try selecting 'Product > Build' to fix the problem.");
756759
}
760+
return issueDetected;
761+
}
762+
763+
// Return 'true' a missing development team issue is detected.
764+
bool _missingDevelopmentTeam(XcodeBuildExecution? xcodeBuildExecution) {
765+
// Make sure the user has specified one of:
766+
// * DEVELOPMENT_TEAM (automatic signing)
767+
// * PROVISIONING_PROFILE (manual signing)
768+
return xcodeBuildExecution != null && xcodeBuildExecution.environmentType == EnvironmentType.physical &&
769+
!<String>['DEVELOPMENT_TEAM', 'PROVISIONING_PROFILE'].any(
770+
xcodeBuildExecution.buildSettings.containsKey);
771+
}
772+
// Detects and handles errors from stdout.
773+
//
774+
// As detecting issues in stdout is not usually accurate, this should be used as a fallback when other issue detecting methods failed.
775+
void _parseIssueInStdout(XcodeBuildExecution xcodeBuildExecution, Logger logger, XcodeBuildResult result) {
776+
if (xcodeBuildExecution.environmentType == EnvironmentType.physical
777+
// May need updating if Xcode changes its outputs.
778+
&& (result.stdout?.contains('requires a provisioning profile. Select a provisioning profile in the Signing & Capabilities editor') ?? false)) {
779+
logger.printError(noProvisioningProfileInstruction, emphasis: true);
780+
return;
781+
}
782+
}
783+
784+
// The result of [_handleXCResultIssue].
785+
class _XCResultIssueHandlingResult {
786+
787+
_XCResultIssueHandlingResult({required this.requiresProvisioningProfile, required this.hasProvisioningProfileIssue});
788+
789+
// An issue indicates that user didn't provide the provisioning profile.
790+
final bool requiresProvisioningProfile;
791+
792+
// An issue indicates that there is a provisioning profile issue.
793+
final bool hasProvisioningProfileIssue;
757794
}
758795

759796
const String _kResultBundlePath = 'temporary_xcresult_bundle';

0 commit comments

Comments
 (0)