Зачем вообще избегать Xcode?

Xcode — мощный инструмент, но у него есть одна фундаментальная проблема: он стоит на пути. Многие разработчики, работающие с Mac годами, так и не полюбили Xcode — непривычные горячие клавиши, Navigation-панели мышью, странная логика вкладок. Но главное — в Xcode совершенно не интегрированы LLM-инструменты, которые сегодня кардинально ускоряют разработку.

Есть и хорошая новость: Xcode.app должен быть установлен, но его никогда не нужно открывать. Инструменты xcodebuild, notarytool, stapler и devicectl — все они живут внутри Xcode и отлично работают из командной строки.

Именно этим подходом пользуется Scott Willsey в своём проекте: с небольшой предварительной настройкой можно кодить Mac и iOS приложения сколько угодно, не смотря на Xcode. А если что-то непонятно — достаточно направить Claude Code на нужный материал и позволить ему разобраться.

«После первоначальной настройки слово “выпустить новую сборку” превращается в одно предложение.»


Что нужно сделать один раз: одноразовая настройка

Прежде чем полностью уйти в терминал, нужно пройти несколько шагов через GUI — но только один раз.

Несколько одноразовых шагов действительно требуют графического интерфейса или интерактивного терминала: войти в Apple ID, создать сертификат Developer ID и сохранить пароль для нотаризации. После этого — сборка и деплой полностью headless.

Шаг 1: Apple Developer Account

Необходимо иметь платный аккаунт Apple Developer, чтобы распространять и нотаризировать приложения. Нотаризация нужна, чтобы macOS и iOS не приняли ваш бинарник за вредоносное ПО и не удалили его.

Шаг 2: Два типа сертификатов

Developer ID Application и Apple Development — это два разных сертификата. Apple Development — для сборки и запуска на собственных устройствах, локальной отладки. Developer ID Application — для нотаризированного .app-бандла, который проходит Gatekeeper и запускается на чужом Mac.

⚠ Важно
Без платного Apple Developer Account ($99/год) ни нотаризация, ни дистрибуция не работают. Это обязательное требование Apple вне зависимости от используемого инструментария.

Шаг 3: Ключ подписи в keychain

Подпись основана на сертификате в keychain. Ключ подписи хранится в login keychain, xcodebuild находит его автоматически. Никаких секретов в репозитории.


Инструменты командной строки: ваш новый рабочий стол

После одноразовой настройки весь pipeline переходит в терминал. Вот ключевые утилиты:

ИнструментНазначениеГде живёт
xcodebuildКомпиляция, архивирование, экспортВнутри Xcode.app
notarytoolНотаризация Mac-приложения в AppleВнутри Xcode.app
staplerПрикрепление нотаризационного тикета к бандлуВнутри Xcode.app
devicectlУстановка на подключённый iPhone/iPadВнутри Xcode.app
codesignПодпись бинарникаmacOS system tools

Всё это — обычные вызовы командной строки. Xcode.app никогда не запускается; инструменты живут внутри него, но работают автономно.

Быстрый inner loop: сборка без подписи

Для проверки «компилируется ли / проходят ли тесты» подпись вообще не нужна:

xcodebuild \n  -scheme MyApp \n  -destination 'platform=iOS Simulator,name=iPhone 16' \n  CODE_SIGNING_ALLOWED=NO \n  build

Флаг CODE_SIGNING_ALLOWED=NO даёт ad-hoc сборку: она компилируется и запускается в симуляторе, но Gatekeeper её отклонит, и entitlements вроде iCloud KVS или App Group не привяжутся. Это быстрый inner loop.

💡 Совет
Используйте CODE_SIGNING_ALLOWED=NO для ежедневной разработки и тестов. Переключайтесь на полный release.sh только когда готовы шипнуть.

release.sh: весь pipeline в одном скрипте

Mac-приложение шипится через один скрипт — scripts/release.sh — который пишется один раз. Он запускает всю цепочку: archive → Developer ID sign → notarize → staple → install в /Applications.

Одна команда делает весь shippable chain: архивирует, экспортирует с Developer ID, нотаризирует, staple-ует, верифицирует, устанавливает. Если любой шаг падает — скрипт останавливается и сообщает, что именно сломалось.

#!/usr/bin/env bash
set -euo pipefail

APP_NAME="MyApp"
SCHEME="MyApp"
ARCHIVE_PATH="build/${APP_NAME}.xcarchive"
EXPORT_PATH="build/export"
NOTARY_PROFILE=${TZED_NOTARY_PROFILE:-"my-notary-profile"}

# 1. Archive
xcodebuild archive \n  -scheme "$SCHEME" \n  -archivePath "$ARCHIVE_PATH"

# 2. Export with Developer ID
xcodebuild -exportArchive \n  -archivePath "$ARCHIVE_PATH" \n  -exportPath "$EXPORT_PATH" \n  -exportOptionsPlist ExportOptions.plist

