В прошлой статье я рассказал как сделал шифрованный мессенджер и народ в комментариях завис на одной фразе: «я пишу код на Windows, пушу в GitHub, и через 15 минут получаю готовый iOS-билд на своём iPhone». Попросили подробностей. Ну ладно.

Сначала покажу результат, а потом расскажу как к нему прийти. Вот мои приложения в App Store, оба сделаны на Windows, без мака, через GitHub Actions:

  • Dark Message — Crypto Chat — шифрованный мессенджер, про который была первая статья. Шифрует текст, фото, документы. Работает полностью офлайн.

  • Engineering Calculator HVAC — инженерный калькулятор для расчётов систем вентиляции и кондиционирования. Да, я ещё и этим занимаюсь.

Два приложения. В App Store. Написаны на Windows. Без единого макбука. Если бы мне год назад кто-то сказал что это возможно — я бы не поверил. Но вот оно.

Дальше расписываю весь путь. От регистрации аккаунта Apple из России до момента когда приложение появляется в сторе. Так, чтобы понял даже тот, кто ни разу не видел Xcode.

Зачем вообще это нужно

Разработка под iOS требует Mac. Xcode только на macOS, подписание только через утилиты Apple, сборка только на маке. Apple выстроила стену вокруг своей экосистемы и повесила табличку «вход только с макбуком».

Но есть нюанс: GitHub даёт бесплатные виртуальные машины с macOS. А Xcode на них уже установлен. То есть у тебя прямо в облаке стоит полноценный Mac, который может собрать, подписать и отправить твоё приложение в App Store. Бесплатно. Нужно только правильно это настроить.

Я покажу три пути:

  • Для вайбкодеров — ты объясняешь ИИ что хочешь, он пишет код, ты пьёшь кофе и чувствуешь себя CEO стартапа. Claude Code, Cursor, что угодно. Кнопочки нажимать умеешь — значит справишься.

  • Для программистов без мака — ты знаешь Swift, ты сам пишешь код, но мака нет. Отдаёшь свой готовый код ИИ и говоришь «настрой мне сборку и залей в App Store». ИИ тут не программист, а DevOps-инженер. Код твой, руки твои, а вся возня с сертификатами и GitHub Actions — его.

  • Для хардкорных программистов — ты сам пишешь Swift, сам ковыряешь YAML, сам гуглишь ошибки в три часа ночи. Настоящий путь самурая. Уважаю.

Результат одинаковый — приложение в App Store. Выбирай что ближе, осуждать не буду. Ну, почти.


Шаг 1. Регистрация Apple Developer Account из России

Первым делом нужен Apple ID. Если у тебя iPhone — он уже есть. Если нет — создай на appleid.apple.com. Страну аккаунта лучше поставить не Россию (я поставил другую).

Дальше идёшь на developer.apple.com/programs/enroll, логинишься, выбираешь Individual и заполняешь данные. Адрес должен совпадать со страной Apple ID.

И тут момент — Apple хочет $99 в год. Российские карты не проходят. Нужна зарубежная. Я использую карту Bybit — оформляется за день, оплачивает вообще всё. Получить её на самом деле просто, надо знать пару моментов при регистрации. Ставьте +100 к карме — расскажу как. Шучу, конечно. Кому надо — пишите в личку, расскажу бесплатно, никакой рекламы. Могу и отдельную статью написать если тема зайдёт.

Оплатил, подождал сутки (бывает до 48 часов) — и у тебя доступ к App Store Connect и порталу разработчика.


Шаг 2. Создаём проект

Вот тут пути расходятся.

Путь вайбкодера (Claude Code)

Окей, если ты из тех, кто считает что «программирование — это когда я объясняю роботу что делать» — добро пожаловать. Не стесняйся, тут таких половина. Я и сам из них.

