checkAppStoreTree function
Loads the App Store metadata tree at path and reports what it refuses.
The loading is the check: loadMetadata validates text limits, URL
schemes, category ids, screenshot dimensions and — the one that fires most
often in practice — the alpha channel every simulator screen capture
carries. Anything it throws becomes a problem here rather than an exception,
so a caller sees it alongside whatever else is wrong.
requireScreenshotTypes covers the case the loader cannot know about on its
own: a universal app declaring TARGETED_DEVICE_FAMILY = "1,2" must carry an
iPad set as well as an iPhone one, and Apple refuses the submission if it
does not. Which types are required is a property of the app, so the consumer
names them.
Implementation
List<ReleaseProblem> checkAppStoreTree(
String path, {
Set<String> requireScreenshotTypes = const {},
Set<String> requireLocales = const {},
}) {
final AppStoreMetadata metadata;
try {
metadata = loadMetadata(path);
} on MetadataException catch (e) {
return [ReleaseProblem(path, e.message)];
}
final problems = <ReleaseProblem>[];
if (metadata.locales.isEmpty) {
problems.add(ReleaseProblem(path, 'no locales — nothing would publish'));
return problems;
}
for (final locale in requireLocales) {
if (!metadata.locales.any((l) => l.locale == locale)) {
problems.add(
ReleaseProblem(path, 'no listing for required locale $locale'),
);
}
}
for (final locale in metadata.locales) {
if (requireLocales.isNotEmpty && !requireLocales.contains(locale.locale)) {
continue;
}
for (final type in requireScreenshotTypes) {
final shots = locale.screenshots[type];
if (shots == null || shots.isEmpty) {
problems.add(
ReleaseProblem(
'$path → ${locale.locale}',
'no $type screenshots, which this app is required to carry',
),
);
}
}
}
return problems;
}