Занимаюсь разработкой своей игры на Flutter. Дошёл до этапа, когда её пора было показать другу-тестировщику, а у него iPhone. Первая мысль — покупать Mac Mini или подписку Apple Developer за $99 в год. Обе цены платить не хотелось, пока проект не подтвердил, что вообще будет.
Пошёл искать, как выкрутиться. Оказалось, что решение вполне рабочее, но чтобы понять, что оно вообще существует и увидеть его в одной голове целиком, ушло больше времени, чем на реализацию. Собрать сам пайплайн — час. Понять, что именно нужно собирать, — заметно дольше.
Внутри: рабочая схема из четырёх инструментов, полный yml для GitHub Actions, разбор ключевых нюансов Flutter-сборки под iOS и отдельно честная экономика инди-разработчика, который в июле 2026 хочет выкатиться на iOS из России.
Android для контраста
На Samsung тестовая установка своей сборки занимает пятнадцать минут. Семь тапов по номеру сборки, тумблер отладки по USB, adb install ./app.apk — всё. Никаких кастомных программ, никаких подписей на стороне пользователя, никакой отдельной подписки, чтобы поставить своё же приложение на своё же (или дружеское) устройство.
Дальше в маркетплейс — цена вопроса тоже щадящая. Google Play Console — единоразовые $25 за аккаунт разработчика, не в год, а один раз. RuStore — бесплатно. AppGallery — бесплатно. F-Droid — бесплатно и с открытым исходником. Или просто раздавать .apk ссылкой с сайта, тоже бесплатно.
Путь «инди-разработчик пишет приложение и раскатывает пользователям» на Android стоит от нуля до $25 за всю жизнь разработчика, и процесс укладывается в один вечер даже с нулём опыта.
С iPhone всё иначе.
iPhone: схема из четырёх инструментов
Официальный путь Apple: покупаешь Mac, потому что macOS нужна для Xcode. Покупаешь подписку Apple Developer за $99 в год. Собираешь в Xcode с сертификатом провижининга. Распространяешь через TestFlight. Чинно, но затратно.
Мой путь обошёлся без Mac и без Apple Developer:
Tenorshare iCareFone — с Windows включаем на iPhone режим разработчика.
GitHub Actions — на хостовом macOS-раннере собираем
.ipaбез подписи.Sideloadly — на Windows берём собранный
.ipa, авторизуемся в Apple ID (можно бесплатный) и Sideloadly подписывает сборку этим Apple ID и ставит её на телефон.Разрешение на iPhone — на самом устройстве в настройках даём подписанному приложению доверие.
По каждому шагу детали.
Шаг 1. Включаем режим разработчика на iPhone
Начиная с iOS 16 Apple вынесла Developer Mode в отдельный тумблер, чтобы обычный пользователь случайно не поставил себе неподписанное магазином приложение. Тумблер в «Настройки → Приватность и безопасность → Режим разработчика» появляется только после того, как на устройство попало dev-signed приложение. То есть чтобы включить режим разработчика, уже нужен signed app. Курица и яйцо.
Обход простой. Подключаем телефон к компьютеру и через специальную утилиту даём iOS сигнал показать нужный тумблер. Я выбрал Tenorshare iCareFone: для базовых функций подписка не обязательна, а «Enable Developer Mode» лежит в бесплатной части. Из альтернатив рабочими называют 3uTools и AltServer.
Схема: подключил iPhone к Windows, запустил iCareFone, «Advanced Features → Enable Developer Mode», подтвердил на телефоне. После перезагрузки в «Настройках» появился тумблер. Включил один раз и на этом с iCareFone закончил, дальше он не нужен.