Я использую Claude Code. Это штука от Anthropic, которая живёт прямо в терминале. Ты ей пишешь по-русски (или по-английски, ей всё равно) что тебе нужно, а она создаёт файлы, правит код, запускает команды. Ну как джуниор на стероидах, только не просит повышения и не уходит на обед.

Ставится так:

npm install -g @anthropic-ai/claude-code

Потом заходишь в папку проекта и пишешь:

claude

Всё, ты в чате. Дальше говоришь что-то вроде:

«Сделай мне iOS-приложение на SwiftUI. Шифрованный мессенджер. AES-256-GCM, ключ через PBKDF2. Экран ввода текста, кнопка зашифровать, кнопка расшифровать, результат в буфер обмена»

И он берёт и делает. Создаёт Swift-файлы, конфиг для сборки, структуру папок. Ты смотришь, говоришь «тут поменяй цвет», «добавь тёмную тему», «сделай чтобы фотки тоже шифровало». Он правит. Ты опять смотришь. И так по кругу, пока не получится то что нужно.

Главное — Claude Code работает на Windows, Linux, да хоть на маминых тапочках если в них встроен терминал. Ему Xcode не нужен. Он просто создаёт текстовые файлы с кодом. А собирать всё это будет GitHub Actions на виртуальном маке (об этом ниже).

Да, по сути ты «программируешь» голосом. Да, хардкорные разработчики сейчас кривятся. Но знаешь что? Моё приложение в App Store, а мнение снобов — нет.

Путь программиста без мака (код твой, инфраструктура на ИИ)

Это для тех, кто Swift знает, код пишет сам, но мака нет. Может, не хочешь покупать ради одного проекта. Может, принципиально на Windows. Неважно.

Схема такая: ты пишешь весь код сам в любом редакторе. SwiftUI, логика, модели — всё твоё. А потом открываешь Claude Code и говоришь:

«Вот мой готовый Swift-проект. Настрой project.yml для XcodeGen, создай GitHub Actions workflow для сборки и заливки в App Store, помоги с сертификатами»

ИИ тут не пишет код приложения. Он работает как DevOps — настраивает всю обвязку: конфиг сборки, пайплайн, подписание. Ту рутину, для которой обычно нужен мак и Xcode.

По сути ты как опытный архитектор, который нарисовал проект дома, но нанял бригаду для прокладки труб и электрики. Дом твой, идея твоя, а ковыряться в YAML и ExportOptions.plist — пусть робот, ему не жалко.

Дальше всё то же: git push, GitHub Actions собирает, TestFlight доставляет. Код в приложении твой на 100%, а вот настройку инфраструктуры ты делегировал.

Путь настоящего хардкорщика

Если от слова «ИИ» тебя передёргивает и ты считаешь что всё надо делать руками, как деды завещали — респект. Серьёзно. Этот раздел для тебя.

Создаёшь структуру руками:

MyApp/
├── Sources/
│   ├── App/
│   │   └── MyApp.swift          # @main, точка входа
│   ├── Views/
│   │   ├── ContentView.swift     # главный экран
│   │   └── SettingsView.swift    # настройки
│   ├── Models/
│   │   └── Message.swift         # модели данных
│   └── Services/
│       └── CryptoService.swift   # логика шифрования
├── Resources/
│   └── Assets.xcassets/          # иконки, картинки
├── project.yml                   # конфиг для XcodeGen
└── .github/
    └── workflows/
        └── build.yml             # CI/CD пайплайн

Пишешь Swift сам. SwiftUI, CryptoKit, UIKit — что душе угодно. Документация Apple на удивление приличная, StackOverflow ещё не умер, разберёшься.

Технически .swift файлы это просто текст, писать можно в VS Code или Sublime. Но давай честно: без мака ты работаешь вслепую. Нет превью интерфейса, нет нормального автодополнения, нет симулятора iPhone на экране. Написал кнопку — а как она выглядит, узнаешь только когда билд прилетит в TestFlight через 15 минут. Это как красить стену с закрытыми глазами и потом открывать — «ну, почти попал».

Если ты серьёзный iOS-разработчик и планируешь этим заниматься постоянно — мак тебе рано или поздно понадобится. Xcode с превью, отладчиком и симулятором это просто другой уровень комфорта.

Но если тебе надо выложить приложение, а мака нет и покупать не хочешь — способ без мака работает. Я так два приложения выпустил. Просто итерации длиннее: написал → запушил → подождал 15 минут → посмотрел на телефоне → поправил → по новой. Не так удобно, но результат тот же.

Для вайбкодеров этот момент вообще не важен — ИИ и так знает как выглядят SwiftUI-компоненты, ему превью не нужно.


Шаг 3. XcodeGen — генерируем Xcode-проект из конфига

Вот тут фишка. Обычно iOS-проект — это .xcodeproj, который весит мегабайты и создаётся в Xcode. Без мака ты его не создашь. Но есть XcodeGen — утилита, которая генерирует .xcodeproj из простого YAML-файла.

Файл project.yml выглядит так:

name: DarkMessage
options:
  bundleIdPrefix: com.darkmessage
  deploymentTarget:
    iOS: "15.0"
  xcodeVersion: "15.0"

targets:
  DarkMessage:
    type: application
    platform: iOS
    sources:
      - path: Sources
    resources:
      - path: Resources
    settings:
      base:
        PRODUCT_BUNDLE_IDENTIFIER: com.darkmessage.ios
        MARKETING_VERSION: "1.0.0"
        CURRENT_PROJECT_VERSION: "1"
        SWIFT_VERSION: "5.9"
        TARGETED_DEVICE_FAMILY: "1,2"  # iPhone и iPad
        INFOPLIST_VALUES:
          UILaunchScreen: {}
    dependencies: []

Этот файл описывает всё: название, bundle ID, версию, целевые устройства, где лежат исходники. Когда GitHub Actions запустит сборку, первым делом он вызовет xcodegen generate — и из этого YAML-файла создастся полноценный .xcodeproj.

Почему не хранить .xcodeproj в репозитории? Потому что он огромный, постоянно меняется, создаёт конфликты при мерже, и главное — без мака ты не можешь его нормально редактировать. А project.yml — это 30 строк текста, которые ты правишь в любом редакторе.


Шаг 4. GitHub — создаём репозиторий

  1. Создаёшь аккаунт на github.com (если ещё нет)

  2. Создаёшь новый репозиторий (можно приватный — бесплатно)

  3. На своём компе:

cd /путь/к/проекту
git init
git add .
git commit -m "Initial commit"
git remote add origin https://github.com/твой-юзер/твой-репо.git
git push -u origin main

Всё, код в облаке.

Связка GitHub с Claude Code (для вайбкодеров)

Тут всё проще чем кажется. Никакой специальной «связки» нет. Claude Code просто видит файлы в папке. Ты запускаешь claude, он правит код, а ты потом делаешь git push. Можешь даже попросить Claude сам сделать коммит — он умеет. По сути ты менеджер, а Claude — твой разработчик который не спорит. Мечта любого тимлида.

Связка GitHub с Apple (тут уже без разницы кто ты)

Хоть вайбкодер, хоть десять лет в Swift — эту часть придётся пройти всем одинаково. Чтобы GitHub Actions мог собирать и подписывать iOS-приложение, ему нужны три вещи:

  1. Сертификат подписи (distribution certificate)

  2. Provisioning profile

  3. Ключ API App Store Connect

Звучит страшно, но по факту делается один раз и забывается.


Шаг 5. Сертификаты и подписание

Самая мутная часть всей истории. У меня ушло больше всего времени именно сюда. Но я разжую так, чтобы не пришлось проходить через ту же боль.

Что такое Code Signing

Apple требует, чтобы каждое приложение было подписано. Подпись — это как печать, которая говорит «это приложение создал конкретный разработчик и его код не менялся с момента подписи». Без подписи iOS не запустит приложение.