# 3. Notarize
xcrun notarytool submit "${EXPORT_PATH}/${APP_NAME}.app" \n  --keychain-profile "$NOTARY_PROFILE" \n  --wait

# 4. Staple
xcrun stapler staple "${EXPORT_PATH}/${APP_NAME}.app"

# 5. Verify
spctl -a -vvv "${EXPORT_PATH}/${APP_NAME}.app"

# 6. Install
cp -R "${EXPORT_PATH}/${APP_NAME}.app" /Applications/
echo "✅ Shipped!"

Перегрузить профиль нотаризации без правки скрипта можно одной переменной:

TZED_NOTARY_PROFILE=other-profile ./scripts/release.sh

iOS: деплой на устройство

У iOS нет шага нотаризации — это концепция дистрибуции для Mac. Установка сборки на подключённый iPhone делается через xcodebuild плюс devicectl — оба из тулчейна Xcode.

# Сборка для устройства
xcodebuild \n  -scheme MyApp \n  -destination 'generic/platform=iOS' \n  -archivePath build/MyApp.xcarchive \n  archive

# Установка на конкретный iPhone через devicectl
xcrun devicectl device install app \n  --device 00008120-001234567890 \n  build/export/MyApp.ipa

graph TD
    A[Написать код в VS Code / Cursor] --> B{Проверка?}
    B -->|Быстрая| C[xcodebuild CODE_SIGNING_ALLOWED=NO]
    C --> D[Симулятор]
    B -->|Финальный релиз| E[./scripts/release.sh]
    E --> F[Archive]
    F --> G[Developer ID Sign]
    G --> H[Notarize]
    H --> I[Staple]
    I --> J[Install /Applications]
    E --> K{iOS?}
    K --> L[xcodebuild archive]
    L --> M[devicectl install]


Claude Code как движок всего процесса

Именно это и выполняет Claude Code через свой shell. Идея в том, что LLM-агент получает доступ к терминалу и запускает весь pipeline сам — от компиляции до нотаризации — без единого клика в GUI.

Если хотите попробовать самостоятельно: установите Xcode и xcodegen, сделайте credential setup, затем сядьте с Claude и постройте собственные release.sh и CLAUDE.md. Последняя часть — это настоящая работа, занимает час-два максимум. После этого «выпустить новую сборку» становится одним предложением.

После настройки первого приложения Claude Code может скопировать ту же конфигурацию для будущих проектов.

ℹ CLAUDE.md
CLAUDE.md — это файл инструкций для агента, который кладётся в корень проекта. В нём описывается структура проекта, команды сборки, путь к скриптам и правила для агента. Claude Code читает его при старте каждой сессии и знает, как именно работать с конкретным репозиторием.

Альтернативы: если Xcode не установлен вообще

Описанный выше подход предполагает, что Mac есть, просто Xcode не открывается. Но что если Mac нет совсем?

Третий вариант — полностью пропустить «сырой Mac» и использовать специализированный mobile CI/CD-сервис: Capawesome Cloud, Codemagic или Bitrise. Вместо аренды машины вы описываете сборку в конфиг-файле, сервис поднимает чистое macOS-окружение, собирает, подписывает и отдаёт вам .ipa. Вам не нужно прикасаться к Xcode самостоятельно.

Облачные сервисы сборки — Code2Native, Codemagic, Expo EAS — содержат парки Mac-серверов в дата-центрах. Вы загружаете проект, они компилируют на реальных Mac-машинах и возвращают подписанный бинарник.

СценарийРекомендация
Mac есть, Xcode надоелxcodebuild + Claude Code + release.sh
Mac есть, нужен CI/CDGitHub Actions (macOS runner)
Mac нет, редкие сборки (1–20/мес)Codemagic / Capawesome Cloud
Mac нет, ежедневные сборкиАренда MacStadium / MacinCloud
Нет Mac, кроссплатформаReact Native + Expo EAS Build
📝 Пример
Если вы solo-разработчик и шипите обновления раз в неделю — связка xcodebuild + release.sh + Claude Code на локальном Mac даёт самый чистый и быстрый workflow без подписок на CI/CD.

Заключение

Xcode — необходимость инфраструктурная, но не рабочая. Xcode должен быть установлен — никуда от этого не деться, потому что сборка зависит от инструментов внутри Xcode.app. Но открывать его каждый раз — не нужно.

Весь производственный цикл — от компиляции Swift-кода до нотаризированного .app в /Applications или .ipa на iPhone — укладывается в несколько shell-команд. Один раз настроенный release.sh и правильно заполненный CLAUDE.md превращают релиз в буквально одну команду терминала.

Это не хак и не обходной манёвр — это нормальный профессиональный инструментарий, который Apple предоставляет, просто никто особо не рассказывал, что Xcode.app можно держать в доке, но никогда не открывать.