Работаю iOS-разработчиком в компании, которая попала под санкции. Казалось бы - ну попала и попала, мы же просто код пишем. Но Apple так не считает. Это история о том, как мы трижды теряли аккаунт разработчика, ловили абсурдные ошибки и находили обходные пути, чтобы просто доставить приложение пользователям.

Если вы iOS-разработчик в санкционной компании — эта статья может сэкономить вам месяцы нервов.

Начало. Enterprise — было хорошо

Я работаю в команде, которая разрабатывает корпоративное внутреннее приложение. Классика — сотрудники компании пользуются, наружу ничего не торчит. Для такого случая Apple придумал Apple Developer Enterprise Program. Подписал IPA, раздал через внутренний MDM или ссылку — и всё работает, никакого App Store.

Жили мы так спокойно, релизили, радовались. Пока в один февральский день 2024 года не прилетело письмо.

None

Первый удар. Enterprise больше не для вас

Apple сообщил, что корпоративные учётные записи разработчиков для России больше не будут работать. Просто так. Без вариантов.

Окей. Сели, подумали, нашли выход — переходим на обычный Apple Developer Program и используем Unlisted App Distribution. Это когда приложение есть в App Store, но его нельзя найти через поиск — только по прямой ссылке. Для корпоративного приложения — идеально.

Подали заявку на Unlisted. Apple одобрила. Приложение стало доступно по ссылке. Корпоративный аккаунт удалили. Казалось, что мы нашли решение, которое проживёт долго. Казалось.

Спустя 2 месяца. Письмо с извинениями

Через два месяца пришло письмо от Apple. Вежливое такое — мол, мы видим, что вашим аккаунтом пользуются из России или Беларуси, поэтому мы сожалеем, но вынуждены удалить ваш аккаунт. Прямо так — «сожалеем и удаляем». Приложение перестало быть доступно. Для всех стран. Просто — бац — и нет его.

Причём на том же аккаунте были и публичные приложения — и вот с ними Apple оказался куда суровее. Удалили полностью весь аккаунт. Все приложения.

Первая мысль — окей, есть же iMazing, можно установить IPA напрямую. Но нет. iMazing работает только если приложение когда-то было скачано из App Store на этот аккаунт. А наше приложение уже испарилось оттуда.

Кто-то скажет — а почему не сделали приложение-ширму, как банки? Выложить под другим названием, с другим интерфейсом, а внутри — ваше приложение. Опыт банков мы знали хорошо. И именно поэтому не пошли этим путём. Apple удаляет такие приложения быстро — у банков их сносили пачками. А ресурсов на постоянное создание новых ширм у нас не столько, сколько у крупных банков. Нам нужно было решение, которое живёт, а не которое нужно пересоздавать каждые две недели.

Тупик? Почти.

Попытка 2. Дочерняя компания

Завели новую учётную запись Apple Developer на дочернюю компанию. Выложили приложение, хотели сделать его публичным. Но App Store Review не пропустил — нет демо-версии, нет возможности зарегистрироваться для проверяющего. А показывать внутренний корпоративный функционал случайному ревьюеру… ну вы понимаете.

Решение — распространять через TestFlight. Загружаем сборку, добавляем тестеров, они получают приложение. Работает.

Но при подаче на TestFlight review прилетел отказ: Guideline 4.3(a) — Design — Spam.

None

Ваше приложение похоже на приложения с ранее заблокированного аккаунта.

Ну конечно похоже. Это оно и есть. Просто на другом аккаунте.

Как я обошёл 4.3(a)

Мне помогло вот что:

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

- Написал подробное описание отличий от предыдущего приложения при подаче: «добавили модуль X, переработали дизайн Y, изменили архитектуру Z».

- Не просто скопировал старое приложение — реально добавил видимые изменения.

Apple приняла. Мы снова распространяли приложение через TestFlight. И жили так какое-то время.

А потом на этот же аккаунт добавили второе публичное приложение, которое легко гуглится и связывается с компанией из санкционного списка. Итог предсказуем — аккаунт снова удалён вместе с моим приложением.

None

Попытка 3. Физлицо и паранойя

Новый аккаунт. На этот раз — на физическое лицо. Никаких связей с компанией в метаданных.

Но у аккаунта на физлицо есть серьёзный минус, о котором стоит знать заранее. В Apple Developer Program для Individual-аккаунта роль Account Holder нельзя передать другому человеку. Вообще. Apple разрешает передачу только в двух случаях: несовершеннолетний владелец достиг 18 лет, или владелец аккаунта умер. Всё. Это значит, что если единственный человек, на которого зарегистрирован аккаунт, уволится, заболеет или просто уедет в отпуск без связи — вся дистрибуция встанет. Классический bus factor = 1. В организационном аккаунте хотя бы можно назначить нескольких админов, а тут — один человек держит всё на себе.