Для подписи нужны:

  • Сертификат — файл .p12, содержит твой приватный ключ и сертификат от Apple. Это как твоя личная печать.

  • Provisioning profile — файл .mobileprovision, связывает твой сертификат, bundle ID приложения и список устройств (для development) или App Store. Это как разрешение «этот человек с этой печатью может подписывать вот это приложение».

Как получить без Mac

Вариант 1: Через портал Apple (ручной способ)

Тут есть проблема — для создания сертификата обычно нужен Keychain Access на маке, чтобы создать Certificate Signing Request (CSR). Но CSR можно создать и на Windows/Linux через OpenSSL:

# Генерируем приватный ключ
openssl genrsa -out ios_dist.key 2048

# Создаём CSR
openssl req -new -key ios_dist.key -out ios_dist.csr -subj "/CN=Your Name/emailAddress=your@email.com"

Потом:

  1. Идёшь на developer.apple.com/account/resources/certificates

  2. Нажимаешь + (Create Certificate)

  3. Выбираешь “Apple Distribution”

  4. Загружаешь свой ios_dist.csr

  5. Apple выдаёт тебе .cer файл

  6. Конвертируешь в .p12:

openssl x509 -in distribution.cer -inform DER -out distribution.pem
openssl pkcs12 -export -out distribution.p12 -inkey ios_dist.key -in distribution.pem

Вариант 2: Через App Store Connect API Key + GitHub Actions (автоматический)

Это то, что я на самом деле использую. Вместо того чтобы вручную возиться с сертификатами, я создаю API-ключ и GitHub Actions сам разбирается с подписями через xcodebuild.

  1. Идёшь в App Store Connect → Users and Access → Integrations → App Store Connect API

  2. Нажимаешь Generate API Key

  3. Выбираешь роль “App Manager” или “Admin”

  4. Скачиваешь .p8 файл — сохрани его, повторно скачать нельзя!

  5. Запоминаешь Key ID и Issuer ID

Этот API-ключ позволяет GitHub Actions авторизоваться в App Store Connect для загрузки билда.

Provisioning Profile

  1. В портале разработчика → Identifiers → создаёшь App ID с нужным Bundle ID (например com.darkmessage.ios)

  2. Profiles → создаёшь “App Store Distribution” profile

  3. Выбираешь свой App ID и сертификат

  4. Скачиваешь .mobileprovision файл

Складываем всё в GitHub Secrets

Теперь самое важное — эти секреты нельзя хранить в коде. Они идут в GitHub Secrets:

Репозиторий → Settings → Secrets and variables → Actions → New repository secret

Добавляешь:

  • CERTIFICATE_P12 — содержимое .p12 файла в base64 (base64 -i distribution.p12)

  • CERTIFICATE_PASSWORD — пароль от .p12

  • PROVISIONING_PROFILE — содержимое .mobileprovision в base64

  • APPSTORE_API_KEY_ID — Key ID из App Store Connect

  • APPSTORE_API_ISSUER_ID — Issuer ID

  • APPSTORE_API_KEY — содержимое .p8 файла


Шаг 6. GitHub Actions — тут происходит вся магия

Вот ради этого всё и затевалось. Файл .github/workflows/build.yml — это скрипт, который запускается на серверах GitHub каждый раз когда ты пушишь код. Сервер с macOS берёт твой код, собирает приложение, подписывает и отправляет в App Store. Ты при этом сидишь на Windows и ничего не делаешь.

name: Build and Upload to App Store

on:
  push:
    branches: [ main ]
  workflow_dispatch:  # ручной запуск

