Unverified Commit 61e2e866 authored by Jenn Magder's avatar Jenn Magder Committed by GitHub

Add iOS build -destination flag (#90915)

parent 905ac63e
......@@ -184,7 +184,8 @@ Future<XcodeBuildResult> buildXcodeProject({
final Map<String, String> buildSettings = await app.project.buildSettingsForBuildInfo(
buildInfo,
environmentType: environmentType
environmentType: environmentType,
deviceId: deviceID,
) ?? <String, String>{};
if (codesign && environmentType == EnvironmentType.physical) {
......@@ -249,11 +250,12 @@ Future<XcodeBuildResult> buildXcodeProject({
final bool hasWatchCompanion = await app.project.containsWatchCompanion(
projectInfo.targets,
buildInfo,
deviceID,
);
if (hasWatchCompanion) {
// The -sdk argument has to be omitted if a watchOS companion app exists.
// Otherwise the build will fail as WatchKit dependencies cannot be build using the iOS SDK.
globals.printStatus('Watch companion app found. Adjusting build settings.');
globals.printStatus('Watch companion app found.');
if (environmentType == EnvironmentType.simulator && (deviceID == null || deviceID == '')) {
globals.printError('No simulator device ID has been set.');
globals.printError('A device ID is required to build an app with a watchOS companion app.');
......@@ -261,9 +263,6 @@ Future<XcodeBuildResult> buildXcodeProject({
globals.printError('and specify one using the -d, --device-id flag.');
return XcodeBuildResult(success: false);
}
if (environmentType == EnvironmentType.simulator) {
buildCommands.addAll(<String>['-destination', 'id=$deviceID']);
}
} else {
if (environmentType == EnvironmentType.physical) {
buildCommands.addAll(<String>['-sdk', 'iphoneos']);
......@@ -272,6 +271,15 @@ Future<XcodeBuildResult> buildXcodeProject({
}
}
buildCommands.add('-destination');
if (deviceID != null) {
buildCommands.add('id=$deviceID');
} else if (environmentType == EnvironmentType.physical) {
buildCommands.add('generic/platform=iOS');
} else {
buildCommands.add('generic/platform=iOS Simulator');
}
if (activeArch != null) {
final String activeArchName = getNameForDarwinArch(activeArch);
if (activeArchName != null) {
......
......@@ -173,6 +173,7 @@ class XcodeProjectInterpreter {
final Status status = _logger.startSpinner();
final String? scheme = buildContext.scheme;
final String? configuration = buildContext.configuration;
final String? deviceId = buildContext.deviceId;
final List<String> showBuildSettingsCommand = <String>[
...xcrunCommand(),
'xcodebuild',
......@@ -184,6 +185,13 @@ class XcodeProjectInterpreter {
...<String>['-configuration', configuration],
if (buildContext.environmentType == EnvironmentType.simulator)
...<String>['-sdk', 'iphonesimulator'],
'-destination',
if (deviceId != null)
'id=$deviceId'
else if (buildContext.environmentType == EnvironmentType.physical)
'generic/platform=iOS'
else
'generic/platform=iOS Simulator',
'-showBuildSettings',
'BUILD_DIR=${_fileSystem.path.absolute(getIosBuildDirectory())}',
...environmentVariablesAsXcodeBuildSettings(_platform)
......@@ -351,14 +359,20 @@ String substituteXcodeVariables(String str, Map<String, String> xcodeBuildSettin
@immutable
class XcodeProjectBuildContext {
const XcodeProjectBuildContext({this.scheme, this.configuration, this.environmentType = EnvironmentType.physical});
const XcodeProjectBuildContext({
this.scheme,
this.configuration,
this.environmentType = EnvironmentType.physical,
this.deviceId,
});
final String? scheme;
final String? configuration;
final EnvironmentType environmentType;
final String? deviceId;
@override
int get hashCode => Object.hash(scheme, configuration, environmentType);
int get hashCode => Object.hash(scheme, configuration, environmentType, deviceId);
@override
bool operator ==(Object other) {
......@@ -368,6 +382,7 @@ class XcodeProjectBuildContext {
return other is XcodeProjectBuildContext &&
other.scheme == scheme &&
other.configuration == configuration &&
other.deviceId == deviceId &&
other.environmentType == environmentType;
}
}
......
......@@ -244,7 +244,11 @@ class IosProject extends XcodeBasedProject {
/// The build settings for the host app of this project, as a detached map.
///
/// Returns null, if iOS tooling is unavailable.
Future<Map<String, String>?> buildSettingsForBuildInfo(BuildInfo? buildInfo, { EnvironmentType environmentType = EnvironmentType.physical }) async {
Future<Map<String, String>?> buildSettingsForBuildInfo(
BuildInfo? buildInfo, {
EnvironmentType environmentType = EnvironmentType.physical,
String? deviceId,
}) async {
if (!existsSync()) {
return null;
}
......@@ -262,7 +266,12 @@ class IosProject extends XcodeBasedProject {
buildInfo,
scheme,
);
final XcodeProjectBuildContext buildContext = XcodeProjectBuildContext(environmentType: environmentType, scheme: scheme, configuration: configuration);
final XcodeProjectBuildContext buildContext = XcodeProjectBuildContext(
environmentType: environmentType,
scheme: scheme,
configuration: configuration,
deviceId: deviceId,
);
final Map<String, String>? currentBuildSettings = _buildSettingsByBuildContext[buildContext];
if (currentBuildSettings == null) {
final Map<String, String>? calculatedBuildSettings = await _xcodeProjectBuildSettings(buildContext);
......@@ -310,7 +319,7 @@ class IosProject extends XcodeBasedProject {
}
/// Check if one the [targets] of the project is a watchOS companion app target.
Future<bool> containsWatchCompanion(List<String> targets, BuildInfo buildInfo) async {
Future<bool> containsWatchCompanion(List<String> targets, BuildInfo buildInfo, String? deviceId) async {
final String? bundleIdentifier = await productBundleIdentifier(buildInfo);
// A bundle identifier is required for a companion app.
if (bundleIdentifier == null) {
......@@ -330,7 +339,7 @@ class IosProject extends XcodeBasedProject {
// The key WKCompanionAppBundleIdentifier might contain an xcode variable
// that needs to be substituted before comparing it with bundle id
if (fromPlist != null && fromPlist.contains(r'$')) {
final Map<String, String>? allBuildSettings = await buildSettingsForBuildInfo(buildInfo);
final Map<String, String>? allBuildSettings = await buildSettingsForBuildInfo(buildInfo, deviceId: deviceId);
if (allBuildSettings != null) {
final String substitutedVariable = substituteXcodeVariables(fromPlist, allBuildSettings);
if (substitutedVariable == bundleIdentifier) {
......
......@@ -112,10 +112,15 @@ void main() {
'-scheme', 'Runner',
'BUILD_DIR=/build/ios',
'-sdk',
if (simulator)
'iphonesimulator'
else
if (simulator) ...<String>[
'iphonesimulator',
'-destination',
'generic/platform=iOS Simulator',
] else ...<String>[
'iphoneos',
'-destination',
'generic/platform=iOS',
],
'FLUTTER_SUPPRESS_ANALYTICS=true',
'COMPILER_INDEX_STORE_ENABLE=NO',
],
......
......@@ -96,6 +96,8 @@ void main() {
'-workspace', 'Runner.xcworkspace',
'-scheme', 'Runner',
'-sdk', 'iphoneos',
'-destination',
'generic/platform=iOS',
'FLUTTER_SUPPRESS_ANALYTICS=true',
'COMPILER_INDEX_STORE_ENABLE=NO',
'-archivePath', '/build/ios/archive/Runner',
......
......@@ -54,6 +54,8 @@ const List<String> kRunReleaseArgs = <String>[
'BUILD_DIR=/build/ios',
'-sdk',
'iphoneos',
'-destination',
'id=123',
'ONLY_ACTIVE_ARCH=YES',
'ARCHS=arm64',
'FLUTTER_SUPPRESS_ANALYTICS=true',
......
......@@ -278,6 +278,8 @@ void main() {
'/',
'-scheme',
'Free',
'-destination',
'id=123',
'-showBuildSettings',
'BUILD_DIR=${fileSystem.path.absolute('build', 'ios')}',
],
......@@ -286,7 +288,7 @@ void main() {
]);
expect(
await xcodeProjectInterpreter.getBuildSettings('', buildContext: const XcodeProjectBuildContext(scheme: 'Free')),
await xcodeProjectInterpreter.getBuildSettings('', buildContext: const XcodeProjectBuildContext(deviceId: '123', scheme: 'Free')),
const <String, String>{});
expect(fakeProcessManager, hasNoRemainingExpectations);
}, overrides: <Type, Generator>{
......@@ -308,6 +310,8 @@ void main() {
'/',
'-sdk',
'iphonesimulator',
'-destination',
'generic/platform=iOS Simulator',
'-showBuildSettings',
'BUILD_DIR=${fileSystem.path.absolute('build', 'ios')}',
],
......@@ -340,6 +344,8 @@ void main() {
'xcodebuild',
'-project',
'/',
'-destination',
'generic/platform=iOS',
'-showBuildSettings',
'BUILD_DIR=${fileSystem.path.absolute('build', 'ios')}',
],
......@@ -371,6 +377,8 @@ void main() {
fileSystem.path.separator,
'-scheme',
'Free',
'-destination',
'generic/platform=iOS',
'-showBuildSettings',
'BUILD_DIR=${fileSystem.path.absolute('build', 'ios')}',
'CODE_SIGN_STYLE=Manual',
......
......@@ -628,7 +628,7 @@ apply plugin: 'kotlin-android'
testUsingContext('cannot find bundle identifier', () async {
final FlutterProject project = await someProject();
expect(await project.ios.containsWatchCompanion(<String>['WatchTarget'], null), isFalse);
expect(await project.ios.containsWatchCompanion(<String>['WatchTarget'], null, '123'), isFalse);
}, overrides: <Type, Generator>{
FileSystem: () => fs,
ProcessManager: () => FakeProcessManager.any(),
......@@ -647,7 +647,7 @@ apply plugin: 'kotlin-android'
testUsingContext('no Info.plist in target', () async {
final FlutterProject project = await someProject();
expect(await project.ios.containsWatchCompanion(<String>['WatchTarget'], null), isFalse);
expect(await project.ios.containsWatchCompanion(<String>['WatchTarget'], null, '123'), isFalse);
}, overrides: <Type, Generator>{
FileSystem: () => fs,
ProcessManager: () => FakeProcessManager.any(),
......@@ -660,7 +660,7 @@ apply plugin: 'kotlin-android'
final FlutterProject project = await someProject();
project.ios.hostAppRoot.childDirectory('WatchTarget').childFile('Info.plist').createSync(recursive: true);
expect(await project.ios.containsWatchCompanion(<String>['WatchTarget'], null), isFalse);
expect(await project.ios.containsWatchCompanion(<String>['WatchTarget'], null, '123'), isFalse);
}, overrides: <Type, Generator>{
FileSystem: () => fs,
ProcessManager: () => FakeProcessManager.any(),
......@@ -674,7 +674,7 @@ apply plugin: 'kotlin-android'
project.ios.hostAppRoot.childDirectory('WatchTarget').childFile('Info.plist').createSync(recursive: true);
testPlistParser.setProperty('WKCompanionAppBundleIdentifier', 'io.flutter.someOTHERproject');
expect(await project.ios.containsWatchCompanion(<String>['WatchTarget'], null), isFalse);
expect(await project.ios.containsWatchCompanion(<String>['WatchTarget'], null, '123'), isFalse);
}, overrides: <Type, Generator>{
FileSystem: () => fs,
ProcessManager: () => FakeProcessManager.any(),
......@@ -689,7 +689,7 @@ apply plugin: 'kotlin-android'
project.ios.hostAppRoot.childDirectory('WatchTarget').childFile('Info.plist').createSync(recursive: true);
testPlistParser.setProperty('WKCompanionAppBundleIdentifier', 'io.flutter.someProject');
expect(await project.ios.containsWatchCompanion(<String>['WatchTarget'], null), isTrue);
expect(await project.ios.containsWatchCompanion(<String>['WatchTarget'], null, '123'), isTrue);
}, overrides: <Type, Generator>{
FileSystem: () => fs,
ProcessManager: () => FakeProcessManager.any(),
......@@ -707,7 +707,7 @@ apply plugin: 'kotlin-android'
project.ios.hostAppRoot.childDirectory('WatchTarget').childFile('Info.plist').createSync(recursive: true);
testPlistParser.setProperty('WKCompanionAppBundleIdentifier', r'$(PRODUCT_BUNDLE_IDENTIFIER)');
expect(await project.ios.containsWatchCompanion(<String>['WatchTarget'], null), isTrue);
expect(await project.ios.containsWatchCompanion(<String>['WatchTarget'], null, '123'), isTrue);
}, overrides: <Type, Generator>{
FileSystem: () => fs,
ProcessManager: () => FakeProcessManager.any(),
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment