Инженерная статья

Предварительная проверка iOS-ресурсов через actool на облачном Mac

Предварительная проверка iOS-ресурсов через actool на облачном Mac

Один пропущенный слот для иконки нередко обнаруживается лишь тогда, когда полная архивация почти завершена. В iOS-конвейере на облачном Mac к этому моменту уже потрачено время на разрешение зависимостей, компиляцию исходного кода и тестирование, но процесс всё равно завершается с ошибкой из-за некорректных метаданных в Assets.xcassets. Более практичный подход — вынести вызываемый Xcode инструмент actool в отдельную предварительную проверку, чтобы ошибки ресурсов останавливали конвейер на раннем этапе.

Что именно проверяет actool

actool читает Asset Catalog и компилирует ресурсы с учётом платформы, минимальной версии ОС и типа устройства. Отдельный запуск позволяет обнаружить некорректный Contents.json, слоты изображений с отсутствующими файлами, неизвестные атрибуты, повторяющиеся имена, а также несовместимость AppIcon с целевой платформой.

Такая проверка не заменяет полноценную сборку. Ссылки в исходном коде на несуществующие ресурсы, разные Asset Catalog у разных target, переопределение имени AppIcon в настройках сборки и другие подобные проблемы по-прежнему могут проявиться только на этапе xcodebuild. Рекомендуемый порядок этапов конвейера:

Этап Что проверяется Стоимость сбоя
Проверка синтаксиса JSON Можно ли разобрать Contents.json Минимальная
Предварительная проверка actool Структура ресурсов и параметры платформы Низкая
Сборка Xcode target, ссылки из исходного кода и компоновка Высокая
Тестирование и архивация Поведение приложения и итоговые артефакты Максимальная

Цель предварительной проверки — не имитировать весь процесс Xcode, а как можно раньше выявлять однозначные ошибки ресурсов с понятным способом исправления.

Фиксация версии инструментов и входных параметров

Сначала проверьте, какой Xcode фактически используется текущей задачей. Не следует считать, что интерактивный терминал и процесс CI работают с одним и тем же каталогом разработчика.

xcode-select -p
xcodebuild -version
xcrun --find actool
xcrun actool --version

Если на узлах команды установлено несколько версий Xcode, в точке входа задачи необходимо явно задавать DEVELOPER_DIR, а вывод xcodebuild -version сохранять в журнале сборки. Платформа, минимальная версия системы, тип устройства и имя AppIcon в скрипте также должны совпадать с настройками сборки проекта. Иначе успешная предварительная проверка означает лишь то, что ресурсы компилируются с другим набором параметров, но не подтверждает работоспособность реального target.

Перед запуском actool стоит дополнительно выполнить быструю проверку всех JSON-файлов в каталоге:

find App/Assets.xcassets -name Contents.json -print0 |
while IFS= read -r -d '' file; do
  plutil -lint "$file"
done

Так можно точно определить путь к файлу, в котором остались маркеры конфликта слияния, лишние символы в конце или повреждённое содержимое.

Скрипт для непосредственного запуска в CI

Следующий скрипт сохраняет результаты в .ci-artifacts/actool и при ошибке оставляет полную диагностику, которую CI может собрать как вложение. Каталог, минимальную версию ОС и имя AppIcon следует передавать через параметры или конфигурацию проекта, а не поддерживать несколько копий одного скрипта.

#!/bin/bash
set -euo pipefail

CATALOG="${1:-App/Assets.xcassets}"
DEPLOYMENT_TARGET="${DEPLOYMENT_TARGET:-16.0}"
APP_ICON_NAME="${APP_ICON_NAME:-AppIcon}"
OUT=".ci-artifacts/actool"

rm -rf "$OUT"
mkdir -p "$OUT/compiled"
export LANG=en_US.UTF-8

if ! xcrun actool "$CATALOG" \
  --compile "$OUT/compiled" \
  --platform iphoneos \
  --minimum-deployment-target "$DEPLOYMENT_TARGET" \
  --target-device iphone \
  --app-icon "$APP_ICON_NAME" \
  --output-partial-info-plist "$OUT/partial-info.plist" \
  --notices --warnings --errors \
  >"$OUT/actool.log" 2>&1; then
  cat "$OUT/actool.log"
  exit 1