jobs:
  build:
    runs-on: macos-15  # виртуальный Mac от GitHub

    steps:
    # 1. Забираем код из репозитория
    - name: Checkout code
      uses: actions/checkout@v4

    # 2. Устанавливаем XcodeGen
    - name: Install XcodeGen
      run: brew install xcodegen

    # 3. Генерируем Xcode-проект из project.yml
    - name: Generate Xcode project
      run: xcodegen generate

    # 4. Настраиваем сертификаты для подписи
    - name: Install certificate and profile
      env:
        CERTIFICATE_P12: ${{ secrets.CERTIFICATE_P12 }}
        CERTIFICATE_PASSWORD: ${{ secrets.CERTIFICATE_PASSWORD }}
        PROVISIONING_PROFILE: ${{ secrets.PROVISIONING_PROFILE }}
      run: |
        # Создаём временный keychain
        KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db
        KEYCHAIN_PASSWORD=$(openssl rand -base64 32)

        security create-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
        security set-keychain-settings -lut 21600 $KEYCHAIN_PATH
        security unlock-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH

        # Импортируем сертификат
        echo "$CERTIFICATE_P12" | base64 --decode > $RUNNER_TEMP/cert.p12
        security import $RUNNER_TEMP/cert.p12 -P "$CERTIFICATE_PASSWORD" \
          -A -t cert -f pkcs12 -k $KEYCHAIN_PATH
        security set-key-partition-list -S apple-tool:,apple: \
          -k "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
        security list-keychains -d user -s $KEYCHAIN_PATH

        # Устанавливаем provisioning profile
        mkdir -p ~/Library/MobileDevice/Provisioning\ Profiles
        echo "$PROVISIONING_PROFILE" | base64 --decode \
          > ~/Library/MobileDevice/Provisioning\ Profiles/profile.mobileprovision

    # 5. Собираем архив
    - name: Build archive
      run: |
        xcodebuild archive \
          -project DarkMessage.xcodeproj \
          -scheme DarkMessage \
          -configuration Release \
          -archivePath $RUNNER_TEMP/DarkMessage.xcarchive \
          -destination "generic/platform=iOS" \
          CODE_SIGN_STYLE=Manual \
          CODE_SIGN_IDENTITY="Apple Distribution" \
          PROVISIONING_PROFILE_SPECIFIER="ваш-profile-name"

    # 6. Экспортируем IPA
    - name: Export IPA
      run: |
        cat > $RUNNER_TEMP/ExportOptions.plist << 'EOF'
        <?xml version="1.0" encoding="UTF-8"?>
        <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
          "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
        <plist version="1.0">
        <dict>
          <key>method</key>
          <string>app-store-connect</string>
          <key>destination</key>
          <string>upload</string>
          <key>signingStyle</key>
          <string>manual</string>
          <key>provisioningProfiles</key>
          <dict>
            <key>com.darkmessage.ios</key>
            <string>ваш-profile-name</string>
          </dict>
        </dict>
        </plist>
        EOF

        xcodebuild -exportArchive \
          -archivePath $RUNNER_TEMP/DarkMessage.xcarchive \
          -exportPath $RUNNER_TEMP/export \
          -exportOptionsPlist $RUNNER_TEMP/ExportOptions.plist

    # 7. Загружаем в App Store Connect
    - name: Upload to App Store Connect
      env:
        API_KEY: ${{ secrets.APPSTORE_API_KEY }}
        API_KEY_ID: ${{ secrets.APPSTORE_API_KEY_ID }}
        API_ISSUER_ID: ${{ secrets.APPSTORE_API_ISSUER_ID }}
      run: |
        mkdir -p ~/.private_keys
        echo "$API_KEY" > ~/.private_keys/AuthKey_${API_KEY_ID}.p8

        xcodebuild -exportArchive \
          -archivePath $RUNNER_TEMP/DarkMessage.xcarchive \
          -exportPath $RUNNER_TEMP/upload \
          -exportOptionsPlist $RUNNER_TEMP/ExportOptions.plist \
          -allowProvisioningUpdates \
          -authenticationKeyPath ~/.private_keys/AuthKey_${API_KEY_ID}.p8 \
          -authenticationKeyID $API_KEY_ID \
          -authenticationKeyIssuerID $API_ISSUER_ID

