Use cached Xcode build settings during iOS build (#80904)
This commit is contained in:
parent
2d5ee03c04
commit
db3f49b1b4
@ -176,9 +176,15 @@ Future<XcodeBuildResult> buildXcodeProject({
|
|||||||
}
|
}
|
||||||
|
|
||||||
Map<String, String> autoSigningConfigs;
|
Map<String, String> autoSigningConfigs;
|
||||||
|
|
||||||
|
final Map<String, String> buildSettings = await app.project.buildSettingsForBuildInfo(
|
||||||
|
buildInfo,
|
||||||
|
environmentType: buildForDevice ? EnvironmentType.physical : EnvironmentType.simulator,
|
||||||
|
) ?? <String, String>{};
|
||||||
|
|
||||||
if (codesign && buildForDevice) {
|
if (codesign && buildForDevice) {
|
||||||
autoSigningConfigs = await getCodeSigningIdentityDevelopmentTeam(
|
autoSigningConfigs = await getCodeSigningIdentityDevelopmentTeam(
|
||||||
buildSettings: await app.project.buildSettingsForBuildInfo(buildInfo),
|
buildSettings: buildSettings,
|
||||||
processManager: globals.processManager,
|
processManager: globals.processManager,
|
||||||
logger: globals.logger,
|
logger: globals.logger,
|
||||||
config: globals.config,
|
config: globals.config,
|
||||||
@ -353,45 +359,6 @@ Future<XcodeBuildResult> buildXcodeProject({
|
|||||||
);
|
);
|
||||||
globals.flutterUsage.sendTiming(xcodeBuildActionToString(buildAction), 'xcode-ios', Duration(milliseconds: sw.elapsedMilliseconds));
|
globals.flutterUsage.sendTiming(xcodeBuildActionToString(buildAction), 'xcode-ios', Duration(milliseconds: sw.elapsedMilliseconds));
|
||||||
|
|
||||||
// Run -showBuildSettings again but with the exact same parameters as the
|
|
||||||
// build. showBuildSettings is reported to occasionally timeout. Here, we give
|
|
||||||
// it a lot of wiggle room (locally on Flutter Gallery, this takes ~1s).
|
|
||||||
// When there is a timeout, we retry once. See issue #35988.
|
|
||||||
final List<String> showBuildSettingsCommand = (List<String>
|
|
||||||
.of(buildCommands)
|
|
||||||
..add('-showBuildSettings'))
|
|
||||||
// Undocumented behavior: xcodebuild craps out if -showBuildSettings
|
|
||||||
// is used together with -allowProvisioningUpdates or
|
|
||||||
// -allowProvisioningDeviceRegistration and freezes forever.
|
|
||||||
.where((String buildCommand) {
|
|
||||||
return !const <String>[
|
|
||||||
'-allowProvisioningUpdates',
|
|
||||||
'-allowProvisioningDeviceRegistration',
|
|
||||||
].contains(buildCommand);
|
|
||||||
}).toList();
|
|
||||||
const Duration showBuildSettingsTimeout = Duration(minutes: 1);
|
|
||||||
Map<String, String> buildSettings;
|
|
||||||
try {
|
|
||||||
final RunResult showBuildSettingsResult = await globals.processUtils.run(
|
|
||||||
showBuildSettingsCommand,
|
|
||||||
throwOnError: true,
|
|
||||||
workingDirectory: app.project.hostAppRoot.path,
|
|
||||||
timeout: showBuildSettingsTimeout,
|
|
||||||
timeoutRetries: 1,
|
|
||||||
);
|
|
||||||
final String showBuildSettings = showBuildSettingsResult.stdout.trim();
|
|
||||||
buildSettings = parseXcodeBuildSettings(showBuildSettings);
|
|
||||||
} on ProcessException catch (e) {
|
|
||||||
if (e.toString().contains('timed out')) {
|
|
||||||
BuildEvent('xcode-show-build-settings-timeout',
|
|
||||||
type: 'ios',
|
|
||||||
command: showBuildSettingsCommand.join(' '),
|
|
||||||
flutterUsage: globals.flutterUsage,
|
|
||||||
).send();
|
|
||||||
}
|
|
||||||
rethrow;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (buildResult.exitCode != 0) {
|
if (buildResult.exitCode != 0) {
|
||||||
globals.printStatus('Failed to build iOS app');
|
globals.printStatus('Failed to build iOS app');
|
||||||
if (buildResult.stderr.isNotEmpty) {
|
if (buildResult.stderr.isNotEmpty) {
|
||||||
|
@ -166,10 +166,12 @@ class XcodeProjectInterpreter {
|
|||||||
/// target (by default this is Runner).
|
/// target (by default this is Runner).
|
||||||
Future<Map<String, String>> getBuildSettings(
|
Future<Map<String, String>> getBuildSettings(
|
||||||
String projectPath, {
|
String projectPath, {
|
||||||
String? scheme,
|
required XcodeProjectBuildContext buildContext,
|
||||||
Duration timeout = const Duration(minutes: 1),
|
Duration timeout = const Duration(minutes: 1),
|
||||||
}) async {
|
}) async {
|
||||||
final Status status = _logger.startSpinner();
|
final Status status = _logger.startSpinner();
|
||||||
|
final String? scheme = buildContext.scheme;
|
||||||
|
final String? configuration = buildContext.configuration;
|
||||||
final List<String> showBuildSettingsCommand = <String>[
|
final List<String> showBuildSettingsCommand = <String>[
|
||||||
...xcrunCommand(),
|
...xcrunCommand(),
|
||||||
'xcodebuild',
|
'xcodebuild',
|
||||||
@ -177,7 +179,12 @@ class XcodeProjectInterpreter {
|
|||||||
_fileSystem.path.absolute(projectPath),
|
_fileSystem.path.absolute(projectPath),
|
||||||
if (scheme != null)
|
if (scheme != null)
|
||||||
...<String>['-scheme', scheme],
|
...<String>['-scheme', scheme],
|
||||||
|
if (configuration != null)
|
||||||
|
...<String>['-configuration', configuration],
|
||||||
|
if (buildContext.environmentType == EnvironmentType.simulator)
|
||||||
|
...<String>['-sdk', 'iphonesimulator'],
|
||||||
'-showBuildSettings',
|
'-showBuildSettings',
|
||||||
|
'BUILD_DIR=${_fileSystem.path.absolute(getIosBuildDirectory())}',
|
||||||
...environmentVariablesAsXcodeBuildSettings(_platform)
|
...environmentVariablesAsXcodeBuildSettings(_platform)
|
||||||
];
|
];
|
||||||
try {
|
try {
|
||||||
@ -201,7 +208,7 @@ class XcodeProjectInterpreter {
|
|||||||
flutterUsage: _usage,
|
flutterUsage: _usage,
|
||||||
).send();
|
).send();
|
||||||
}
|
}
|
||||||
_logger.printTrace('Unexpected failure to get the build settings: $error.');
|
_logger.printTrace('Unexpected failure to get Xcode build settings: $error.');
|
||||||
return const <String, String>{};
|
return const <String, String>{};
|
||||||
} finally {
|
} finally {
|
||||||
status.stop();
|
status.stop();
|
||||||
@ -282,6 +289,29 @@ String substituteXcodeVariables(String str, Map<String, String> xcodeBuildSettin
|
|||||||
return str.replaceAllMapped(_varExpr, (Match m) => xcodeBuildSettings[m[1]!] ?? m[0]!);
|
return str.replaceAllMapped(_varExpr, (Match m) => xcodeBuildSettings[m[1]!] ?? m[0]!);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@immutable
|
||||||
|
class XcodeProjectBuildContext {
|
||||||
|
const XcodeProjectBuildContext({this.scheme, this.configuration, this.environmentType = EnvironmentType.physical});
|
||||||
|
|
||||||
|
final String? scheme;
|
||||||
|
final String? configuration;
|
||||||
|
final EnvironmentType environmentType;
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode => scheme.hashCode ^ configuration.hashCode ^ environmentType.hashCode;
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
if (identical(other, this)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return other is XcodeProjectBuildContext &&
|
||||||
|
other.scheme == scheme &&
|
||||||
|
other.configuration == configuration &&
|
||||||
|
other.environmentType == environmentType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Information about an Xcode project.
|
/// Information about an Xcode project.
|
||||||
///
|
///
|
||||||
/// Represents the output of `xcodebuild -list`.
|
/// Represents the output of `xcodebuild -list`.
|
||||||
@ -365,7 +395,7 @@ class XcodeProjectInfo {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void reportFlavorNotFoundAndExit() {
|
Never reportFlavorNotFoundAndExit() {
|
||||||
_logger.printError('');
|
_logger.printError('');
|
||||||
if (definesCustomSchemes) {
|
if (definesCustomSchemes) {
|
||||||
_logger.printError('The Xcode project defines schemes: ${schemes.join(', ')}');
|
_logger.printError('The Xcode project defines schemes: ${schemes.join(', ')}');
|
||||||
@ -377,7 +407,10 @@ class XcodeProjectInfo {
|
|||||||
|
|
||||||
/// Returns unique build configuration matching [buildInfo] and [scheme], or
|
/// Returns unique build configuration matching [buildInfo] and [scheme], or
|
||||||
/// null, if there is no unique best match.
|
/// null, if there is no unique best match.
|
||||||
String? buildConfigurationFor(BuildInfo buildInfo, String scheme) {
|
String? buildConfigurationFor(BuildInfo? buildInfo, String scheme) {
|
||||||
|
if (buildInfo == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
final String expectedConfiguration = expectedBuildConfigurationFor(buildInfo, scheme);
|
final String expectedConfiguration = expectedBuildConfigurationFor(buildInfo, scheme);
|
||||||
if (hasBuildConfigurationForBuildMode(expectedConfiguration)) {
|
if (hasBuildConfigurationForBuildMode(expectedConfiguration)) {
|
||||||
return expectedConfiguration;
|
return expectedConfiguration;
|
||||||
|
@ -248,6 +248,7 @@ class CocoaPods {
|
|||||||
} else {
|
} else {
|
||||||
final bool isSwift = (await _xcodeProjectInterpreter.getBuildSettings(
|
final bool isSwift = (await _xcodeProjectInterpreter.getBuildSettings(
|
||||||
runnerProject.path,
|
runnerProject.path,
|
||||||
|
buildContext: const XcodeProjectBuildContext(),
|
||||||
)).containsKey('SWIFT_VERSION');
|
)).containsKey('SWIFT_VERSION');
|
||||||
podfileTemplateName = isSwift ? 'Podfile-ios-swift' : 'Podfile-ios-objc';
|
podfileTemplateName = isSwift ? 'Podfile-ios-swift' : 'Podfile-ios-objc';
|
||||||
}
|
}
|
||||||
|
@ -593,11 +593,10 @@ class IosProject extends FlutterProjectPlatform implements XcodeBasedProject {
|
|||||||
/// The build settings for the host app of this project, as a detached map.
|
/// The build settings for the host app of this project, as a detached map.
|
||||||
///
|
///
|
||||||
/// Returns null, if iOS tooling is unavailable.
|
/// Returns null, if iOS tooling is unavailable.
|
||||||
Future<Map<String, String>> buildSettingsForBuildInfo(BuildInfo buildInfo) async {
|
Future<Map<String, String>> buildSettingsForBuildInfo(BuildInfo buildInfo, { EnvironmentType environmentType = EnvironmentType.physical }) async {
|
||||||
if (!existsSync()) {
|
if (!existsSync()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
_buildSettingsByScheme ??= <String, Map<String, String>>{};
|
|
||||||
final XcodeProjectInfo info = await projectInfo();
|
final XcodeProjectInfo info = await projectInfo();
|
||||||
if (info == null) {
|
if (info == null) {
|
||||||
return null;
|
return null;
|
||||||
@ -608,9 +607,15 @@ class IosProject extends FlutterProjectPlatform implements XcodeBasedProject {
|
|||||||
info.reportFlavorNotFoundAndExit();
|
info.reportFlavorNotFoundAndExit();
|
||||||
}
|
}
|
||||||
|
|
||||||
return _buildSettingsByScheme[scheme] ??= await _xcodeProjectBuildSettings(scheme);
|
final String configuration = (await projectInfo()).buildConfigurationFor(
|
||||||
|
buildInfo,
|
||||||
|
scheme,
|
||||||
|
);
|
||||||
|
final XcodeProjectBuildContext buildContext = XcodeProjectBuildContext(environmentType: environmentType, scheme: scheme, configuration: configuration);
|
||||||
|
return _buildSettingsByBuildContext[buildContext] ??= await _xcodeProjectBuildSettings(buildContext);
|
||||||
}
|
}
|
||||||
Map<String, Map<String, String>> _buildSettingsByScheme;
|
|
||||||
|
final Map<XcodeProjectBuildContext, Map<String, String>> _buildSettingsByBuildContext = <XcodeProjectBuildContext, Map<String, String>>{};
|
||||||
|
|
||||||
Future<XcodeProjectInfo> projectInfo() async {
|
Future<XcodeProjectInfo> projectInfo() async {
|
||||||
if (!xcodeProject.existsSync() || !globals.xcodeProjectInterpreter.isInstalled) {
|
if (!xcodeProject.existsSync() || !globals.xcodeProjectInterpreter.isInstalled) {
|
||||||
@ -620,13 +625,14 @@ class IosProject extends FlutterProjectPlatform implements XcodeBasedProject {
|
|||||||
}
|
}
|
||||||
XcodeProjectInfo _projectInfo;
|
XcodeProjectInfo _projectInfo;
|
||||||
|
|
||||||
Future<Map<String, String>> _xcodeProjectBuildSettings(String scheme) async {
|
Future<Map<String, String>> _xcodeProjectBuildSettings(XcodeProjectBuildContext buildContext) async {
|
||||||
if (!globals.xcodeProjectInterpreter.isInstalled) {
|
if (!globals.xcodeProjectInterpreter.isInstalled) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
final Map<String, String> buildSettings = await globals.xcodeProjectInterpreter.getBuildSettings(
|
final Map<String, String> buildSettings = await globals.xcodeProjectInterpreter.getBuildSettings(
|
||||||
xcodeProject.path,
|
xcodeProject.path,
|
||||||
scheme: scheme,
|
buildContext: buildContext,
|
||||||
);
|
);
|
||||||
if (buildSettings != null && buildSettings.isNotEmpty) {
|
if (buildSettings != null && buildSettings.isNotEmpty) {
|
||||||
// No timeouts, flakes, or errors.
|
// No timeouts, flakes, or errors.
|
||||||
|
@ -22,12 +22,14 @@ class FakeXcodeProjectInterpreterWithBuildSettings extends FakeXcodeProjectInter
|
|||||||
@override
|
@override
|
||||||
Future<Map<String, String>> getBuildSettings(
|
Future<Map<String, String>> getBuildSettings(
|
||||||
String projectPath, {
|
String projectPath, {
|
||||||
String scheme,
|
XcodeProjectBuildContext buildContext,
|
||||||
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': 'io.flutter.someProject',
|
||||||
'DEVELOPMENT_TEAM': 'abc',
|
'DEVELOPMENT_TEAM': 'abc',
|
||||||
|
'TARGET_BUILD_DIR': 'build/ios/Release-iphoneos',
|
||||||
|
'WRAPPER_NAME': 'Runner.app',
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -92,12 +94,16 @@ void main() {
|
|||||||
|
|
||||||
// Creates a FakeCommand for the xcodebuild call to build the app
|
// Creates a FakeCommand for the xcodebuild call to build the app
|
||||||
// in the given configuration.
|
// in the given configuration.
|
||||||
FakeCommand _setUpFakeXcodeBuildHandler({ bool verbose = false, bool showBuildSettings = false, void Function() onRun }) {
|
FakeCommand _setUpFakeXcodeBuildHandler({ bool verbose = false, bool simulator = false, void Function() onRun }) {
|
||||||
return FakeCommand(
|
return FakeCommand(
|
||||||
command: <String>[
|
command: <String>[
|
||||||
'xcrun',
|
'xcrun',
|
||||||
'xcodebuild',
|
'xcodebuild',
|
||||||
'-configuration', 'Release',
|
'-configuration',
|
||||||
|
if (simulator)
|
||||||
|
'Debug'
|
||||||
|
else
|
||||||
|
'Release',
|
||||||
if (verbose)
|
if (verbose)
|
||||||
'VERBOSE_SCRIPT_LOGGING=YES'
|
'VERBOSE_SCRIPT_LOGGING=YES'
|
||||||
else
|
else
|
||||||
@ -105,11 +111,13 @@ void main() {
|
|||||||
'-workspace', 'Runner.xcworkspace',
|
'-workspace', 'Runner.xcworkspace',
|
||||||
'-scheme', 'Runner',
|
'-scheme', 'Runner',
|
||||||
'BUILD_DIR=/build/ios',
|
'BUILD_DIR=/build/ios',
|
||||||
'-sdk', 'iphoneos',
|
'-sdk',
|
||||||
|
if (simulator)
|
||||||
|
'iphonesimulator'
|
||||||
|
else
|
||||||
|
'iphoneos',
|
||||||
'FLUTTER_SUPPRESS_ANALYTICS=true',
|
'FLUTTER_SUPPRESS_ANALYTICS=true',
|
||||||
'COMPILER_INDEX_STORE_ENABLE=NO',
|
'COMPILER_INDEX_STORE_ENABLE=NO',
|
||||||
if (showBuildSettings)
|
|
||||||
'-showBuildSettings',
|
|
||||||
],
|
],
|
||||||
stdout: '''
|
stdout: '''
|
||||||
TARGET_BUILD_DIR=build/ios/Release-iphoneos
|
TARGET_BUILD_DIR=build/ios/Release-iphoneos
|
||||||
@ -179,7 +187,26 @@ void main() {
|
|||||||
_setUpFakeXcodeBuildHandler(onRun: () {
|
_setUpFakeXcodeBuildHandler(onRun: () {
|
||||||
fileSystem.directory('build/ios/Release-iphoneos/Runner.app').createSync(recursive: true);
|
fileSystem.directory('build/ios/Release-iphoneos/Runner.app').createSync(recursive: true);
|
||||||
}),
|
}),
|
||||||
_setUpFakeXcodeBuildHandler(showBuildSettings: true),
|
_setUpRsyncCommand(),
|
||||||
|
]),
|
||||||
|
Platform: () => macosPlatform,
|
||||||
|
XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(),
|
||||||
|
});
|
||||||
|
|
||||||
|
testUsingContext('ios simulator build invokes xcode build', () async {
|
||||||
|
final BuildCommand command = BuildCommand();
|
||||||
|
_createMinimalMockProjectFiles();
|
||||||
|
|
||||||
|
await createTestCommandRunner(command).run(
|
||||||
|
const <String>['build', 'ios', '--simulator', '--no-pub']
|
||||||
|
);
|
||||||
|
}, overrides: <Type, Generator>{
|
||||||
|
FileSystem: () => fileSystem,
|
||||||
|
ProcessManager: () => FakeProcessManager.list(<FakeCommand>[
|
||||||
|
xattrCommand,
|
||||||
|
_setUpFakeXcodeBuildHandler(simulator: true, onRun: () {
|
||||||
|
fileSystem.directory('build/ios/Debug-iphonesimulator/Runner.app').createSync(recursive: true);
|
||||||
|
}),
|
||||||
_setUpRsyncCommand(),
|
_setUpRsyncCommand(),
|
||||||
]),
|
]),
|
||||||
Platform: () => macosPlatform,
|
Platform: () => macosPlatform,
|
||||||
@ -200,7 +227,6 @@ void main() {
|
|||||||
_setUpFakeXcodeBuildHandler(verbose: true, onRun: () {
|
_setUpFakeXcodeBuildHandler(verbose: true, onRun: () {
|
||||||
fileSystem.directory('build/ios/Release-iphoneos/Runner.app').createSync(recursive: true);
|
fileSystem.directory('build/ios/Release-iphoneos/Runner.app').createSync(recursive: true);
|
||||||
}),
|
}),
|
||||||
_setUpFakeXcodeBuildHandler(verbose: true, showBuildSettings: true),
|
|
||||||
_setUpRsyncCommand(),
|
_setUpRsyncCommand(),
|
||||||
]),
|
]),
|
||||||
Platform: () => macosPlatform,
|
Platform: () => macosPlatform,
|
||||||
@ -241,7 +267,6 @@ void main() {
|
|||||||
..createSync(recursive: true)
|
..createSync(recursive: true)
|
||||||
..writeAsStringSync('{}');
|
..writeAsStringSync('{}');
|
||||||
}),
|
}),
|
||||||
_setUpFakeXcodeBuildHandler(showBuildSettings: true),
|
|
||||||
_setUpRsyncCommand(onRun: () => fileSystem.file('build/ios/iphoneos/Runner.app/Frameworks/App.framework/App')
|
_setUpRsyncCommand(onRun: () => fileSystem.file('build/ios/iphoneos/Runner.app/Frameworks/App.framework/App')
|
||||||
..createSync(recursive: true)
|
..createSync(recursive: true)
|
||||||
..writeAsBytesSync(List<int>.generate(10000, (int index) => 0))),
|
..writeAsBytesSync(List<int>.generate(10000, (int index) => 0))),
|
||||||
|
@ -21,7 +21,7 @@ class FakeXcodeProjectInterpreterWithBuildSettings extends FakeXcodeProjectInter
|
|||||||
@override
|
@override
|
||||||
Future<Map<String, String>> getBuildSettings(
|
Future<Map<String, String>> getBuildSettings(
|
||||||
String projectPath, {
|
String projectPath, {
|
||||||
String scheme,
|
XcodeProjectBuildContext buildContext,
|
||||||
Duration timeout = const Duration(minutes: 1),
|
Duration timeout = const Duration(minutes: 1),
|
||||||
}) async {
|
}) async {
|
||||||
return <String, String>{
|
return <String, String>{
|
||||||
@ -81,7 +81,7 @@ void main() {
|
|||||||
|
|
||||||
// Creates a FakeCommand for the xcodebuild call to build the app
|
// Creates a FakeCommand for the xcodebuild call to build the app
|
||||||
// in the given configuration.
|
// in the given configuration.
|
||||||
FakeCommand setUpFakeXcodeBuildHandler({ bool verbose = false, bool showBuildSettings = false, void Function() onRun }) {
|
FakeCommand setUpFakeXcodeBuildHandler({ bool verbose = false, void Function() onRun }) {
|
||||||
return FakeCommand(
|
return FakeCommand(
|
||||||
command: <String>[
|
command: <String>[
|
||||||
'xcrun',
|
'xcrun',
|
||||||
@ -98,8 +98,6 @@ void main() {
|
|||||||
'COMPILER_INDEX_STORE_ENABLE=NO',
|
'COMPILER_INDEX_STORE_ENABLE=NO',
|
||||||
'-archivePath', '/build/ios/archive/Runner',
|
'-archivePath', '/build/ios/archive/Runner',
|
||||||
'archive',
|
'archive',
|
||||||
if (showBuildSettings)
|
|
||||||
'-showBuildSettings',
|
|
||||||
],
|
],
|
||||||
stdout: 'STDOUT STUFF',
|
stdout: 'STDOUT STUFF',
|
||||||
onRun: onRun,
|
onRun: onRun,
|
||||||
@ -224,7 +222,6 @@ void main() {
|
|||||||
ProcessManager: () => FakeProcessManager.list(<FakeCommand>[
|
ProcessManager: () => FakeProcessManager.list(<FakeCommand>[
|
||||||
xattrCommand,
|
xattrCommand,
|
||||||
setUpFakeXcodeBuildHandler(),
|
setUpFakeXcodeBuildHandler(),
|
||||||
setUpFakeXcodeBuildHandler(showBuildSettings: true),
|
|
||||||
]),
|
]),
|
||||||
Platform: () => macosPlatform,
|
Platform: () => macosPlatform,
|
||||||
XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(),
|
XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(),
|
||||||
@ -242,7 +239,6 @@ void main() {
|
|||||||
ProcessManager: () => FakeProcessManager.list(<FakeCommand>[
|
ProcessManager: () => FakeProcessManager.list(<FakeCommand>[
|
||||||
xattrCommand,
|
xattrCommand,
|
||||||
setUpFakeXcodeBuildHandler(verbose: true),
|
setUpFakeXcodeBuildHandler(verbose: true),
|
||||||
setUpFakeXcodeBuildHandler(verbose: true, showBuildSettings: true),
|
|
||||||
]),
|
]),
|
||||||
Platform: () => macosPlatform,
|
Platform: () => macosPlatform,
|
||||||
XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(),
|
XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(),
|
||||||
@ -303,7 +299,6 @@ void main() {
|
|||||||
..createSync(recursive: true)
|
..createSync(recursive: true)
|
||||||
..writeAsStringSync('{}');
|
..writeAsStringSync('{}');
|
||||||
}),
|
}),
|
||||||
setUpFakeXcodeBuildHandler(showBuildSettings: true),
|
|
||||||
]),
|
]),
|
||||||
Platform: () => macosPlatform,
|
Platform: () => macosPlatform,
|
||||||
FileSystemUtils: () => FileSystemUtils(fileSystem: fileSystem, platform: macosPlatform),
|
FileSystemUtils: () => FileSystemUtils(fileSystem: fileSystem, platform: macosPlatform),
|
||||||
@ -335,7 +330,6 @@ void main() {
|
|||||||
ProcessManager: () => FakeProcessManager.list(<FakeCommand>[
|
ProcessManager: () => FakeProcessManager.list(<FakeCommand>[
|
||||||
xattrCommand,
|
xattrCommand,
|
||||||
setUpFakeXcodeBuildHandler(),
|
setUpFakeXcodeBuildHandler(),
|
||||||
setUpFakeXcodeBuildHandler(showBuildSettings: true),
|
|
||||||
exportArchiveCommand,
|
exportArchiveCommand,
|
||||||
]),
|
]),
|
||||||
Platform: () => macosPlatform,
|
Platform: () => macosPlatform,
|
||||||
|
@ -105,6 +105,13 @@ void main() {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
when(mockXcodeProjectInterpreter.getBuildSettings(any, buildContext: anyNamed('buildContext')))
|
||||||
|
.thenAnswer((_) async => <String, String>{
|
||||||
|
'TARGET_BUILD_DIR': 'build/ios/Release-iphoneos',
|
||||||
|
'WRAPPER_NAME': 'My Super Awesome App.app',
|
||||||
|
'DEVELOPMENT_TEAM': '3333CCCC33',
|
||||||
|
});
|
||||||
|
|
||||||
xcode = Xcode.test(processManager: FakeProcessManager.any(), xcodeProjectInterpreter: mockXcodeProjectInterpreter);
|
xcode = Xcode.test(processManager: FakeProcessManager.any(), xcodeProjectInterpreter: mockXcodeProjectInterpreter);
|
||||||
fileSystem.file('foo/.packages')
|
fileSystem.file('foo/.packages')
|
||||||
..createSync(recursive: true)
|
..createSync(recursive: true)
|
||||||
@ -125,11 +132,6 @@ void main() {
|
|||||||
|
|
||||||
processManager.addCommand(FakeCommand(command: _xattrArgs(flutterProject)));
|
processManager.addCommand(FakeCommand(command: _xattrArgs(flutterProject)));
|
||||||
processManager.addCommand(const FakeCommand(command: kRunReleaseArgs));
|
processManager.addCommand(const FakeCommand(command: kRunReleaseArgs));
|
||||||
processManager.addCommand(const FakeCommand(command: <String>[...kRunReleaseArgs, '-showBuildSettings'], stdout: r'''
|
|
||||||
TARGET_BUILD_DIR=build/ios/Release-iphoneos
|
|
||||||
WRAPPER_NAME=My Super Awesome App.app
|
|
||||||
'''
|
|
||||||
));
|
|
||||||
processManager.addCommand(const FakeCommand(command: <String>[
|
processManager.addCommand(const FakeCommand(command: <String>[
|
||||||
'rsync',
|
'rsync',
|
||||||
'-av',
|
'-av',
|
||||||
@ -174,95 +176,6 @@ void main() {
|
|||||||
Xcode: () => xcode,
|
Xcode: () => xcode,
|
||||||
});
|
});
|
||||||
|
|
||||||
testUsingContext('with flaky buildSettings call', () async {
|
|
||||||
LaunchResult launchResult;
|
|
||||||
FakeAsync().run((FakeAsync time) {
|
|
||||||
final IOSDevice iosDevice = setUpIOSDevice(
|
|
||||||
fileSystem: fileSystem,
|
|
||||||
processManager: processManager,
|
|
||||||
logger: logger,
|
|
||||||
artifacts: artifacts,
|
|
||||||
);
|
|
||||||
setUpIOSProject(fileSystem);
|
|
||||||
final FlutterProject flutterProject = FlutterProject.fromDirectory(fileSystem.currentDirectory);
|
|
||||||
final BuildableIOSApp buildableIOSApp = BuildableIOSApp(flutterProject.ios, 'flutter', 'My Super Awesome App.app');
|
|
||||||
fileSystem.directory('build/ios/Release-iphoneos/My Super Awesome App.app').createSync(recursive: true);
|
|
||||||
|
|
||||||
processManager.addCommand(FakeCommand(command: _xattrArgs(flutterProject)));
|
|
||||||
processManager.addCommand(const FakeCommand(command: kRunReleaseArgs));
|
|
||||||
// The first showBuildSettings call should timeout.
|
|
||||||
processManager.addCommand(
|
|
||||||
const FakeCommand(
|
|
||||||
command: <String>[...kRunReleaseArgs, '-showBuildSettings'],
|
|
||||||
duration: Duration(minutes: 5), // this is longer than the timeout of 1 minute.
|
|
||||||
));
|
|
||||||
// The second call succeeds and is made after the first times out.
|
|
||||||
processManager.addCommand(
|
|
||||||
const FakeCommand(
|
|
||||||
command: <String>[...kRunReleaseArgs, '-showBuildSettings'],
|
|
||||||
exitCode: 0,
|
|
||||||
stdout: r'''
|
|
||||||
TARGET_BUILD_DIR=build/ios/Release-iphoneos
|
|
||||||
WRAPPER_NAME=My Super Awesome App.app
|
|
||||||
'''
|
|
||||||
));
|
|
||||||
processManager.addCommand(const FakeCommand(command: <String>[
|
|
||||||
'rsync',
|
|
||||||
'-av',
|
|
||||||
'--delete',
|
|
||||||
'build/ios/Release-iphoneos/My Super Awesome App.app',
|
|
||||||
'build/ios/iphoneos',
|
|
||||||
]));
|
|
||||||
processManager.addCommand(FakeCommand(
|
|
||||||
command: <String>[
|
|
||||||
iosDeployPath,
|
|
||||||
'--id',
|
|
||||||
'123',
|
|
||||||
'--bundle',
|
|
||||||
'build/ios/iphoneos/My Super Awesome App.app',
|
|
||||||
'--app_deltas',
|
|
||||||
'build/ios/app-delta',
|
|
||||||
'--no-wifi',
|
|
||||||
'--justlaunch',
|
|
||||||
'--args',
|
|
||||||
const <String>[
|
|
||||||
'--enable-dart-profiling',
|
|
||||||
'--disable-service-auth-codes',
|
|
||||||
].join(' ')
|
|
||||||
])
|
|
||||||
);
|
|
||||||
|
|
||||||
iosDevice.startApp(
|
|
||||||
buildableIOSApp,
|
|
||||||
debuggingOptions: DebuggingOptions.disabled(BuildInfo.release),
|
|
||||||
platformArgs: <String, Object>{},
|
|
||||||
).then((LaunchResult result) {
|
|
||||||
launchResult = result;
|
|
||||||
});
|
|
||||||
|
|
||||||
// Elapse duration for process timeout.
|
|
||||||
time.flushMicrotasks();
|
|
||||||
time.elapse(const Duration(minutes: 1));
|
|
||||||
|
|
||||||
// Elapse duration for overall process timer.
|
|
||||||
time.flushMicrotasks();
|
|
||||||
time.elapse(const Duration(minutes: 5));
|
|
||||||
|
|
||||||
time.flushTimers();
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(launchResult?.started, true);
|
|
||||||
expect(fileSystem.directory('build/ios/iphoneos'), exists);
|
|
||||||
expect(processManager, hasNoRemainingExpectations);
|
|
||||||
}, overrides: <Type, Generator>{
|
|
||||||
ProcessManager: () => processManager,
|
|
||||||
FileSystem: () => fileSystem,
|
|
||||||
Logger: () => logger,
|
|
||||||
Platform: () => macPlatform,
|
|
||||||
XcodeProjectInterpreter: () => mockXcodeProjectInterpreter,
|
|
||||||
Xcode: () => xcode,
|
|
||||||
});
|
|
||||||
|
|
||||||
testUsingContext('with concurrent build failures', () async {
|
testUsingContext('with concurrent build failures', () async {
|
||||||
final IOSDevice iosDevice = setUpIOSDevice(
|
final IOSDevice iosDevice = setUpIOSDevice(
|
||||||
fileSystem: fileSystem,
|
fileSystem: fileSystem,
|
||||||
@ -284,11 +197,6 @@ void main() {
|
|||||||
stdout: kConcurrentBuildErrorMessage,
|
stdout: kConcurrentBuildErrorMessage,
|
||||||
));
|
));
|
||||||
processManager.addCommand(const FakeCommand(command: kRunReleaseArgs));
|
processManager.addCommand(const FakeCommand(command: kRunReleaseArgs));
|
||||||
processManager.addCommand(
|
|
||||||
const FakeCommand(
|
|
||||||
command: <String>[...kRunReleaseArgs, '-showBuildSettings'],
|
|
||||||
exitCode: 0,
|
|
||||||
));
|
|
||||||
processManager.addCommand(FakeCommand(
|
processManager.addCommand(FakeCommand(
|
||||||
command: <String>[
|
command: <String>[
|
||||||
iosDeployPath,
|
iosDeployPath,
|
||||||
|
@ -46,7 +46,7 @@ void main() {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
testWithoutContext('xcodebuild build settings flakes', () async {
|
testUsingContext('xcodebuild build settings flakes', () async {
|
||||||
const Duration delay = Duration(seconds: 1);
|
const Duration delay = Duration(seconds: 1);
|
||||||
processManager.processFactory = mocks.flakyProcessFactory(
|
processManager.processFactory = mocks.flakyProcessFactory(
|
||||||
flakes: 1,
|
flakes: 1,
|
||||||
@ -59,8 +59,7 @@ void main() {
|
|||||||
when(processManager.runSync(<String>['sysctl', 'hw.optional.arm64']))
|
when(processManager.runSync(<String>['sysctl', 'hw.optional.arm64']))
|
||||||
.thenReturn(ProcessResult(0, 1, '', ''));
|
.thenReturn(ProcessResult(0, 1, '', ''));
|
||||||
|
|
||||||
expect(await xcodeProjectInterpreter.getBuildSettings(
|
expect(await xcodeProjectInterpreter.getBuildSettings('', buildContext: const XcodeProjectBuildContext(scheme: 'Runner'), timeout: delay),
|
||||||
'', scheme: 'Runner', timeout: delay),
|
|
||||||
const <String, String>{});
|
const <String, String>{});
|
||||||
// build settings times out and is killed once, then succeeds.
|
// build settings times out and is killed once, then succeeds.
|
||||||
verify(processManager.killPid(any)).called(1);
|
verify(processManager.killPid(any)).called(1);
|
||||||
@ -292,12 +291,12 @@ void main() {
|
|||||||
expect(fakeProcessManager.hasRemainingExpectations, isFalse);
|
expect(fakeProcessManager.hasRemainingExpectations, isFalse);
|
||||||
});
|
});
|
||||||
|
|
||||||
testWithoutContext('xcodebuild build settings is empty when xcodebuild failed to get the build settings', () async {
|
testUsingContext('xcodebuild build settings is empty when xcodebuild failed to get the build settings', () async {
|
||||||
platform.environment = const <String, String>{};
|
platform.environment = const <String, String>{};
|
||||||
|
|
||||||
fakeProcessManager.addCommands(const <FakeCommand>[
|
fakeProcessManager.addCommands(<FakeCommand>[
|
||||||
kWhichSysctlCommand,
|
kWhichSysctlCommand,
|
||||||
FakeCommand(
|
const FakeCommand(
|
||||||
command: <String>[
|
command: <String>[
|
||||||
'sysctl',
|
'sysctl',
|
||||||
'hw.optional.arm64',
|
'hw.optional.arm64',
|
||||||
@ -312,20 +311,26 @@ void main() {
|
|||||||
'/',
|
'/',
|
||||||
'-scheme',
|
'-scheme',
|
||||||
'Free',
|
'Free',
|
||||||
'-showBuildSettings'
|
'-showBuildSettings',
|
||||||
|
'BUILD_DIR=${fileSystem.path.absolute('build', 'ios')}',
|
||||||
],
|
],
|
||||||
exitCode: 1,
|
exitCode: 1,
|
||||||
),
|
),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
expect(await xcodeProjectInterpreter.getBuildSettings('', scheme: 'Free'), const <String, String>{});
|
expect(
|
||||||
|
await xcodeProjectInterpreter.getBuildSettings('', buildContext: const XcodeProjectBuildContext(scheme: 'Free')),
|
||||||
|
const <String, String>{});
|
||||||
expect(fakeProcessManager.hasRemainingExpectations, isFalse);
|
expect(fakeProcessManager.hasRemainingExpectations, isFalse);
|
||||||
|
}, overrides: <Type, Generator>{
|
||||||
|
FileSystem: () => fileSystem,
|
||||||
|
ProcessManager: () => FakeProcessManager.any(),
|
||||||
});
|
});
|
||||||
|
|
||||||
testWithoutContext('build settings accepts an empty scheme', () async {
|
testUsingContext('build settings passes in the simulator SDK', () async {
|
||||||
platform.environment = const <String, String>{};
|
platform.environment = const <String, String>{};
|
||||||
|
|
||||||
fakeProcessManager.addCommands(const <FakeCommand>[
|
fakeProcessManager.addCommands(<FakeCommand>[
|
||||||
kWhichSysctlCommand,
|
kWhichSysctlCommand,
|
||||||
kARMCheckCommand,
|
kARMCheckCommand,
|
||||||
FakeCommand(
|
FakeCommand(
|
||||||
@ -334,17 +339,56 @@ void main() {
|
|||||||
'xcodebuild',
|
'xcodebuild',
|
||||||
'-project',
|
'-project',
|
||||||
'/',
|
'/',
|
||||||
'-showBuildSettings'
|
'-sdk',
|
||||||
|
'iphonesimulator',
|
||||||
|
'-showBuildSettings',
|
||||||
|
'BUILD_DIR=${fileSystem.path.absolute('build', 'ios')}',
|
||||||
],
|
],
|
||||||
exitCode: 1,
|
exitCode: 1,
|
||||||
),
|
),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
expect(await xcodeProjectInterpreter.getBuildSettings(''), const <String, String>{});
|
expect(
|
||||||
|
await xcodeProjectInterpreter.getBuildSettings(
|
||||||
|
'',
|
||||||
|
buildContext: const XcodeProjectBuildContext(environmentType: EnvironmentType.simulator),
|
||||||
|
),
|
||||||
|
const <String, String>{},
|
||||||
|
);
|
||||||
expect(fakeProcessManager.hasRemainingExpectations, isFalse);
|
expect(fakeProcessManager.hasRemainingExpectations, isFalse);
|
||||||
|
}, overrides: <Type, Generator>{
|
||||||
|
FileSystem: () => fileSystem,
|
||||||
|
ProcessManager: () => FakeProcessManager.any(),
|
||||||
});
|
});
|
||||||
|
|
||||||
testWithoutContext('xcodebuild build settings contains Flutter Xcode environment variables', () async {
|
testUsingContext('build settings accepts an empty scheme', () async {
|
||||||
|
platform.environment = const <String, String>{};
|
||||||
|
|
||||||
|
fakeProcessManager.addCommands(<FakeCommand>[
|
||||||
|
kWhichSysctlCommand,
|
||||||
|
kARMCheckCommand,
|
||||||
|
FakeCommand(
|
||||||
|
command: <String>[
|
||||||
|
'xcrun',
|
||||||
|
'xcodebuild',
|
||||||
|
'-project',
|
||||||
|
'/',
|
||||||
|
'-showBuildSettings',
|
||||||
|
'BUILD_DIR=${fileSystem.path.absolute('build', 'ios')}',
|
||||||
|
],
|
||||||
|
exitCode: 1,
|
||||||
|
),
|
||||||
|
]);
|
||||||
|
|
||||||
|
expect(await xcodeProjectInterpreter.getBuildSettings('', buildContext: const XcodeProjectBuildContext()),
|
||||||
|
const <String, String>{});
|
||||||
|
expect(fakeProcessManager.hasRemainingExpectations, isFalse);
|
||||||
|
}, overrides: <Type, Generator>{
|
||||||
|
FileSystem: () => fileSystem,
|
||||||
|
ProcessManager: () => FakeProcessManager.any(),
|
||||||
|
});
|
||||||
|
|
||||||
|
testUsingContext('xcodebuild build settings contains Flutter Xcode environment variables', () async {
|
||||||
platform.environment = const <String, String>{
|
platform.environment = const <String, String>{
|
||||||
'FLUTTER_XCODE_CODE_SIGN_STYLE': 'Manual',
|
'FLUTTER_XCODE_CODE_SIGN_STYLE': 'Manual',
|
||||||
'FLUTTER_XCODE_ARCHS': 'arm64'
|
'FLUTTER_XCODE_ARCHS': 'arm64'
|
||||||
@ -361,13 +405,19 @@ void main() {
|
|||||||
'-scheme',
|
'-scheme',
|
||||||
'Free',
|
'Free',
|
||||||
'-showBuildSettings',
|
'-showBuildSettings',
|
||||||
|
'BUILD_DIR=${fileSystem.path.absolute('build', 'ios')}',
|
||||||
'CODE_SIGN_STYLE=Manual',
|
'CODE_SIGN_STYLE=Manual',
|
||||||
'ARCHS=arm64'
|
'ARCHS=arm64'
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
]);
|
]);
|
||||||
expect(await xcodeProjectInterpreter.getBuildSettings('', scheme: 'Free'), const <String, String>{});
|
expect(
|
||||||
|
await xcodeProjectInterpreter.getBuildSettings('', buildContext: const XcodeProjectBuildContext(scheme: 'Free')),
|
||||||
|
const <String, String>{});
|
||||||
expect(fakeProcessManager.hasRemainingExpectations, isFalse);
|
expect(fakeProcessManager.hasRemainingExpectations, isFalse);
|
||||||
|
}, overrides: <Type, Generator>{
|
||||||
|
FileSystem: () => fileSystem,
|
||||||
|
ProcessManager: () => FakeProcessManager.any(),
|
||||||
});
|
});
|
||||||
|
|
||||||
testWithoutContext('xcodebuild clean contains Flutter Xcode environment variables', () async {
|
testWithoutContext('xcodebuild clean contains Flutter Xcode environment variables', () async {
|
||||||
|
@ -794,7 +794,7 @@ class FakeXcodeProjectInterpreter extends Fake implements XcodeProjectInterprete
|
|||||||
@override
|
@override
|
||||||
Future<Map<String, String>> getBuildSettings(
|
Future<Map<String, String>> getBuildSettings(
|
||||||
String projectPath, {
|
String projectPath, {
|
||||||
String scheme,
|
XcodeProjectBuildContext buildContext,
|
||||||
Duration timeout = const Duration(minutes: 1),
|
Duration timeout = const Duration(minutes: 1),
|
||||||
}) async => buildSettings;
|
}) async => buildSettings;
|
||||||
|
|
||||||
|
@ -397,7 +397,7 @@ apply plugin: 'kotlin-android'
|
|||||||
testWithMocks('from build settings, if no plist', () async {
|
testWithMocks('from build settings, if no plist', () async {
|
||||||
final FlutterProject project = await someProject();
|
final FlutterProject project = await someProject();
|
||||||
project.ios.xcodeProject.createSync();
|
project.ios.xcodeProject.createSync();
|
||||||
when(mockXcodeProjectInterpreter.getBuildSettings(any, scheme: anyNamed('scheme'))).thenAnswer(
|
when(mockXcodeProjectInterpreter.getBuildSettings(any, buildContext: anyNamed('buildContext'))).thenAnswer(
|
||||||
(_) {
|
(_) {
|
||||||
return Future<Map<String,String>>.value(<String, String>{
|
return Future<Map<String,String>>.value(<String, String>{
|
||||||
'PRODUCT_BUNDLE_IDENTIFIER': 'io.flutter.someProject',
|
'PRODUCT_BUNDLE_IDENTIFIER': 'io.flutter.someProject',
|
||||||
@ -428,7 +428,7 @@ apply plugin: 'kotlin-android'
|
|||||||
testWithMocks('from build settings and plist, if default variable', () async {
|
testWithMocks('from build settings and plist, if default variable', () async {
|
||||||
final FlutterProject project = await someProject();
|
final FlutterProject project = await someProject();
|
||||||
project.ios.xcodeProject.createSync();
|
project.ios.xcodeProject.createSync();
|
||||||
when(mockXcodeProjectInterpreter.getBuildSettings(any, scheme: anyNamed('scheme'))).thenAnswer(
|
when(mockXcodeProjectInterpreter.getBuildSettings(any, buildContext: anyNamed('buildContext'))).thenAnswer(
|
||||||
(_) {
|
(_) {
|
||||||
return Future<Map<String,String>>.value(<String, String>{
|
return Future<Map<String,String>>.value(<String, String>{
|
||||||
'PRODUCT_BUNDLE_IDENTIFIER': 'io.flutter.someProject',
|
'PRODUCT_BUNDLE_IDENTIFIER': 'io.flutter.someProject',
|
||||||
@ -447,7 +447,7 @@ apply plugin: 'kotlin-android'
|
|||||||
final FlutterProject project = await someProject();
|
final FlutterProject project = await someProject();
|
||||||
project.ios.xcodeProject.createSync();
|
project.ios.xcodeProject.createSync();
|
||||||
project.ios.defaultHostInfoPlist.createSync(recursive: true);
|
project.ios.defaultHostInfoPlist.createSync(recursive: true);
|
||||||
when(mockXcodeProjectInterpreter.getBuildSettings(any, scheme: anyNamed('scheme'))).thenAnswer(
|
when(mockXcodeProjectInterpreter.getBuildSettings(any, buildContext: anyNamed('buildContext'))).thenAnswer(
|
||||||
(_) {
|
(_) {
|
||||||
return Future<Map<String,String>>.value(<String, String>{
|
return Future<Map<String,String>>.value(<String, String>{
|
||||||
'PRODUCT_BUNDLE_IDENTIFIER': 'io.flutter.someProject',
|
'PRODUCT_BUNDLE_IDENTIFIER': 'io.flutter.someProject',
|
||||||
@ -478,7 +478,7 @@ apply plugin: 'kotlin-android'
|
|||||||
testWithMocks('handles case insensitive flavor', () async {
|
testWithMocks('handles case insensitive flavor', () async {
|
||||||
final FlutterProject project = await someProject();
|
final FlutterProject project = await someProject();
|
||||||
project.ios.xcodeProject.createSync();
|
project.ios.xcodeProject.createSync();
|
||||||
when(mockXcodeProjectInterpreter.getBuildSettings(any, scheme: anyNamed('scheme'))).thenAnswer(
|
when(mockXcodeProjectInterpreter.getBuildSettings(any, buildContext: anyNamed('buildContext'))).thenAnswer(
|
||||||
(_) {
|
(_) {
|
||||||
return Future<Map<String,String>>.value(<String, String>{
|
return Future<Map<String,String>>.value(<String, String>{
|
||||||
'PRODUCT_BUNDLE_IDENTIFIER': 'io.flutter.someProject',
|
'PRODUCT_BUNDLE_IDENTIFIER': 'io.flutter.someProject',
|
||||||
@ -550,7 +550,7 @@ apply plugin: 'kotlin-android'
|
|||||||
testUsingContext('app product name xcodebuild settings', () async {
|
testUsingContext('app product name xcodebuild settings', () async {
|
||||||
final FlutterProject project = await someProject();
|
final FlutterProject project = await someProject();
|
||||||
project.ios.xcodeProject.createSync();
|
project.ios.xcodeProject.createSync();
|
||||||
when(mockXcodeProjectInterpreter.getBuildSettings(any, scheme: anyNamed('scheme'))).thenAnswer((_) {
|
when(mockXcodeProjectInterpreter.getBuildSettings(any, buildContext: anyNamed('buildContext'))).thenAnswer((_) {
|
||||||
return Future<Map<String,String>>.value(<String, String>{
|
return Future<Map<String,String>>.value(<String, String>{
|
||||||
'FULL_PRODUCT_NAME': 'My App.app'
|
'FULL_PRODUCT_NAME': 'My App.app'
|
||||||
});
|
});
|
||||||
@ -667,7 +667,7 @@ apply plugin: 'kotlin-android'
|
|||||||
|
|
||||||
group('with bundle identifier', () {
|
group('with bundle identifier', () {
|
||||||
setUp(() {
|
setUp(() {
|
||||||
when(mockXcodeProjectInterpreter.getBuildSettings(any, scheme: anyNamed('scheme'))).thenAnswer(
|
when(mockXcodeProjectInterpreter.getBuildSettings(any, buildContext: anyNamed('buildContext'))).thenAnswer(
|
||||||
(_) {
|
(_) {
|
||||||
return Future<Map<String,String>>.value(<String, String>{
|
return Future<Map<String,String>>.value(<String, String>{
|
||||||
'PRODUCT_BUNDLE_IDENTIFIER': 'io.flutter.someProject',
|
'PRODUCT_BUNDLE_IDENTIFIER': 'io.flutter.someProject',
|
||||||
|
@ -307,7 +307,7 @@ class FakeXcodeProjectInterpreter implements XcodeProjectInterpreter {
|
|||||||
@override
|
@override
|
||||||
Future<Map<String, String>> getBuildSettings(
|
Future<Map<String, String>> getBuildSettings(
|
||||||
String projectPath, {
|
String projectPath, {
|
||||||
String scheme,
|
XcodeProjectBuildContext buildContext,
|
||||||
Duration timeout = const Duration(minutes: 1),
|
Duration timeout = const Duration(minutes: 1),
|
||||||
}) async {
|
}) async {
|
||||||
return <String, String>{};
|
return <String, String>{};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user