mirror of
https://github.com/flutter/flutter
synced 2024-08-25 11:07:06 +00:00
Check for watch companion in build settings (#114078)
This commit is contained in:
parent
cece4a5d19
commit
8aad1190b7
|
@ -5,7 +5,6 @@
|
|||
import 'dart:io';
|
||||
|
||||
import 'package:flutter_devicelab/framework/framework.dart';
|
||||
import 'package:flutter_devicelab/framework/ios.dart';
|
||||
import 'package:flutter_devicelab/framework/task_result.dart';
|
||||
import 'package:flutter_devicelab/framework/utils.dart';
|
||||
import 'package:path/path.dart' as path;
|
||||
|
@ -28,54 +27,19 @@ Future<void> main() async {
|
|||
|
||||
section('Create release build');
|
||||
|
||||
// This only builds the iOS app, not the companion watchOS app. The watchOS app
|
||||
// has been removed as a build dependency and is not embedded in the app to avoid
|
||||
// requiring the watchOS being available in CI.
|
||||
// Instead, validate the tool detects that there is a watch companion, and omits
|
||||
// the "-sdk iphoneos" option, which fails to build the watchOS app.
|
||||
// This attempts to build the companion watchOS app. However, the watchOS
|
||||
// SDK is not available in CI and therefore the build will fail.
|
||||
// Check to make sure that the tool attempts to build the companion watchOS app.
|
||||
// See https://github.com/flutter/flutter/pull/94190.
|
||||
await inDirectory(projectDir, () async {
|
||||
final String buildOutput = await evalFlutter(
|
||||
'build',
|
||||
options: <String>['ios', '--no-codesign', '--release', '--verbose'],
|
||||
);
|
||||
if (!buildOutput.contains('Watch companion app found')) {
|
||||
throw TaskResult.failure('Did not detect watch companion');
|
||||
if (!buildOutput.contains('-destination generic/platform=watchOS')) {
|
||||
print(buildOutput);
|
||||
throw TaskResult.failure('Did not try to get watch build settings');
|
||||
}
|
||||
if (buildOutput.contains('-sdk iphoneos -destination')) {
|
||||
throw TaskResult.failure('-sdk must be omitted for app with watch companion');
|
||||
}
|
||||
});
|
||||
|
||||
final String appBundle = Directory(path.join(
|
||||
projectDir.path,
|
||||
'build',
|
||||
'ios',
|
||||
'iphoneos',
|
||||
'Runner.app',
|
||||
)).path;
|
||||
|
||||
final String appFrameworkPath = path.join(
|
||||
appBundle,
|
||||
'Frameworks',
|
||||
'App.framework',
|
||||
'App',
|
||||
);
|
||||
final String flutterFrameworkPath = path.join(
|
||||
appBundle,
|
||||
'Frameworks',
|
||||
'Flutter.framework',
|
||||
'Flutter',
|
||||
);
|
||||
|
||||
checkDirectoryExists(appBundle);
|
||||
await _checkFlutterFrameworkArchs(appFrameworkPath);
|
||||
await _checkFlutterFrameworkArchs(flutterFrameworkPath);
|
||||
|
||||
section('Clean build');
|
||||
|
||||
await inDirectory(projectDir, () async {
|
||||
await flutter('clean');
|
||||
});
|
||||
|
||||
return TaskResult.success(null);
|
||||
|
@ -86,16 +50,3 @@ Future<void> main() async {
|
|||
}
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> _checkFlutterFrameworkArchs(String frameworkPath) async {
|
||||
checkFileExists(frameworkPath);
|
||||
|
||||
final String archs = await fileType(frameworkPath);
|
||||
if (!archs.contains('arm64')) {
|
||||
throw TaskResult.failure('$frameworkPath arm64 architecture missing');
|
||||
}
|
||||
|
||||
if (archs.contains('x86_64')) {
|
||||
throw TaskResult.failure('$frameworkPath x86_64 architecture unexpectedly present');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -727,6 +727,7 @@
|
|||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
IBSC_MODULE = watch_Extension;
|
||||
INFOPLIST_FILE = watch/Info.plist;
|
||||
INFOPLIST_KEY_WKCompanionAppBundleIdentifier = io.flutter.extensionTest;
|
||||
MARKETING_VERSION = 1.0.0;
|
||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||
MTL_FAST_MATH = YES;
|
||||
|
@ -757,6 +758,7 @@
|
|||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
IBSC_MODULE = watch_Extension;
|
||||
INFOPLIST_FILE = watch/Info.plist;
|
||||
INFOPLIST_KEY_WKCompanionAppBundleIdentifier = io.flutter.extensionTest;
|
||||
MARKETING_VERSION = 1.0.0;
|
||||
MTL_FAST_MATH = YES;
|
||||
OTHER_LDFLAGS = "";
|
||||
|
@ -785,6 +787,7 @@
|
|||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
IBSC_MODULE = watch_Extension;
|
||||
INFOPLIST_FILE = watch/Info.plist;
|
||||
INFOPLIST_KEY_WKCompanionAppBundleIdentifier = io.flutter.extensionTest;
|
||||
MARKETING_VERSION = 1.0.0;
|
||||
MTL_FAST_MATH = YES;
|
||||
OTHER_LDFLAGS = "";
|
||||
|
|
|
@ -25,8 +25,6 @@
|
|||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
||||
</array>
|
||||
<key>WKCompanionAppBundleIdentifier</key>
|
||||
<string>$(APP_BUNDLE_IDENTIFIER)</string>
|
||||
<key>WKWatchKitApp</key>
|
||||
<true/>
|
||||
</dict>
|
||||
|
|
|
@ -265,9 +265,9 @@ Future<XcodeBuildResult> buildXcodeProject({
|
|||
|
||||
// Check if the project contains a watchOS companion app.
|
||||
final bool hasWatchCompanion = await app.project.containsWatchCompanion(
|
||||
projectInfo.targets,
|
||||
buildInfo,
|
||||
deviceID,
|
||||
projectInfo: projectInfo,
|
||||
buildInfo: buildInfo,
|
||||
deviceId: deviceID,
|
||||
);
|
||||
if (hasWatchCompanion) {
|
||||
// The -sdk argument has to be omitted if a watchOS companion app exists.
|
||||
|
|
|
@ -198,7 +198,11 @@ class XcodeProjectInterpreter {
|
|||
if (buildContext.environmentType == EnvironmentType.simulator)
|
||||
...<String>['-sdk', 'iphonesimulator'],
|
||||
'-destination',
|
||||
if (deviceId != null)
|
||||
if (buildContext.isWatch == true && buildContext.environmentType == EnvironmentType.physical)
|
||||
'generic/platform=watchOS'
|
||||
else if (buildContext.isWatch == true)
|
||||
'generic/platform=watchOS Simulator'
|
||||
else if (deviceId != null)
|
||||
'id=$deviceId'
|
||||
else if (buildContext.environmentType == EnvironmentType.physical)
|
||||
'generic/platform=iOS'
|
||||
|
@ -376,12 +380,14 @@ class XcodeProjectBuildContext {
|
|||
this.configuration,
|
||||
this.environmentType = EnvironmentType.physical,
|
||||
this.deviceId,
|
||||
this.isWatch = false,
|
||||
});
|
||||
|
||||
final String? scheme;
|
||||
final String? configuration;
|
||||
final EnvironmentType environmentType;
|
||||
final String? deviceId;
|
||||
final bool isWatch;
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(scheme, configuration, environmentType, deviceId);
|
||||
|
@ -395,7 +401,8 @@ class XcodeProjectBuildContext {
|
|||
other.scheme == scheme &&
|
||||
other.configuration == configuration &&
|
||||
other.deviceId == deviceId &&
|
||||
other.environmentType == environmentType;
|
||||
other.environmentType == environmentType &&
|
||||
other.isWatch == isWatch;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -256,6 +256,8 @@ class IosProject extends XcodeBasedProject {
|
|||
BuildInfo? buildInfo, {
|
||||
EnvironmentType environmentType = EnvironmentType.physical,
|
||||
String? deviceId,
|
||||
String? scheme,
|
||||
bool isWatch = false,
|
||||
}) async {
|
||||
if (!existsSync()) {
|
||||
return null;
|
||||
|
@ -265,9 +267,11 @@ class IosProject extends XcodeBasedProject {
|
|||
return null;
|
||||
}
|
||||
|
||||
final String? scheme = info.schemeFor(buildInfo);
|
||||
if (scheme == null) {
|
||||
info.reportFlavorNotFoundAndExit();
|
||||
scheme = info.schemeFor(buildInfo);
|
||||
if (scheme == null) {
|
||||
info.reportFlavorNotFoundAndExit();
|
||||
}
|
||||
}
|
||||
|
||||
final String? configuration = (await projectInfo())?.buildConfigurationFor(
|
||||
|
@ -279,6 +283,7 @@ class IosProject extends XcodeBasedProject {
|
|||
scheme: scheme,
|
||||
configuration: configuration,
|
||||
deviceId: deviceId,
|
||||
isWatch: isWatch,
|
||||
);
|
||||
final Map<String, String>? currentBuildSettings = _buildSettingsByBuildContext[buildContext];
|
||||
if (currentBuildSettings == null) {
|
||||
|
@ -327,17 +332,21 @@ 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, String? deviceId) async {
|
||||
Future<bool> containsWatchCompanion({
|
||||
required XcodeProjectInfo projectInfo,
|
||||
required BuildInfo buildInfo,
|
||||
String? deviceId,
|
||||
}) async {
|
||||
final String? bundleIdentifier = await productBundleIdentifier(buildInfo);
|
||||
// A bundle identifier is required for a companion app.
|
||||
if (bundleIdentifier == null) {
|
||||
return false;
|
||||
}
|
||||
for (final String target in targets) {
|
||||
for (final String target in projectInfo.targets) {
|
||||
// Create Info.plist file of the target.
|
||||
final File infoFile = hostAppRoot.childDirectory(target).childFile('Info.plist');
|
||||
// The Info.plist file of a target contains the key WKCompanionAppBundleIdentifier,
|
||||
// if it is a watchOS companion app.
|
||||
// In older versions of Xcode, if the target was a watchOS companion app,
|
||||
// the Info.plist file of the target contained the key WKCompanionAppBundleIdentifier.
|
||||
if (infoFile.existsSync()) {
|
||||
final String? fromPlist = globals.plistParser.getStringValueFromFile(infoFile.path, 'WKCompanionAppBundleIdentifier');
|
||||
if (bundleIdentifier == fromPlist) {
|
||||
|
@ -357,6 +366,43 @@ class IosProject extends XcodeBasedProject {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If key not found in Info.plist above, do more expensive check of build settings.
|
||||
// In newer versions of Xcode, the build settings of the watchOS companion
|
||||
// app's scheme should contain the key INFOPLIST_KEY_WKCompanionAppBundleIdentifier.
|
||||
final bool watchIdentifierFound = xcodeProjectInfoFile.readAsStringSync().contains('WKCompanionAppBundleIdentifier');
|
||||
if (watchIdentifierFound == false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final String? defaultScheme = projectInfo.schemeFor(buildInfo);
|
||||
if (defaultScheme == null) {
|
||||
projectInfo.reportFlavorNotFoundAndExit();
|
||||
}
|
||||
for (final String scheme in projectInfo.schemes) {
|
||||
// the default scheme should not be a watch scheme, so skip it
|
||||
if (scheme == defaultScheme) {
|
||||
continue;
|
||||
}
|
||||
final Map<String, String>? allBuildSettings = await buildSettingsForBuildInfo(
|
||||
buildInfo,
|
||||
deviceId: deviceId,
|
||||
scheme: scheme,
|
||||
isWatch: true,
|
||||
);
|
||||
if (allBuildSettings != null) {
|
||||
final String? fromBuild = allBuildSettings['INFOPLIST_KEY_WKCompanionAppBundleIdentifier'];
|
||||
if (bundleIdentifier == fromBuild) {
|
||||
return true;
|
||||
}
|
||||
if (fromBuild != null && fromBuild.contains(r'$')) {
|
||||
final String substitutedVariable = substituteXcodeVariables(fromBuild, allBuildSettings);
|
||||
if (substitutedVariable == bundleIdentifier) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -395,6 +395,76 @@ void main() {
|
|||
ProcessManager: () => FakeProcessManager.any(),
|
||||
});
|
||||
|
||||
testUsingContext('build settings uses watch destination if isWatch is true', () async {
|
||||
platform.environment = const <String, String>{};
|
||||
|
||||
fakeProcessManager.addCommands(<FakeCommand>[
|
||||
kWhichSysctlCommand,
|
||||
kx64CheckCommand,
|
||||
FakeCommand(
|
||||
command: <String>[
|
||||
'xcrun',
|
||||
'xcodebuild',
|
||||
'-project',
|
||||
'/',
|
||||
'-destination',
|
||||
'generic/platform=watchOS',
|
||||
'-showBuildSettings',
|
||||
'BUILD_DIR=${fileSystem.path.absolute('build', 'ios')}',
|
||||
],
|
||||
exitCode: 1,
|
||||
),
|
||||
]);
|
||||
|
||||
expect(
|
||||
await xcodeProjectInterpreter.getBuildSettings(
|
||||
'',
|
||||
buildContext: const XcodeProjectBuildContext(isWatch: true),
|
||||
),
|
||||
const <String, String>{},
|
||||
);
|
||||
expect(fakeProcessManager, hasNoRemainingExpectations);
|
||||
}, overrides: <Type, Generator>{
|
||||
FileSystem: () => fileSystem,
|
||||
ProcessManager: () => FakeProcessManager.any(),
|
||||
});
|
||||
|
||||
testUsingContext('build settings uses watch simulator destination if isWatch is true and environment type is simulator', () async {
|
||||
platform.environment = const <String, String>{};
|
||||
|
||||
fakeProcessManager.addCommands(<FakeCommand>[
|
||||
kWhichSysctlCommand,
|
||||
kx64CheckCommand,
|
||||
FakeCommand(
|
||||
command: <String>[
|
||||
'xcrun',
|
||||
'xcodebuild',
|
||||
'-project',
|
||||
'/',
|
||||
'-sdk',
|
||||
'iphonesimulator',
|
||||
'-destination',
|
||||
'generic/platform=watchOS Simulator',
|
||||
'-showBuildSettings',
|
||||
'BUILD_DIR=${fileSystem.path.absolute('build', 'ios')}',
|
||||
],
|
||||
exitCode: 1,
|
||||
),
|
||||
]);
|
||||
|
||||
expect(
|
||||
await xcodeProjectInterpreter.getBuildSettings(
|
||||
'',
|
||||
buildContext: const XcodeProjectBuildContext(environmentType: EnvironmentType.simulator, isWatch: true),
|
||||
),
|
||||
const <String, String>{},
|
||||
);
|
||||
expect(fakeProcessManager, hasNoRemainingExpectations);
|
||||
}, overrides: <Type, Generator>{
|
||||
FileSystem: () => fileSystem,
|
||||
ProcessManager: () => FakeProcessManager.any(),
|
||||
});
|
||||
|
||||
testWithoutContext('xcodebuild clean contains Flutter Xcode environment variables', () async {
|
||||
platform.environment = const <String, String>{
|
||||
'FLUTTER_XCODE_CODE_SIGN_STYLE': 'Manual',
|
||||
|
|
|
@ -458,7 +458,8 @@ apply plugin: 'kotlin-android'
|
|||
testWithMocks('from build settings, if no plist', () async {
|
||||
final FlutterProject project = await someProject();
|
||||
project.ios.xcodeProject.createSync();
|
||||
xcodeProjectInterpreter.buildSettings = <String, String>{
|
||||
const XcodeProjectBuildContext buildContext = XcodeProjectBuildContext(scheme: 'Runner');
|
||||
xcodeProjectInterpreter.buildSettingsByBuildContext[buildContext] = <String, String>{
|
||||
'PRODUCT_BUNDLE_IDENTIFIER': 'io.flutter.someProject',
|
||||
};
|
||||
xcodeProjectInterpreter.xcodeProjectInfo = XcodeProjectInfo(<String>[], <String>[], <String>['Runner'], logger);
|
||||
|
@ -486,7 +487,8 @@ apply plugin: 'kotlin-android'
|
|||
testWithMocks('from build settings and plist, if default variable', () async {
|
||||
final FlutterProject project = await someProject();
|
||||
project.ios.xcodeProject.createSync();
|
||||
xcodeProjectInterpreter.buildSettings = <String, String>{
|
||||
const XcodeProjectBuildContext buildContext = XcodeProjectBuildContext(scheme: 'Runner');
|
||||
xcodeProjectInterpreter.buildSettingsByBuildContext[buildContext] = <String, String>{
|
||||
'PRODUCT_BUNDLE_IDENTIFIER': 'io.flutter.someProject',
|
||||
};
|
||||
xcodeProjectInterpreter.xcodeProjectInfo = XcodeProjectInfo(<String>[], <String>[], <String>['Runner'], logger);
|
||||
|
@ -499,7 +501,8 @@ apply plugin: 'kotlin-android'
|
|||
final FlutterProject project = await someProject();
|
||||
project.ios.xcodeProject.createSync();
|
||||
project.ios.defaultHostInfoPlist.createSync(recursive: true);
|
||||
xcodeProjectInterpreter.buildSettings = <String, String>{
|
||||
const XcodeProjectBuildContext buildContext = XcodeProjectBuildContext(scheme: 'Runner');
|
||||
xcodeProjectInterpreter.buildSettingsByBuildContext[buildContext] = <String, String>{
|
||||
'PRODUCT_BUNDLE_IDENTIFIER': 'io.flutter.someProject',
|
||||
'SUFFIX': 'suffix',
|
||||
};
|
||||
|
@ -534,7 +537,8 @@ apply plugin: 'kotlin-android'
|
|||
testWithMocks('handles case insensitive flavor', () async {
|
||||
final FlutterProject project = await someProject();
|
||||
project.ios.xcodeProject.createSync();
|
||||
xcodeProjectInterpreter.buildSettings = <String, String>{
|
||||
const XcodeProjectBuildContext buildContext = XcodeProjectBuildContext(scheme: 'Free');
|
||||
xcodeProjectInterpreter.buildSettingsByBuildContext[buildContext] = <String, String>{
|
||||
'PRODUCT_BUNDLE_IDENTIFIER': 'io.flutter.someProject',
|
||||
};
|
||||
xcodeProjectInterpreter.xcodeProjectInfo =XcodeProjectInfo(<String>[], <String>[], <String>['Free'], logger);
|
||||
|
@ -603,7 +607,8 @@ apply plugin: 'kotlin-android'
|
|||
testUsingContext('app product name xcodebuild settings', () async {
|
||||
final FlutterProject project = await someProject();
|
||||
project.ios.xcodeProject.createSync();
|
||||
mockXcodeProjectInterpreter.buildSettings = <String, String>{
|
||||
const XcodeProjectBuildContext buildContext = XcodeProjectBuildContext(scheme: 'Runner');
|
||||
mockXcodeProjectInterpreter.buildSettingsByBuildContext[buildContext] = <String, String>{
|
||||
'FULL_PRODUCT_NAME': 'My App.app',
|
||||
};
|
||||
mockXcodeProjectInterpreter.xcodeProjectInfo = XcodeProjectInfo(<String>[], <String>[], <String>['Runner'], logger);
|
||||
|
@ -705,7 +710,15 @@ apply plugin: 'kotlin-android'
|
|||
|
||||
testUsingContext('cannot find bundle identifier', () async {
|
||||
final FlutterProject project = await someProject();
|
||||
expect(await project.ios.containsWatchCompanion(<String>['WatchTarget'], BuildInfo.debug, '123'), isFalse);
|
||||
final XcodeProjectInfo projectInfo = XcodeProjectInfo(<String>['WatchTarget'], <String>[], <String>[], logger);
|
||||
expect(
|
||||
await project.ios.containsWatchCompanion(
|
||||
projectInfo: projectInfo,
|
||||
buildInfo: BuildInfo.debug,
|
||||
deviceId: '123',
|
||||
),
|
||||
isFalse,
|
||||
);
|
||||
}, overrides: <Type, Generator>{
|
||||
FileSystem: () => fs,
|
||||
ProcessManager: () => FakeProcessManager.any(),
|
||||
|
@ -716,15 +729,23 @@ apply plugin: 'kotlin-android'
|
|||
|
||||
group('with bundle identifier', () {
|
||||
setUp(() {
|
||||
mockXcodeProjectInterpreter.buildSettings = <String, String>{
|
||||
const XcodeProjectBuildContext buildContext = XcodeProjectBuildContext(scheme: 'Runner');
|
||||
mockXcodeProjectInterpreter.buildSettingsByBuildContext[buildContext] = <String, String>{
|
||||
'PRODUCT_BUNDLE_IDENTIFIER': 'io.flutter.someProject',
|
||||
};
|
||||
mockXcodeProjectInterpreter.xcodeProjectInfo = XcodeProjectInfo(<String>[], <String>[], <String>['Runner'], logger);
|
||||
mockXcodeProjectInterpreter.xcodeProjectInfo = XcodeProjectInfo(<String>['Runner', 'WatchTarget'], <String>[], <String>['Runner', 'WatchScheme'], logger);
|
||||
});
|
||||
|
||||
testUsingContext('no Info.plist in target', () async {
|
||||
final FlutterProject project = await someProject();
|
||||
expect(await project.ios.containsWatchCompanion(<String>['WatchTarget'], BuildInfo.debug, '123'), isFalse);
|
||||
expect(
|
||||
await project.ios.containsWatchCompanion(
|
||||
projectInfo: mockXcodeProjectInterpreter.xcodeProjectInfo,
|
||||
buildInfo: BuildInfo.debug,
|
||||
deviceId: '123',
|
||||
),
|
||||
isFalse,
|
||||
);
|
||||
}, overrides: <Type, Generator>{
|
||||
FileSystem: () => fs,
|
||||
ProcessManager: () => FakeProcessManager.any(),
|
||||
|
@ -737,7 +758,14 @@ 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'], BuildInfo.debug, '123'), isFalse);
|
||||
expect(
|
||||
await project.ios.containsWatchCompanion(
|
||||
projectInfo: mockXcodeProjectInterpreter.xcodeProjectInfo,
|
||||
buildInfo: BuildInfo.debug,
|
||||
deviceId: '123',
|
||||
),
|
||||
isFalse,
|
||||
);
|
||||
}, overrides: <Type, Generator>{
|
||||
FileSystem: () => fs,
|
||||
ProcessManager: () => FakeProcessManager.any(),
|
||||
|
@ -751,7 +779,14 @@ 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'], BuildInfo.debug, '123'), isFalse);
|
||||
expect(
|
||||
await project.ios.containsWatchCompanion(
|
||||
projectInfo: mockXcodeProjectInterpreter.xcodeProjectInfo,
|
||||
buildInfo: BuildInfo.debug,
|
||||
deviceId: '123',
|
||||
),
|
||||
isFalse,
|
||||
);
|
||||
}, overrides: <Type, Generator>{
|
||||
FileSystem: () => fs,
|
||||
ProcessManager: () => FakeProcessManager.any(),
|
||||
|
@ -760,13 +795,20 @@ apply plugin: 'kotlin-android'
|
|||
FlutterProjectFactory: () => flutterProjectFactory,
|
||||
});
|
||||
|
||||
testUsingContext('has watch companion', () async {
|
||||
testUsingContext('has watch companion in plist', () async {
|
||||
final FlutterProject project = await someProject();
|
||||
project.ios.xcodeProject.createSync();
|
||||
project.ios.hostAppRoot.childDirectory('WatchTarget').childFile('Info.plist').createSync(recursive: true);
|
||||
testPlistParser.setProperty('WKCompanionAppBundleIdentifier', 'io.flutter.someProject');
|
||||
|
||||
expect(await project.ios.containsWatchCompanion(<String>['WatchTarget'], BuildInfo.debug, '123'), isTrue);
|
||||
expect(
|
||||
await project.ios.containsWatchCompanion(
|
||||
projectInfo: mockXcodeProjectInterpreter.xcodeProjectInfo,
|
||||
buildInfo: BuildInfo.debug,
|
||||
deviceId: '123',
|
||||
),
|
||||
isTrue,
|
||||
);
|
||||
}, overrides: <Type, Generator>{
|
||||
FileSystem: () => fs,
|
||||
ProcessManager: () => FakeProcessManager.any(),
|
||||
|
@ -775,16 +817,109 @@ apply plugin: 'kotlin-android'
|
|||
FlutterProjectFactory: () => flutterProjectFactory,
|
||||
});
|
||||
|
||||
testUsingContext('has watch companion with build settings', () async {
|
||||
testUsingContext('has watch companion in plist with xcode variable', () async {
|
||||
final FlutterProject project = await someProject();
|
||||
project.ios.xcodeProject.createSync();
|
||||
mockXcodeProjectInterpreter.buildSettings = <String, String>{
|
||||
const XcodeProjectBuildContext buildContext = XcodeProjectBuildContext(
|
||||
scheme: 'Runner',
|
||||
deviceId: '123',
|
||||
);
|
||||
mockXcodeProjectInterpreter.buildSettingsByBuildContext[buildContext] = <String, String>{
|
||||
'PRODUCT_BUNDLE_IDENTIFIER': 'io.flutter.someProject',
|
||||
};
|
||||
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'], BuildInfo.debug, '123'), isTrue);
|
||||
expect(
|
||||
await project.ios.containsWatchCompanion(
|
||||
projectInfo: mockXcodeProjectInterpreter.xcodeProjectInfo,
|
||||
buildInfo: BuildInfo.debug,
|
||||
deviceId: '123',
|
||||
),
|
||||
isTrue,
|
||||
);
|
||||
}, overrides: <Type, Generator>{
|
||||
FileSystem: () => fs,
|
||||
ProcessManager: () => FakeProcessManager.any(),
|
||||
PlistParser: () => testPlistParser,
|
||||
XcodeProjectInterpreter: () => mockXcodeProjectInterpreter,
|
||||
FlutterProjectFactory: () => flutterProjectFactory,
|
||||
});
|
||||
|
||||
testUsingContext('has watch companion in other scheme build settings', () async {
|
||||
final FlutterProject project = await someProject();
|
||||
project.ios.xcodeProject.createSync();
|
||||
project.ios.xcodeProjectInfoFile.writeAsStringSync('''
|
||||
Build settings for action build and target "WatchTarget":
|
||||
INFOPLIST_KEY_WKCompanionAppBundleIdentifier = io.flutter.someProject
|
||||
''');
|
||||
|
||||
const XcodeProjectBuildContext buildContext = XcodeProjectBuildContext(
|
||||
scheme: 'Runner',
|
||||
deviceId: '123',
|
||||
);
|
||||
mockXcodeProjectInterpreter.buildSettingsByBuildContext[buildContext] = <String, String>{
|
||||
'PRODUCT_BUNDLE_IDENTIFIER': 'io.flutter.someProject',
|
||||
};
|
||||
|
||||
const XcodeProjectBuildContext watchBuildContext = XcodeProjectBuildContext(
|
||||
scheme: 'WatchScheme',
|
||||
deviceId: '123',
|
||||
isWatch: true,
|
||||
);
|
||||
mockXcodeProjectInterpreter.buildSettingsByBuildContext[watchBuildContext] = <String, String>{
|
||||
'INFOPLIST_KEY_WKCompanionAppBundleIdentifier': 'io.flutter.someProject',
|
||||
};
|
||||
|
||||
expect(
|
||||
await project.ios.containsWatchCompanion(
|
||||
projectInfo: mockXcodeProjectInterpreter.xcodeProjectInfo,
|
||||
buildInfo: BuildInfo.debug,
|
||||
deviceId: '123',
|
||||
),
|
||||
isTrue,
|
||||
);
|
||||
}, overrides: <Type, Generator>{
|
||||
FileSystem: () => fs,
|
||||
ProcessManager: () => FakeProcessManager.any(),
|
||||
PlistParser: () => testPlistParser,
|
||||
XcodeProjectInterpreter: () => mockXcodeProjectInterpreter,
|
||||
FlutterProjectFactory: () => flutterProjectFactory,
|
||||
});
|
||||
|
||||
testUsingContext('has watch companion in other scheme build settings with xcode variable', () async {
|
||||
final FlutterProject project = await someProject();
|
||||
project.ios.xcodeProject.createSync();
|
||||
project.ios.xcodeProjectInfoFile.writeAsStringSync(r'''
|
||||
Build settings for action build and target "WatchTarget":
|
||||
INFOPLIST_KEY_WKCompanionAppBundleIdentifier = $(PRODUCT_BUNDLE_IDENTIFIER)
|
||||
''');
|
||||
const XcodeProjectBuildContext buildContext = XcodeProjectBuildContext(
|
||||
scheme: 'Runner',
|
||||
deviceId: '123'
|
||||
);
|
||||
mockXcodeProjectInterpreter.buildSettingsByBuildContext[buildContext] = <String, String>{
|
||||
'PRODUCT_BUNDLE_IDENTIFIER': 'io.flutter.someProject',
|
||||
};
|
||||
|
||||
const XcodeProjectBuildContext watchBuildContext = XcodeProjectBuildContext(
|
||||
scheme: 'WatchScheme',
|
||||
deviceId: '123',
|
||||
isWatch: true,
|
||||
);
|
||||
mockXcodeProjectInterpreter.buildSettingsByBuildContext[watchBuildContext] = <String, String>{
|
||||
'PRODUCT_BUNDLE_IDENTIFIER': 'io.flutter.someProject',
|
||||
'INFOPLIST_KEY_WKCompanionAppBundleIdentifier': r'$(PRODUCT_BUNDLE_IDENTIFIER)',
|
||||
};
|
||||
|
||||
expect(
|
||||
await project.ios.containsWatchCompanion(
|
||||
projectInfo: mockXcodeProjectInterpreter.xcodeProjectInfo,
|
||||
buildInfo: BuildInfo.debug,
|
||||
deviceId: '123',
|
||||
),
|
||||
isTrue,
|
||||
);
|
||||
}, overrides: <Type, Generator>{
|
||||
FileSystem: () => fs,
|
||||
ProcessManager: () => FakeProcessManager.any(),
|
||||
|
@ -1075,7 +1210,7 @@ File androidPluginRegistrant(Directory parent) {
|
|||
}
|
||||
|
||||
class FakeXcodeProjectInterpreter extends Fake implements XcodeProjectInterpreter {
|
||||
Map<String, String> buildSettings = <String, String>{};
|
||||
final Map<XcodeProjectBuildContext, Map<String, String>> buildSettingsByBuildContext = <XcodeProjectBuildContext, Map<String, String>>{};
|
||||
late XcodeProjectInfo xcodeProjectInfo;
|
||||
|
||||
@override
|
||||
|
@ -1083,7 +1218,10 @@ class FakeXcodeProjectInterpreter extends Fake implements XcodeProjectInterprete
|
|||
XcodeProjectBuildContext? buildContext,
|
||||
Duration timeout = const Duration(minutes: 1),
|
||||
}) async {
|
||||
return buildSettings;
|
||||
if (buildSettingsByBuildContext[buildContext] == null) {
|
||||
return <String, String>{};
|
||||
}
|
||||
return buildSettingsByBuildContext[buildContext]!;
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
Loading…
Reference in a new issue