resolveSigningBundleIds static method
Future<Set<String> >
resolveSigningBundleIds(
- String appRoot, {
- required String mainBundleId,
- String? flavor,
- ProcessRunner processRunner = const SystemProcessRunner(),
- bool? isMacOS,
Resolves every signed app or extension bundle ID in the Release scheme.
Implementation
static Future<Set<String>> resolveSigningBundleIds(
String appRoot, {
required String mainBundleId,
String? flavor,
ProcessRunner processRunner = const SystemProcessRunner(),
bool? isMacOS,
}) async {
if (!(isMacOS ?? Platform.isMacOS)) {
throw const SmfError(
'Apple signing-target discovery requires a macOS runner.',
SmfErrorCode.macosRequired,
);
}
SmfError.check(
_isExplicitBundleId(mainBundleId),
'The configured iOS bundle identifier is not an explicit bundle ID: '
'$mainBundleId.',
SmfErrorCode.bundleIdInvalid,
);
final projectRoot = p.normalize(p.absolute(appRoot));
final iosDirectory = p.join(projectRoot, 'ios');
final container = await _xcodeContainer(iosDirectory);
final scheme = flavor ?? 'Runner';
final arguments = <String>[
container.option,
container.path,
'-scheme',
scheme,
'-configuration',
'Release',
'-sdk',
'iphoneos',
'-showBuildSettings',
'-json',
];
final result = await processRunner.run(
'xcodebuild',
arguments,
options: RunOptions(workingDirectory: projectRoot),
);
Object? decoded;
try {
decoded = jsonDecode(result.stdout);
} on FormatException catch (error) {
throw SmfError(
'Xcode returned malformed signing-target build settings.',
SmfErrorCode.xcodeBuildSettingsInvalid,
cause: error,
);
}
if (decoded is! List<Object?>) {
throw const SmfError(
'Xcode signing-target build settings are not a list.',
SmfErrorCode.xcodeBuildSettingsInvalid,
);
}
final bundleIds = <String>{};
final appBundleIds = <String>{};
for (final item in decoded) {
if (item is! Map<Object?, Object?>) continue;
final settingsValue = item['buildSettings'];
if (settingsValue is! Map<Object?, Object?>) continue;
final wrapperExtension = settingsValue['WRAPPER_EXTENSION'];
final signingAllowed = settingsValue['CODE_SIGNING_ALLOWED'];
final signingRequired = settingsValue['CODE_SIGNING_REQUIRED'];
if ((wrapperExtension != 'app' && wrapperExtension != 'appex') ||
signingAllowed == 'NO' ||
signingRequired == 'NO') {
continue;
}
final bundleId = settingsValue['PRODUCT_BUNDLE_IDENTIFIER'];
final targetValue = item['target'];
final target = targetValue is String ? targetValue : 'unknown target';
if (bundleId is! String || !_isExplicitBundleId(bundleId.trim())) {
throw SmfError(
'Xcode target "$target" does not resolve to an explicit Release '
'bundle identifier.',
SmfErrorCode.xcodeBundleIdInvalid,
);
}
final resolved = bundleId.trim();
bundleIds.add(resolved);
if (wrapperExtension == 'app') appBundleIds.add(resolved);
}
SmfError.check(
appBundleIds.contains(mainBundleId),
appBundleIds.isEmpty
? 'Xcode did not report a signed application target for the Release '
'scheme.'
: 'The configured iOS bundle ID $mainBundleId does not match a signed '
'application target in Xcode: ${appBundleIds.toList()..sort()}.',
SmfErrorCode.bundleIdMismatch,
);
return bundleIds;
}