Log XCResult before other build issues (#100787)

This commit is contained in:
Chris Yang 2022-04-08 16:27:08 -07:00 committed by GitHub
parent 74cdc42207
commit 1755819cb1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 421 additions and 130 deletions

View File

@ -574,37 +574,14 @@ Future<void> diagnoseXcodeBuildFailure(XcodeBuildResult result, Usage flutterUsa
).send(); ).send();
} }
// Building for iOS Simulator, but the linked and embedded framework 'App.framework' was built for iOS. // Handle errors.
// or final bool issueDetected = _handleIssues(result.xcResult, logger, xcodeBuildExecution);
// Building for iOS, but the linked and embedded framework 'App.framework' was built for iOS Simulator.
if ((result.stdout?.contains('Building for iOS') ?? false) if (!issueDetected && xcodeBuildExecution != null) {
&& (result.stdout?.contains('but the linked and embedded framework') ?? false) // Fallback to use stdout to detect and print issues.
&& (result.stdout?.contains('was built for iOS') ?? false)) { _parseIssueInStdout(xcodeBuildExecution, logger, result);
logger.printError('');
logger.printError('Your Xcode project requires migration. See https://flutter.dev/docs/development/ios-project-migration for details.');
logger.printError('');
logger.printError('You can temporarily work around this issue by running:');
logger.printError(' flutter clean');
return;
}
if (xcodeBuildExecution != null
&& xcodeBuildExecution.environmentType == EnvironmentType.physical
&& (result.stdout?.contains('BCEROR') ?? false)
// May need updating if Xcode changes its outputs.
&& (result.stdout?.contains("Xcode couldn't find a provisioning profile matching") ?? false)) {
logger.printError(noProvisioningProfileInstruction, emphasis: true);
return;
}
// Make sure the user has specified one of:
// * DEVELOPMENT_TEAM (automatic signing)
// * PROVISIONING_PROFILE (manual signing)
if (xcodeBuildExecution != null &&
xcodeBuildExecution.environmentType == EnvironmentType.physical &&
!<String>['DEVELOPMENT_TEAM', 'PROVISIONING_PROFILE'].any(
xcodeBuildExecution.buildSettings.containsKey)) {
logger.printError(noDevelopmentTeamInstruction, emphasis: true);
return;
} }
if (xcodeBuildExecution != null if (xcodeBuildExecution != null
&& xcodeBuildExecution.environmentType == EnvironmentType.physical && xcodeBuildExecution.environmentType == EnvironmentType.physical
&& (xcodeBuildExecution.buildSettings['PRODUCT_BUNDLE_IDENTIFIER']?.contains('com.example') ?? false)) { && (xcodeBuildExecution.buildSettings['PRODUCT_BUNDLE_IDENTIFIER']?.contains('com.example') ?? false)) {
@ -614,19 +591,6 @@ Future<void> diagnoseXcodeBuildFailure(XcodeBuildResult result, Usage flutterUsa
logger.printError(' open ios/Runner.xcworkspace'); logger.printError(' open ios/Runner.xcworkspace');
return; return;
} }
// Handle xcresult errors.
final XCResult? xcResult = result.xcResult;
if (xcResult == null) {
return;
}
if (!xcResult.parseSuccess) {
globals.printTrace('XCResult parsing error: ${xcResult.parsingErrorMessage}');
return;
}
for (final XCResultIssue issue in xcResult.issues) {
_handleXCResultIssue(issue: issue, logger: logger);
}
} }
/// xcodebuild <buildaction> parameter (see man xcodebuild for details). /// xcodebuild <buildaction> parameter (see man xcodebuild for details).
@ -724,7 +688,7 @@ bool upgradePbxProjWithFlutterAssets(IosProject project, Logger logger) {
return true; return true;
} }
void _handleXCResultIssue({required XCResultIssue issue, required Logger logger}) { _XCResultIssueHandlingResult _handleXCResultIssue({required XCResultIssue issue, required Logger logger}) {
// Issue summary from xcresult. // Issue summary from xcresult.
final StringBuffer issueSummaryBuffer = StringBuffer(); final StringBuffer issueSummaryBuffer = StringBuffer();
issueSummaryBuffer.write(issue.subType ?? 'Unknown'); issueSummaryBuffer.write(issue.subType ?? 'Unknown');
@ -744,16 +708,89 @@ void _handleXCResultIssue({required XCResultIssue issue, required Logger logger}
break; break;
} }
// Add more custom output for flutter users. final String? message = issue.message;
if (issue.message != null && issue.message!.toLowerCase().contains('provisioning profile')) { if (message == null) {
return _XCResultIssueHandlingResult(requiresProvisioningProfile: false, hasProvisioningProfileIssue: false);
}
// Add more error messages for flutter users for some special errors.
if (message.toLowerCase().contains('requires a provisioning profile.')) {
return _XCResultIssueHandlingResult(requiresProvisioningProfile: true, hasProvisioningProfileIssue: true);
} else if (message.toLowerCase().contains('provisioning profile')) {
return _XCResultIssueHandlingResult(requiresProvisioningProfile: false, hasProvisioningProfileIssue: true);
}
return _XCResultIssueHandlingResult(requiresProvisioningProfile: false, hasProvisioningProfileIssue: false);
}
// Returns `true` if at least one issue is detected.
bool _handleIssues(XCResult? xcResult, Logger logger, XcodeBuildExecution? xcodeBuildExecution) {
bool requiresProvisioningProfile = false;
bool hasProvisioningProfileIssue = false;
bool issueDetected = false;
if (xcResult != null && xcResult.parseSuccess) {
for (final XCResultIssue issue in xcResult.issues) {
final _XCResultIssueHandlingResult handlingResult = _handleXCResultIssue(issue: issue, logger: logger);
if (handlingResult.hasProvisioningProfileIssue) {
hasProvisioningProfileIssue = true;
}
if (handlingResult.requiresProvisioningProfile) {
requiresProvisioningProfile = true;
}
issueDetected = true;
}
} else if (xcResult != null) {
globals.printTrace('XCResult parsing error: ${xcResult.parsingErrorMessage}');
}
if (requiresProvisioningProfile) {
logger.printError(noProvisioningProfileInstruction, emphasis: true);
} else if (_missingDevelopmentTeam(xcodeBuildExecution)) {
issueDetected = true;
logger.printError(noDevelopmentTeamInstruction, emphasis: true);
} else if (hasProvisioningProfileIssue) {
logger.printError(''); logger.printError('');
logger.printError('It appears that there was a problem signing your application prior to installation on the device.'); logger.printError('It appears that there was a problem signing your application prior to installation on the device.');
logger.printError(''); logger.printError('');
logger.printError('Verify that the Bundle Identifier in your project is your signing id in Xcode'); logger.printError('Verify that the Bundle Identifier in your project is your signing id in Xcode');
logger.printError(' open ios/Runner.xcworkspace'); logger.printError(' open ios/Runner.xcworkspace');
logger.printError(''); logger.printError('');
logger.printError("Also try selecting 'Product > Build' to fix the problem:"); logger.printError("Also try selecting 'Product > Build' to fix the problem.");
} }
return issueDetected;
}
// Return 'true' a missing development team issue is detected.
bool _missingDevelopmentTeam(XcodeBuildExecution? xcodeBuildExecution) {
// Make sure the user has specified one of:
// * DEVELOPMENT_TEAM (automatic signing)
// * PROVISIONING_PROFILE (manual signing)
return xcodeBuildExecution != null && xcodeBuildExecution.environmentType == EnvironmentType.physical &&
!<String>['DEVELOPMENT_TEAM', 'PROVISIONING_PROFILE'].any(
xcodeBuildExecution.buildSettings.containsKey);
}
// Detects and handles errors from stdout.
//
// As detecting issues in stdout is not usually accurate, this should be used as a fallback when other issue detecting methods failed.
void _parseIssueInStdout(XcodeBuildExecution xcodeBuildExecution, Logger logger, XcodeBuildResult result) {
if (xcodeBuildExecution.environmentType == EnvironmentType.physical
// May need updating if Xcode changes its outputs.
&& (result.stdout?.contains('requires a provisioning profile. Select a provisioning profile in the Signing & Capabilities editor') ?? false)) {
logger.printError(noProvisioningProfileInstruction, emphasis: true);
return;
}
}
// The result of [_handleXCResultIssue].
class _XCResultIssueHandlingResult {
_XCResultIssueHandlingResult({required this.requiresProvisioningProfile, required this.hasProvisioningProfileIssue});
// An issue indicates that user didn't provide the provisioning profile.
final bool requiresProvisioningProfile;
// An issue indicates that there is a provisioning profile issue.
final bool hasProvisioningProfileIssue;
} }
const String _kResultBundlePath = 'temporary_xcresult_bundle'; const String _kResultBundlePath = 'temporary_xcresult_bundle';