Шаг 2. Собираем .ipa без подписи через GitHub Actions
Задача: собрать релизную сборку Flutter под iOS без сертификата провижининга и без Apple Developer-аккаунта. Такая сборка не устанавливается напрямую, но её можно потом подписать чем угодно, в том числе бесплатным Apple ID.
Собирать нужно на macOS, потому что Xcode есть только там. Своего Mac нет, поэтому беру хостовый macOS-раннер в GitHub Actions.
Yml лежит в .github/workflows/ios-build.yml. Названия артефактов и пути унифицирую под общий пример:
name: iOS unsigned build on: push: branches: [main] tags: ['v*'] workflow_dispatch: jobs: build: name: Build unsigned .ipa runs-on: macos-latest timeout-minutes: 45 defaults: run: working-directory: apps/mobile steps: - name: Checkout uses: actions/checkout@v4 - name: Set up Flutter uses: subosito/flutter-action@v2 with: flutter-version: '3.44.0' channel: stable cache: true - name: Flutter doctor run: flutter doctor -v - name: Precache iOS artefacts run: flutter precache --ios --no-android --no-web --no-windows --no-macos --no-linux --no-fuchsia - name: Pub get run: flutter pub get - name: Pod install run: | cd ios pod install --repo-update --verbose - name: Build iOS (no codesign) env: API_BASE_URL: ${{ secrets.API_BASE_URL }} run: | if [ ! -f lib/firebase_options.dart ]; then echo "Missing lib/firebase_options.dart" exit 1 fi flutter build ios --release --no-codesign --verbose \ --dart-define=API_BASE_URL=${API_BASE_URL:-http://192.168.1.100:4000/api} - name: Package unsigned .ipa run: | set -euo pipefail cd build/ios/iphoneos mkdir -p Payload cp -R Runner.app Payload/ zip -qr myapp-unsigned.ipa Payload ls -lh myapp-unsigned.ipa - name: Upload artefact uses: actions/upload-artifact@v4 with: name: myapp-ios-unsigned-ipa retention-days: 14 path: apps/mobile/build/ios/iphoneos/myapp-unsigned.ipa - name: Attach to release if: startsWith(github.ref, 'refs/tags/v') uses: softprops/action-gh-release@v2 with: files: apps/mobile/build/ios/iphoneos/myapp-unsigned.ipa generate_release_notes: true
Что стоит вычленить.
flutter-version: 3.44.0. Не 3.32.x. Там flutter_test пинит vector_math на версии 2.1.4, и свежие библиотеки вроде fl_chart 1.1.1, требующие vector_math ^2.2.0, ломают pub solver ещё до iOS-стадии. 3.44.0 (та же версия, что стоит у меня локально) исправляет пин, и сборка проходит.
Precache с --no-android --no-web --no-windows .... Экономия времени и трафика на раннере. По умолчанию Flutter precache тащит артефакты под все платформы, а нам нужен только iPhone.
flutter build ios --release --no-codesign. Собираем без подписи. Результат в build/ios/iphoneos/Runner.app. Готовый app-бандл, который остаётся упаковать в Payload/ и заархивировать в zip, переименовав в .ipa. Ровно то, что делает Xcode при экспорте, только без обвязки с сертификатами.
Packaging step вручную. mkdir Payload && cp -R Runner.app Payload/ && zip -qr myapp-unsigned.ipa Payload. Три строки. Именно так .ipa устроен изнутри: zip-архив с директорией Payload/AppName.app. Никакой магии.
API_BASE_URL через --dart-define. Мой backend локально на LAN, но для тестировщика на его iPhone важно, чтобы приложение из коробки било по нужному хосту. Задаётся через GitHub Secret API_BASE_URL, фолбэк на локальный IP разработческого сервера. Когда backend уходит в открытый доступ, секрет обновляется одной строкой в настройках репозитория, и следующий push соберёт .ipa уже с продовым URL.
Upload artifact, retention-days: 14. Держим .ipa в артефактах две недели. Достаточно, чтобы тестировщик успел скачать и подписать, лишнее не занимает квоту хранилища.
Attach to release на тегах v*. На релизных тегах .ipa дополнительно прикладывается к GitHub Release. Внешний тестировщик берёт стабильную версию по прямой ссылке, не заходя в раздел Actions.
После push в main через 8–10 минут в разделе Actions лежит артефакт myapp-ios-unsigned-ipa весом около 60 МБ. Тестировщик его скачивает.

Одна практическая заметка про экономику раннеров. Хостовый macOS в GitHub Actions на приватных репозиториях считается по цене x10 к Linux, то есть 10 минут macOS едят 100 минут квоты. Стандартный free tier — 2000 минут в месяц в Linux-эквиваленте, то есть примерно 200 минут macOS. Моя сборка укладывается в 8m 6s, хватает и на push’и, и на релизные теги, и на эксперименты с yml. Если репозиторий публичный — минуты не считаются вовсе.
Шаг 3. Подписываем через Sideloadly на Windows
Sideloadly — бесплатная утилита для установки .ipa на iPhone через USB. Она же берёт на себя подпись: свободным Apple ID можно подписать любой .ipa и поставить его на своё устройство. Ограничения бесплатного Apple ID: подпись действует 7 дней, максимум 3 приложения одновременно. Через 7 дней приложение перестаёт запускаться, нужно перекатать через Sideloadly ещё раз. Для тестирования нормально. Для клиентского использования уже нет, тут либо покупать полноценный Apple Developer, либо TestFlight, либо распространять через альтернативные пути.
Схема на пальцах:
Скачал
.ipaиз артефакта Actions на Windows.Запустил Sideloadly, подключил iPhone кабелем.
В Sideloadly ввёл Apple ID тестировщика, можно тот самый бесплатный, зарегистрированный без карты.
Указал путь к
.ipa, нажал Start.Sideloadly подписал сборку и установил её на телефон.
Через две-три минуты приложение появилось в списке приложений на iPhone.

Шаг 4. Даём приложению доверие
При первом запуске iOS попросит подтвердить доверие профилю разработчика. «Настройки → Основные → VPN и управление устройством», в списке выбираем свой Apple ID, тапаем «Доверять». Дальше приложение запускается штатно.
Всё, тестировщик пользуется.

Тонкие моменты, которые нашёл не сразу
Пара вещей, которые в чужих инструкциях не всегда подсвечены.
Bundle ID — уникальный внутри Apple ID. Sideloadly подписывает .ipa с той бандл-идентификацией, что зашита в Info.plist. Если она пересекается с другим приложением, установленным под тем же Apple ID, предыдущее заменится. Для бесплатного Apple ID Sideloadly обычно суффиксует bundle ID случайной строкой, чтобы обойти лимит в 3 приложения. Но это надо иметь в виду при обновлениях: с изменённым bundle ID приложение видится системой как новое, старые данные не переносятся.
Firebase-конфиги под iOS. Если используется Firebase, файл GoogleService-Info.plist должен быть в репозитории (в ios/Runner/), иначе сборка упадёт. То же самое с lib/firebase_options.dart. У меня в yml стоит явная проверка перед сборкой:
if [ ! -f lib/firebase_options.dart ]; then echo "Missing lib/firebase_options.dart" exit 1 fi
Помогает не гонять раннер восемь минут впустую, если файл случайно попал в .gitignore.
Node.js на раннере. GitHub уже начал уведомлять, что Node.js 20 на раннерах помечен как deprecated, и часть actions (v4 у checkout и upload-artifact) едут на Node.js 24. Пока это уведомление, не ошибка, но при апдейте actions стоит проверять release notes: сборка внезапно может перестать проходить.
Миграция macOS-раннера. GitHub объявил, что лейбл macos-latest с 15 июня 2026 переезжает на macOS 26. Если yml привязан к специфике текущей LTS-версии macOS, стоит либо явно закрепить macos-14 (или соответствующую), либо заранее протестировать сборку на новом образе.
Экономика iOS-релиза из России в июле 2026
Тестирование на iPhone друга — окей, работает без Mac, без Apple Developer, за ноль рублей. Дальше вопрос: а как выкатить в App Store, если проект пойдёт всерьёз? Тут начинается отдельный квест, специфический для российских разработчиков.
Apple Developer стоит $99 в год, независимо от размера команды или доходов. Оплата с российской карты не проходит: Visa и Mastercard российских банков отклоняются, «Мир» не поддерживается. Обходные пути на середину 2026:
Оплата с мобильного счёта у МТС или Билайна. До апреля 2026 это был самый простой способ. Пополняешь баланс телефона на 8-9 тысяч рублей (курс Apple плавает), в Apple ID выставляешь оплату «Списание со счёта мобильного оператора», подтверждаешь. С 1 апреля 2026 Минцифры распорядилось операторам эту опцию отключить, способ больше не работает.
Apple Gift Card через маркетплейсы. Карты для российского региона продают с наценкой, иногда до 100%. Номинал в 5 000 рублей уходит за 10 000. Способ рабочий, но по факту переплачиваешь двукратно.
Иностранная карта (Bybit Card, банки Армении, Кыргызстана, Турции). Виртуальная или физическая, оформляется удалённо, пополняется криптой или переводом. Итоговая стоимость $99 плюс курсовые потери и комиссия карты, чаще выходит 10-12 тысяч рублей. Самый чистый вариант из оставшихся, если планируется работа с иностранными сервисами всерьёз.
Посредники, которые оплачивают за вас. Комиссия 20-50% сверху, $99 превращаются в $150-200. Плюс риск блокировки аккаунта Apple: когда несколько десятков человек привязывают к своим Apple ID одну и ту же карту посредника, алгоритмы Apple помечают такие аккаунты как подозрительные.
Итого чистая цена iOS-релиза из России в июле 2026: 10-15 тысяч рублей в год через иностранную карту либо 15-20 тысяч через Gift Card и посредников. Плюс единожды — цена Mac, если решить отказаться от workflow через GitHub Actions.
Сравним с Android для того же инди-разработчика:
Google Play Console — $25 единоразово, не в год.
RuStore — бесплатно.
AppGallery от Huawei — бесплатно.
F-Droid — бесплатно, только open-source.
Прямой
.apkс сайта — бесплатно.
$25 против $99 в год плюс квест на оплату. На Android распространение — пятнадцать минут через USB для тестировщика, на iPhone — четыре инструмента и понимание, что вообще существует такая схема.
Заключение
Тестирование Flutter-игры на iPhone друга без Mac и без Apple Developer реально. Схема Tenorshare iCareFone → GitHub Actions → Sideloadly → доверие на устройстве собирается за час, если сразу понятно, что делать. Основная работа не в реализации, а в том, чтобы сначала найти саму схему в комплекте: инструкций по каждому куску много, но сшитого маршрута в одном месте не попадалось. Собрал сам.
Выкладываться в App Store из России — отдельная история, к которой пока не подошёл. Когда дойдёт очередь, материала на ещё одну статью соберётся сам собой.