fi

cat "$OUT/actool.log"
plutil -lint "$OUT/partial-info.plist"

Параметр set -euo pipefail не позволяет конвейеру продолжить работу после сбоя команды. Журнал сначала записывается в файл и только затем выводится, чтобы сохранить и код завершения, и диагностические сообщения. Если сразу включить команду в сложный конвейер, легко ошибочно получить статус последней команды вместо статуса actool.

Обработка предупреждений и распространённых ложных срабатываний

Не превращайте сразу все предупреждения в ошибки

В старых проектах могут накапливаться предупреждения о неназначенных вариантах отображения для устройств, неиспользуемых наборах изображений или соглашениях об именовании. При первом подключении проверки лучше сохранить журнал и сформировать базовый уровень, а блокировать конвейер только по однозначным проблемам. Если завершать задачу с ошибкой при любой строке с warning:, команда, скорее всего, сначала отключит проверку, а не исправит ресурсы.

Некорректный JSON, отсутствующие файлы ресурсов, незаполненные обязательные слоты AppIcon и повторяющиеся имена рекомендуется блокировать сразу. Для уведомлений о неиспользуемых ресурсах и подобных проблемах сначала стоит учитывать их количество, назначить срок очистки и лишь затем ужесточить правила.

Разделяйте платформы симулятора и реального устройства

Успешная проверка только с iphonesimulator не гарантирует, что проверка с iphoneos также завершится успешно. Требования к устройствам, правила для иконок и формат артефактов могут приводить к разным диагностическим сообщениям. Если конвейер собирает оба типа target, проверку нужно запускать дважды с отдельными каталогами вывода, чтобы второй запуск не перезаписал результаты первого.

Для target с поддержкой iPad необходимо дополнительно передать соответствующий параметр --target-device ipad. Не следует указывать только iphone ради успешного прохождения проверки: набор устройств должен соответствовать фактической конфигурации target.

Подключение к конвейеру и проверка результата

Размещать предварительную проверку после установки зависимостей нет необходимости, поскольку actool обычно требует только Xcode и ресурсы из репозитория. Лучше запускать её сразу после получения исходного кода, до разрешения зависимостей. Тогда ошибки ресурсов будут обнаруживаться быстро, даже если сервис управления пакетами временно работает медленно.

Для первого запуска можно подготовить три тестовых сбоя: повредить один файл Contents.json, временно переместить используемый файл иконки и заменить имя AppIcon на несуществующее. Убедитесь, что каждая задача завершается с ненулевым статусом, журнал содержит конкретный каталог, а система сохраняет .ci-artifacts/actool. После восстановления файлов проверьте, что успешно выполняются и предварительная проверка, и полная сборка.

Если репозиторий содержит несколько target приложений, следует вести список «target, каталог ресурсов, платформа, имя AppIcon» и обрабатывать его поэлементно в цикле, а не передавать все каталоги одной команде. В этом случае сообщение об ошибке сразу указывает на ответственный модуль, а параметры одного target не скрывают проблемы другого.

В итоге необходимо сохранить два уровня контроля: actool быстро выявляет однозначные ошибки в каталоге ресурсов, а полная сборка Xcode проверяет интеграцию target и итоговые артефакты. При таком разделении ответственности проблемы ресурсов обнаруживаются раньше, а журналы ошибок точнее указывают место, которое нужно исправить.

Часто задаваемые вопросы

Заменяет ли проверка actool полную сборку Xcode?

Нет. Она заранее выявляет ошибки ресурсов и параметров, но итоговую сборку всё равно нужно выполнять с теми же схемой, SDK и конфигурацией выпуска.

Нужно ли останавливать CI при любом предупреждении actool?

Не сразу. Сначала следует классифицировать текущие предупреждения, а затем блокировать однозначные дефекты: неверный JSON, обязательные иконки и дубли имён.

OwnAMac Облачный Mac

Перенесите следующую сборку на выделенный физический узел Apple Silicon

Выберите одну из трёх конфигураций и пяти узлов с учётом масштаба задачи. Вычислительные ресурсы и хранилище не делятся с другими клиентами. Все узлы стабильно работают 365 дней в году; фактический статус доступности возвращается в реальном времени через консоль.

Выбрать конфигурацию и заказать