Прежде чем подавать, я серьёзно подготовился:

- Сделал редизайн — не кардинальный, но заметный.

- Сменил название приложения.

- Добавил ещё один модуль в проект.

  • Переписал некоторые классы — на всякий случай, чтобы код максимально отличался от того, что Apple видел раньше.

И тут маленький, но раздражающий сюрприз: мой старый тестовый iPhone был в карантине на 2 недели. Его UUID был привязан к удалённой учётке, и Apple не давал его использовать для разработки. Пришлось брать другой телефон. Мелочь, но когда у тебя и так всё горит — бесит.

В итоге — снова попал в TestFlight. Приложение работает, тестеры получают сборки. Живём.

422. Финальный босс

Жили мы так долго и почти расслабились. Но недавно случилось то, от чего мы даже удивились.

Все сборки в TestFlight разом стали expired. При выкладке новой — ошибка. В интерфейсе просто красный баннер «There was an error processing your request. Please try again later.»

None

Окей, «try again later» — пробуем. Час. Два. День. Не работает.

Полез в дев-тулзы смотреть ответ сервера. И вот что увидел:

{
  "errors": [{
    "id": "**************",
    "status": "422",
    "code": "ENTITY_UNPROCESSABLE.BETA_CONTRACT_MISSING",
    "title": "Beta contract is missing for the app.",
    "detail": "Beta Contract is missing."
  }]
}

422. Beta Contract is missing.

Первая мысль — мы что-то не приняли в соглашениях. Полез проверять — все agreements подписаны, всё зелёное, всё принято. Никаких красных баннеров в App Store Connect.

Вторая мысль — всё, это конец. Apple наконец-то связал и этот аккаунт.

Написал в техподдержку Apple. Одно письмо. Два. Три. Четыре. Пять писем. Две недели тишины.

А потом пришёл ответ: «Это баг на нашей стороне.»

Через 48 часов всё заработало. Просто так. Без каких-либо действий с моей стороны.

Две недели паники — из-за бага Apple.

Что я вынес из всего этого

Вот конкретные советы, если вы оказались в похожей ситуации:

По аккаунтам:

- Не держите корпоративные и публичные приложения на одном аккаунте. Публичное приложение легко гуглится, а значит легко связывается с санкционной компанией — и утянет за собой всё.

- Физлицо безопаснее юрлица. Apple сложнее связать random-аккаунт физлица с санкционным списком.

- Имейте план Б. И план В. У меня вот дошло до плана Г.

По приложению:

- При переносе на новый аккаунт — не просто копируйте. Меняйте название, добавляйте модули, переписывайте классы. Apple сравнивает бинарники и метаданные.

- Guideline 4.3(a) Spam — не приговор. Подробное описание отличий + реальные изменения в коде помогают пройти ревью.

- Новый UUID устройства для разработки — имейте запасной. Старые девайсы могут быть в карантине.

По безопасности и паранойе:

- Старые девайсы, которые были привязаны к удалённым аккаунтам — лучше вообще не светить. Ни в новом аккаунте, ни при разработке. Apple отслеживает UUID.

- Я лично захожу в учётку Apple Developer только через VPN. Паранойя? Может быть. Но в Apple тоже не глупые люди сидят — IP-адреса, геолокация, всё это может стать основанием для очередного «мы сожалеем».

- Аккаунт на физлицо — это bus factor = 1. Передать Account Holder роль другому человеку практически невозможно. Имейте это в виду и продумайте, что будет, если этот человек станет недоступен.

По ошибкам и поддержке:

- Если видите непонятную ошибку — смотрите ответ сервера, не полагайтесь на UI. Красный баннер «try again later» может означать что угодно.

- Пишите в Apple Support. Много. Настойчиво. 5 писем и 2 недели — это нормально.

- Не все ошибки — это Apple вас банит. Иногда это просто баг. Но нервов вы потратите одинаково.

По распространению:

- TestFlight — рабочий вариант для корпоративных приложений, если Enterprise убили. Лимит в 10 000 тестеров обычно хватает.

- Unlisted App Distribution — хорошее решение, но не защищает от блокировки аккаунта.

Итого

Три аккаунта. Три удаления. Один баг Apple на десерт. А приложение — работает. Пользователи получают сборки через TestFlight, всё стабильно.

Мораль? В санкционном мире iOS-разработки не бывает финальных решений. Бывает текущее решение, которое работает прямо сейчас. И нужно быть готовым, что завтра придётся искать новое.

Если вы в такой же ситуации — не сдавайтесь. Выход есть, просто каждый раз он выглядит по-другому.