View File

@ -8,9 +8,11 @@ import 'package:args/command_runner.dart';
import 'package:file/memory.dart'; import 'package:file/memory.dart';
import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/base/platform.dart'; import 'package:flutter_tools/src/base/platform.dart';
import 'package:flutter_tools/src/build_info.dart';
import 'package:flutter_tools/src/cache.dart'; import 'package:flutter_tools/src/cache.dart';
import 'package:flutter_tools/src/commands/build.dart'; import 'package:flutter_tools/src/commands/build.dart';
import 'package:flutter_tools/src/commands/build_ios.dart'; import 'package:flutter_tools/src/commands/build_ios.dart';
import 'package:flutter_tools/src/ios/code_signing.dart';
import 'package:flutter_tools/src/ios/xcodeproj.dart'; import 'package:flutter_tools/src/ios/xcodeproj.dart';
import 'package:flutter_tools/src/reporting/reporting.dart'; import 'package:flutter_tools/src/reporting/reporting.dart';
@ -20,6 +22,9 @@ import '../../src/context.dart';
import '../../src/test_flutter_command_runner.dart'; import '../../src/test_flutter_command_runner.dart';
class FakeXcodeProjectInterpreterWithBuildSettings extends FakeXcodeProjectInterpreter { class FakeXcodeProjectInterpreterWithBuildSettings extends FakeXcodeProjectInterpreter {
FakeXcodeProjectInterpreterWithBuildSettings({this.productBundleIdentifier, this.developmentTeam = 'abc'});
@override @override
Future<Map<String, String>> getBuildSettings( Future<Map<String, String>> getBuildSettings(
String projectPath, { String projectPath, {
@ -27,12 +32,17 @@ class FakeXcodeProjectInterpreterWithBuildSettings extends FakeXcodeProjectInter
Duration timeout = const Duration(minutes: 1), Duration timeout = const Duration(minutes: 1),
}) async { }) async {
return <String, String>{ return <String, String>{
'PRODUCT_BUNDLE_IDENTIFIER': 'io.flutter.someProject', 'PRODUCT_BUNDLE_IDENTIFIER': productBundleIdentifier ?? 'io.flutter.someProject',
'DEVELOPMENT_TEAM': 'abc',
'TARGET_BUILD_DIR': 'build/ios/Release-iphoneos', 'TARGET_BUILD_DIR': 'build/ios/Release-iphoneos',
'WRAPPER_NAME': 'Runner.app', 'WRAPPER_NAME': 'Runner.app',
if (developmentTeam != null) 'DEVELOPMENT_TEAM': developmentTeam,
}; };
} }
/// The value of 'PRODUCT_BUNDLE_IDENTIFIER'.
final String productBundleIdentifier;
final String developmentTeam;
} }
final Platform macosPlatform = FakePlatform( final Platform macosPlatform = FakePlatform(
@ -117,6 +127,7 @@ void main() {
bool simulator = false, bool simulator = false,
String deviceId, String deviceId,
int exitCode = 0, int exitCode = 0,
String stdout,
void Function() onRun, void Function() onRun,
}) { }) {
return FakeCommand( return FakeCommand(
@ -159,6 +170,7 @@ void main() {
stdout: ''' stdout: '''
TARGET_BUILD_DIR=build/ios/Release-iphoneos TARGET_BUILD_DIR=build/ios/Release-iphoneos
WRAPPER_NAME=Runner.app WRAPPER_NAME=Runner.app
$stdout
''', ''',
exitCode: exitCode, exitCode: exitCode,
onRun: onRun, onRun: onRun,
@ -439,7 +451,7 @@ void main() {
XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(), XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(),
}); });
testUsingContext('Extra error message for provision profile issue in xcresulb bundle.', () async { testUsingContext('Extra error message for provision profile issue in xcresult bundle.', () async {
final BuildCommand command = BuildCommand(); final BuildCommand command = BuildCommand();
_createMinimalMockProjectFiles(); _createMinimalMockProjectFiles();
@ -453,7 +465,7 @@ void main() {
expect(testLogger.errorText, contains('It appears that there was a problem signing your application prior to installation on the device.')); expect(testLogger.errorText, contains('It appears that there was a problem signing your application prior to installation on the device.'));
expect(testLogger.errorText, contains('Verify that the Bundle Identifier in your project is your signing id in Xcode')); expect(testLogger.errorText, contains('Verify that the Bundle Identifier in your project is your signing id in Xcode'));
expect(testLogger.errorText, contains('open ios/Runner.xcworkspace')); expect(testLogger.errorText, contains('open ios/Runner.xcworkspace'));
expect(testLogger.errorText, contains("Also try selecting 'Product > Build' to fix the problem:")); expect(testLogger.errorText, contains("Also try selecting 'Product > Build' to fix the problem."));
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
FileSystem: () => fileSystem, FileSystem: () => fileSystem,
ProcessManager: () => FakeProcessManager.list(<FakeCommand>[ ProcessManager: () => FakeProcessManager.list(<FakeCommand>[
@ -467,6 +479,241 @@ void main() {
Platform: () => macosPlatform, Platform: () => macosPlatform,
XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(), XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(),
}); });
testUsingContext('Display xcresult issues with default bundle identifier.', () async {
final BuildCommand command = BuildCommand();
_createMinimalMockProjectFiles();
await expectLater(
createTestCommandRunner(command).run(const <String>['build', 'ios', '--no-pub']),
throwsToolExit(),
);
expect(testLogger.errorText, contains("Use of undeclared identifier 'asdas'"));
expect(testLogger.errorText, contains('/Users/m/Projects/test_create/ios/Runner/AppDelegate.m:7:56'));
expect(testLogger.errorText, contains('It appears that your application still contains the default signing identifier.'));
}, overrides: <Type, Generator>{
FileSystem: () => fileSystem,
ProcessManager: () => FakeProcessManager.list(<FakeCommand>[
xattrCommand,
_setUpFakeXcodeBuildHandler(exitCode: 1, onRun: () {
fileSystem.systemTempDirectory.childDirectory(_xcBundleFilePath).createSync();
}),
_setUpXCResultCommand(stdout: kSampleResultJsonWithIssues),
_setUpRsyncCommand(),
]),
Platform: () => macosPlatform,
EnvironmentType: () => EnvironmentType.physical,
XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(productBundleIdentifier: 'com.example'),
});
testUsingContext('Display xcresult issues with no provisioning profile.', () async {
final BuildCommand command = BuildCommand();
_createMinimalMockProjectFiles();
await expectLater(
createTestCommandRunner(command).run(const <String>['build', 'ios', '--no-pub']),
throwsToolExit(),
);
expect(testLogger.errorText, contains('Runner requires a provisioning profile. Select a provisioning profile in the Signing & Capabilities editor'));
expect(testLogger.errorText, contains(noProvisioningProfileInstruction));
}, overrides: <Type, Generator>{
FileSystem: () => fileSystem,
ProcessManager: () => FakeProcessManager.list(<FakeCommand>[
xattrCommand,
_setUpFakeXcodeBuildHandler(
exitCode: 1,
onRun: () {
fileSystem.systemTempDirectory.childDirectory(_xcBundleFilePath).createSync();
}
),
_setUpXCResultCommand(stdout: kSampleResultJsonWithNoProvisioningProfileIssue),
_setUpRsyncCommand(),
]),
Platform: () => macosPlatform,
XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(),
});
testUsingContext('Failed to parse xcresult but display missing provisioning profile issue from stdout.', () async {
final BuildCommand command = BuildCommand();
_createMinimalMockProjectFiles();
await expectLater(
createTestCommandRunner(command).run(const <String>['build', 'ios', '--no-pub']),
throwsToolExit(),
);
expect(testLogger.errorText, contains(noProvisioningProfileInstruction));
}, overrides: <Type, Generator>{
FileSystem: () => fileSystem,
ProcessManager: () => FakeProcessManager.list(<FakeCommand>[
xattrCommand,
_setUpFakeXcodeBuildHandler(
exitCode: 1,
stdout: '''
Runner requires a provisioning profile. Select a provisioning profile in the Signing & Capabilities editor
''',
onRun: () {
fileSystem.systemTempDirectory.childDirectory(_xcBundleFilePath).createSync();
}
),
_setUpXCResultCommand(stdout: kSampleResultJsonInvalidIssuesMap),
_setUpRsyncCommand(),
]),
Platform: () => macosPlatform,
XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(),
});
testUsingContext('Failed to parse xcresult but detected no development team issue.', () async {
final BuildCommand command = BuildCommand();
_createMinimalMockProjectFiles();
await expectLater(
createTestCommandRunner(command).run(const <String>['build', 'ios', '--no-pub']),
throwsToolExit(),
);
expect(testLogger.errorText, contains(noDevelopmentTeamInstruction));
}, overrides: <Type, Generator>{
FileSystem: () => fileSystem,
ProcessManager: () => FakeProcessManager.list(<FakeCommand>[
xattrCommand,
_setUpFakeXcodeBuildHandler(
exitCode: 1,
onRun: () {
fileSystem.systemTempDirectory.childDirectory(_xcBundleFilePath).createSync();
}
),
_setUpXCResultCommand(stdout: kSampleResultJsonInvalidIssuesMap),
_setUpRsyncCommand(),
]),
Platform: () => macosPlatform,
XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(developmentTeam: null),
});
testUsingContext('xcresult did not detect issue but detected by stdout.', () async {
final BuildCommand command = BuildCommand();
_createMinimalMockProjectFiles();
await expectLater(
createTestCommandRunner(command).run(const <String>['build', 'ios', '--no-pub']),
throwsToolExit(),
);
expect(testLogger.errorText, contains(noProvisioningProfileInstruction));
}, overrides: <Type, Generator>{
FileSystem: () => fileSystem,
ProcessManager: () => FakeProcessManager.list(<FakeCommand>[
xattrCommand,
_setUpFakeXcodeBuildHandler(
exitCode: 1,
stdout: '''
Runner requires a provisioning profile. Select a provisioning profile in the Signing & Capabilities editor
''',
onRun: () {
fileSystem.systemTempDirectory.childDirectory(_xcBundleFilePath).createSync();
}
),
_setUpXCResultCommand(stdout: kSampleResultJsonNoIssues),
_setUpRsyncCommand(),
]),
EnvironmentType: () => EnvironmentType.physical,
Platform: () => macosPlatform,
XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(),
});
testUsingContext('xcresult did not detect issue, no development team is detected from build setting.', () async {
final BuildCommand command = BuildCommand();
_createMinimalMockProjectFiles();
await expectLater(
createTestCommandRunner(command).run(const <String>['build', 'ios', '--no-pub']),
throwsToolExit(),
);
expect(testLogger.errorText, contains(noDevelopmentTeamInstruction));
}, overrides: <Type, Generator>{
FileSystem: () => fileSystem,
ProcessManager: () => FakeProcessManager.list(<FakeCommand>[
xattrCommand,
_setUpFakeXcodeBuildHandler(
exitCode: 1,
onRun: () {
fileSystem.systemTempDirectory.childDirectory(_xcBundleFilePath).createSync();
}
),
_setUpXCResultCommand(stdout: kSampleResultJsonInvalidIssuesMap),
_setUpRsyncCommand(),
]),
Platform: () => macosPlatform,
XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(developmentTeam: null),
});
testUsingContext('No development team issue error message is not displayed if no provisioning profile issue is detected from xcresult first.', () async {
final BuildCommand command = BuildCommand();
_createMinimalMockProjectFiles();
await expectLater(
createTestCommandRunner(command).run(const <String>['build', 'ios', '--no-pub']),
throwsToolExit(),
);
expect(testLogger.errorText, contains(noProvisioningProfileInstruction));
expect(testLogger.errorText, isNot(contains(noDevelopmentTeamInstruction)));
}, overrides: <Type, Generator>{
FileSystem: () => fileSystem,
ProcessManager: () => FakeProcessManager.list(<FakeCommand>[
xattrCommand,
_setUpFakeXcodeBuildHandler(
exitCode: 1,
onRun: () {
fileSystem.systemTempDirectory.childDirectory(_xcBundleFilePath).createSync();
}
),
_setUpXCResultCommand(stdout: kSampleResultJsonWithNoProvisioningProfileIssue),
_setUpRsyncCommand(),
]),
Platform: () => macosPlatform,
XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(developmentTeam: null),
});
testUsingContext('General provisioning profile issue error message is not displayed if no development team issue is detected first.', () async {
final BuildCommand command = BuildCommand();
_createMinimalMockProjectFiles();
await expectLater(
createTestCommandRunner(command).run(const <String>['build', 'ios', '--no-pub']),
throwsToolExit(),
);
expect(testLogger.errorText, contains(noDevelopmentTeamInstruction));
expect(testLogger.errorText, isNot(contains('It appears that there was a problem signing your application prior to installation on the device.')));
}, overrides: <Type, Generator>{
FileSystem: () => fileSystem,
ProcessManager: () => FakeProcessManager.list(<FakeCommand>[
xattrCommand,
_setUpFakeXcodeBuildHandler(
exitCode: 1,
onRun: () {
fileSystem.systemTempDirectory.childDirectory(_xcBundleFilePath).createSync();
}
),
_setUpXCResultCommand(stdout: kSampleResultJsonWithProvisionIssue),
_setUpRsyncCommand(),
]),
Platform: () => macosPlatform,
XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(developmentTeam: null),
});
}); });
group('xcresults simulator', () { group('xcresults simulator', () {

View File

@ -721,7 +721,7 @@ void main() {
expect(testLogger.errorText, contains('It appears that there was a problem signing your application prior to installation on the device.')); expect(testLogger.errorText, contains('It appears that there was a problem signing your application prior to installation on the device.'));
expect(testLogger.errorText, contains('Verify that the Bundle Identifier in your project is your signing id in Xcode')); expect(testLogger.errorText, contains('Verify that the Bundle Identifier in your project is your signing id in Xcode'));
expect(testLogger.errorText, contains('open ios/Runner.xcworkspace')); expect(testLogger.errorText, contains('open ios/Runner.xcworkspace'));
expect(testLogger.errorText, contains("Also try selecting 'Product > Build' to fix the problem:")); expect(testLogger.errorText, contains("Also try selecting 'Product > Build' to fix the problem."));
expect(fakeProcessManager, hasNoRemainingExpectations); expect(fakeProcessManager, hasNoRemainingExpectations);
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
FileSystem: () => fileSystem, FileSystem: () => fileSystem,

View File

@ -10,6 +10,7 @@ import 'package:flutter_tools/src/base/logger.dart';
import 'package:flutter_tools/src/base/process.dart'; import 'package:flutter_tools/src/base/process.dart';
import 'package:flutter_tools/src/build_info.dart'; import 'package:flutter_tools/src/build_info.dart';
import 'package:flutter_tools/src/cache.dart'; import 'package:flutter_tools/src/cache.dart';
import 'package:flutter_tools/src/ios/code_signing.dart';
import 'package:flutter_tools/src/ios/iproxy.dart'; import 'package:flutter_tools/src/ios/iproxy.dart';
import 'package:flutter_tools/src/ios/mac.dart'; import 'package:flutter_tools/src/ios/mac.dart';
import 'package:flutter_tools/src/project.dart'; import 'package:flutter_tools/src/project.dart';
@ -166,7 +167,11 @@ void main() {
)); ));
}); });
testWithoutContext('No provisioning profile shows message', () async { testWithoutContext('fallback to stdout: No provisioning profile shows message', () async {
final Map<String, String> buildSettingsWithDevTeam = <String, String>{
'PRODUCT_BUNDLE_IDENTIFIER': 'test.app',
'DEVELOPMENT_TEAM': 'a team',
};
final XcodeBuildResult buildResult = XcodeBuildResult( final XcodeBuildResult buildResult = XcodeBuildResult(
success: false, success: false,
stdout: ''' stdout: '''
@ -194,7 +199,7 @@ Xcode's output:
=== CLEAN TARGET Runner OF PROJECT Runner WITH CONFIGURATION Release === === CLEAN TARGET Runner OF PROJECT Runner WITH CONFIGURATION Release ===
Check dependencies Check dependencies
[BCEROR]No profiles for 'com.example.test' were found: Xcode couldn't find a provisioning profile matching 'com.example.test'. [BCEROR]"Runner" requires a provisioning profile. Select a provisioning profile in the Signing & Capabilities editor.
[BCEROR]Code signing is required for product type 'Application' in SDK 'iOS 10.3' [BCEROR]Code signing is required for product type 'Application' in SDK 'iOS 10.3'
[BCEROR]Code signing is required for product type 'Application' in SDK 'iOS 10.3' [BCEROR]Code signing is required for product type 'Application' in SDK 'iOS 10.3'
[BCEROR]Code signing is required for product type 'Application' in SDK 'iOS 10.3' [BCEROR]Code signing is required for product type 'Application' in SDK 'iOS 10.3'
@ -228,14 +233,14 @@ Error launching application on iPhone.''',
buildCommands: <String>['xcrun', 'xcodebuild', 'blah'], buildCommands: <String>['xcrun', 'xcodebuild', 'blah'],
appDirectory: '/blah/blah', appDirectory: '/blah/blah',
environmentType: EnvironmentType.physical, environmentType: EnvironmentType.physical,
buildSettings: buildSettings, buildSettings: buildSettingsWithDevTeam,
), ),
); );
await diagnoseXcodeBuildFailure(buildResult, testUsage, logger); await diagnoseXcodeBuildFailure(buildResult, testUsage, logger);
expect( expect(
logger.errorText, logger.errorText,
contains("No Provisioning Profile was found for your project's Bundle Identifier or your \ndevice."), contains(noProvisioningProfileInstruction),
); );
}); });
@ -319,80 +324,6 @@ Could not build the precompiled application for the device.''',
contains('Building a deployable iOS app requires a selected Development Team with a \nProvisioning Profile.'), contains('Building a deployable iOS app requires a selected Development Team with a \nProvisioning Profile.'),
); );
}); });
testWithoutContext('embedded and linked framework iOS mismatch shows message', () async {
final XcodeBuildResult buildResult = XcodeBuildResult(
success: false,
stdout: '''
Launching lib/main.dart on iPhone in debug mode...
Automatically signing iOS for device deployment using specified development team in Xcode project: blah
Xcode build done. 5.7s
Failed to build iOS app
Error output from Xcode build:
** BUILD FAILED **
Xcode's output:
note: Using new build system
note: Building targets in parallel
note: Planning build
note: Constructing build description
error: Building for iOS Simulator, but the linked and embedded framework 'App.framework' was built for iOS. (in target 'Runner' from project 'Runner')
Could not build the precompiled application for the device.
Error launching application on iPhone.
Exited (sigterm)''',
xcodeBuildExecution: XcodeBuildExecution(
buildCommands: <String>['xcrun', 'xcodebuild', 'blah'],
appDirectory: '/blah/blah',
environmentType: EnvironmentType.physical,
buildSettings: buildSettings,
),
);
await diagnoseXcodeBuildFailure(buildResult, testUsage, logger);
expect(
logger.errorText,
contains('Your Xcode project requires migration.'),
);
});
testWithoutContext('embedded and linked framework iOS simulator mismatch shows message', () async {
final XcodeBuildResult buildResult = XcodeBuildResult(
success: false,
stdout: '''
Launching lib/main.dart on iPhone in debug mode...
Automatically signing iOS for device deployment using specified development team in Xcode project: blah
Xcode build done. 5.7s
Failed to build iOS app
Error output from Xcode build:
** BUILD FAILED **
Xcode's output:
note: Using new build system
note: Building targets in parallel
note: Planning build
note: Constructing build description
error: Building for iOS, but the linked and embedded framework 'App.framework' was built for iOS Simulator. (in target 'Runner' from project 'Runner')
Could not build the precompiled application for the device.
Error launching application on iPhone.
Exited (sigterm)''',
xcodeBuildExecution: XcodeBuildExecution(
buildCommands: <String>['xcrun', 'xcodebuild', 'blah'],
appDirectory: '/blah/blah',
environmentType: EnvironmentType.physical,
buildSettings: buildSettings,
),
);
await diagnoseXcodeBuildFailure(buildResult, testUsage, logger);
expect(
logger.errorText,
contains('Your Xcode project requires migration.'),
);
});
}); });
group('Upgrades project.pbxproj for old asset usage', () { group('Upgrades project.pbxproj for old asset usage', () {

View File

@ -181,6 +181,82 @@ const String kSampleResultJsonWithIssues = r'''
} }
'''; ''';
/// An example xcresult bundle json that contains some warning and some errors.
const String kSampleResultJsonWithNoProvisioningProfileIssue = r'''
{
"issues" : {
"_type" : {
"_name" : "ResultIssueSummaries"
},
"errorSummaries" : {
"_type" : {
"_name" : "Array"
},
"_values" : [
{
"_type" : {
"_name" : "IssueSummary"
},
"documentLocationInCreatingWorkspace" : {
"_type" : {
"_name" : "DocumentLocation"
},
"concreteTypeName" : {
"_type" : {
"_name" : "String"
},
"_value" : "DVTTextDocumentLocation"
},
"url" : {
"_type" : {
"_name" : "String"
},
"_value" : "file:\/\/\/Users\/m\/Projects\/test_create\/ios\/Runner\/AppDelegate.m#CharacterRangeLen=0&CharacterRangeLoc=263&EndingColumnNumber=56&EndingLineNumber=7&LocationEncoding=1&StartingColumnNumber=56&StartingLineNumber=7"
}
},
"issueType" : {
"_type" : {
"_name" : "String"
},
"_value" : "Error"
},
"message" : {
"_type" : {
"_name" : "String"
},
"_value" : "Runner requires a provisioning profile. Select a provisioning profile in the Signing & Capabilities editor"
}
}
]
},
"warningSummaries" : {
"_type" : {
"_name" : "Array"
},
"_values" : [
{
"_type" : {
"_name" : "IssueSummary"
},
"issueType" : {
"_type" : {
"_name" : "String"
},
"_value" : "Warning"
},
"message" : {
"_type" : {
"_name" : "String"
},
"_value" : "The iOS deployment target 'IPHONEOS_DEPLOYMENT_TARGET' is set to 8.0, but the range of supported deployment target versions is 9.0 to 14.0.99."
}
}
]
}
}
}
''';
/// An example xcresult bundle json that contains some warning and some errors. /// An example xcresult bundle json that contains some warning and some errors.
const String kSampleResultJsonWithIssuesAndInvalidUrl = r''' const String kSampleResultJsonWithIssuesAndInvalidUrl = r'''
{ {