Что тут происходит по шагам:

  1. Checkout — GitHub скачивает твой код на виртуальный Mac

  2. XcodeGen — устанавливается через Homebrew (он уже есть на виртуалке) и генерирует .xcodeproj из твоего project.yml

  3. Сертификаты — из GitHub Secrets достаются твои сертификат и профиль, кладутся куда нужно

  4. Сборкаxcodebuild archive собирает приложение. Это тот же процесс, что и в Xcode на маке, только из командной строки

  5. Экспорт — создаётся IPA-файл (это по сути zip-архив с приложением), настроенный для App Store

  6. Загрузка — IPA отправляется прямо в App Store Connect

Весь процесс занимает 10-20 минут. Ты пушишь код и идёшь пить чай.


Шаг 7. App Store Connect — настройка страницы приложения

Пока GitHub Actions собирает билд, ты настраиваешь страницу в App Store:

  1. Заходишь в appstoreconnect.apple.com

  2. My Apps → кнопка “+” → New App

  3. Заполняешь:

    • Name — название приложения (должно быть уникальным в App Store)

    • Primary Language — основной язык

    • Bundle ID — выбираешь тот, что создал ранее

    • SKU — любой уникальный идентификатор (например darkmessage-001)

  4. Дальше заполняешь страницу:

    • Описание — что делает приложение

    • Скриншоты — ВАЖНО: они должны быть реальными, сделанными на устройстве или в симуляторе. Apple реально проверяет. Сгенерированные мокапы — повод для реджекта

    • Ключевые слова — для поиска

    • URL поддержки — обязательно рабочая страница поддержки. Я сделал на GitHub Gist

    • URL политики конфиденциальности — тоже обязательно. Тоже Gist

Про скриншоты без мака

У тебя же нет мака, а нужны скриншоты iPhone. Варианты:

  • Из TestFlight — когда билд загрузится, установи на iPhone через TestFlight и сделай скриншоты прямо на телефоне

  • Из GitHub Actions — можно добавить шаг, который запускает симулятор и делает скриншоты автоматически

  • Если есть друг с маком — попроси запустить симулятор на 5 минут


Шаг 8. TestFlight — тестирование

Когда GitHub Actions отправит билд в App Store Connect, он появится в разделе TestFlight. Это система тестирования от Apple.

Есть два вида тестирования:

  • Internal Testing — для тебя и до 100 людей, которых ты добавишь по email. Не требует ревью Apple.

  • External Testing — для всех по публичной ссылке. Требует ревью (обычно 1-2 дня).

Я рекомендую External Testing с публичной ссылкой — можно скинуть друзьям, в чаты, куда угодно. Люди переходят по ссылке, устанавливают TestFlight, и тестируют твоё приложение.


Шаг 9. Отправка на ревью

Когда всё готово:

  1. В App Store Connect → твоё приложение → iOS App → выбираешь билд

  2. Заполняешь «App Review Information» — контакт для ревьюеров

  3. Нажимаешь «Submit for Review»

  4. Ждёшь 1-7 дней (обычно 1-2)

Грабли, на которые я наступил:

  1. Не упоминай чужие приложения в описании. Я написал «отправляйте через Telegram или WhatsApp» — реджект. Apple не любит когда ты рекламируешь чужие приложения в своём описании.

  2. URL поддержки должен быть настоящей страницей поддержки, а не просто ссылкой на профиль GitHub. Нужна страница с контактной информацией и описанием как получить помощь.

  3. Скриншоты должны быть реальными. Не мокапы, не «нарисованные в Figma». Реальные скриншоты из приложения.

  4. Нельзя отправить новый билд, пока старый на ревью. Сначала надо отменить старый, потом отправлять новый.


Как это выглядит в жизни (мой обычный день)

