mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00
Log XCResult before other build issues (#100787)
This commit is contained in:
parent
74cdc42207
commit
1755819cb1
@ -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';
|
||||||
|
@ -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', () {
|
||||||
|
@ -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,
|
||||||
|
@ -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', () {
|
||||||
|
@ -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'''
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user