Если ты вайбкодер (как я):

  1. Открыл терминал на Windows

  2. Зашёл в папку проекта

  3. Написал claude

  4. «Добавь тёмную тему и поменяй иконку шифрования»

  5. Claude покопался, поправил 4 файла

  6. Глянул git diff — вроде нормально

  7. git push

  8. Пошёл за чаем

  9. Через 15 минут на iPhone прилетело обновление в TestFlight

  10. Потыкал — работает. Или нет. Если нет — к шагу 4

Если ты хардкорщик:

Всё то же самое, только на шаге 4 ты сам открываешь VS Code и пишешь Swift. А на шаге 5 тратишь не 2 минуты, а 2 часа. Но зато с чувством глубокого удовлетворения.

Суть одна: мак не нужен. Xcode не нужен. Нужны:

  • Любой компьютер (хоть Linux на Raspberry Pi, хоть Windows на калькуляторе)

  • GitHub аккаунт (бесплатный)

  • Apple Developer ($99/год)

  • Руки и голова (в любой комбинации с ИИ)


Три пути — кто кого

Этап

Вайбкодер

Программист + ИИ-DevOps

Полный хардкор

Код приложения

«Сделай мне красиво»

Пишешь сам

Пишешь сам

project.yml

«Сгенери конфиг»

ИИ настраивает

Читаешь доку XcodeGen

GitHub Actions

«Настрой сборку»

ИИ настраивает

Пишешь YAML и плачешь

Сертификаты

«Какие команды ввести?»

ИИ подсказывает

Три часа в доке Apple

Когда сломалось

Кидаешь лог ИИ

Код чинишь сам, инфру чинит ИИ

Гуглишь и материшься

Время до билда

1-2 дня

2-3 дня

3-7 дней

Чувство гордости

«Я тоже участвовал»

«Код мой, остальное неважно»

«Я сам. РУКАМИ.»

Все три пути рабочие. Приложение в сторе одинаковое, пользователю вообще всё равно кто писал YAML. Но я скажу честно: даже если ты вайбкодишь — старайся хоть немного понимать что происходит. Потому что когда ИИ сломает тебе билд в пятницу вечером (а он сломает), понимание сэкономит нервы.


Частые проблемы и решения

«xcodebuild failed — no signing certificate»

Сертификат не установился. Проверь что в GitHub Secrets правильный base64. Частая ошибка — лишний перенос строки при копировании.

«Provisioning profile doesn’t match bundle ID»

Bundle ID в project.yml должен точно совпадать с тем, что в provisioning profile. Один символ — и всё ломается.

«The binary is not signed correctly»

Обычно проблема с ExportOptions.plist. Метод должен быть app-store-connect, а не app-store (да, это разные вещи).

«Build succeeds but upload fails»

Проверь API-ключ. Файл .p8 должен быть именно в формате AuthKey_XXXXXXXXXX.p8 и лежать в ~/.private_keys/.

Кириллица в паролях ломает шифрование между iOS и Android

Это моя личная боль. Java и Swift по-разному кодируют не-ASCII символы при генерации ключа шифрования. Решение — явно конвертировать пароль в UTF-8 байты на обеих платформах. Об этом я подробно писал в предыдущей статье.


Итого

Мак не нужен. Точка. Не «ну, как бы, можно попробовать с костылями». Нет. Я так реально работаю каждый день. Мой «Mac» — виртуалка на серверах GitHub, которая просыпается на 15 минут, собирает мне билд и засыпает обратно. Бесплатно.

Неважно, вайбкодер ты или хардкорный программист — путь в App Store с Windows один и тот же: GitHub Actions. Разница только в том, кто пишет Swift — ты или ИИ. Apple-то без разницы.

Если что-то непонятно — пишите в комменты, разжую. Про карту для оплаты из РФ — отдельная статья будет. Или в личку, если прям горит.


Предыдущая статья: Как я сделал шифрованный мессенджер, который работает без интернета

Если будет интерес — выложу шаблон репозитория с готовой автоматической сборкой. Скопировал себе, вписал свои данные и поехал.