CodePush закрыли. Чем заменить.
Microsoft закрыл Visual Studio App Center, а вместе с ним CodePush, 31 марта 2025 года. 20 мая 2025 года оба репозитория заархивированы и переведены в режим только для чтения: microsoft/react-native-code-push — клиентская библиотека, и microsoft/code-push-server — отдельный сервер, который Microsoft опубликовал, чтобы команды могли поднять его сами.
В README этого сервера прямо написано, что именно вы берёте на себя: «This code is provided "as is", because of that Microsoft will not provide support services for it» — код предоставляется как есть, поддержки не будет.
Так что вопрос уже не в том, переезжать ли. Вопрос в том, куда — и во сколько это обойдётся вашему приложению.
Четыре честных варианта
1. Оставить CodePush и держать его самим
Развернуть code-push-server, направить на него CLI, в приложении не менять ничего. Сегодня это самая маленькая правка, а завтра — самая большая ответственность: заархивированный сервер и заархивированный клиентский SDK, ни один из которых не получает исправлений, стоят между вашими пользователями и каждым релизом. Когда очередная смена архитектуры React Native сломает нативный модуль, чинить его сверху будет некому.
Разумно, если вам нужны недели, а не годы, и вы уже переезжаете куда-то ещё.
2. EAS Update
Собственный сервис Expo и эталонная реализация протокола, о котором ниже. Технически это самое безопасное направление: его поддерживают те же люди, что поддерживают клиент. Нужен аккаунт Expo, а оплата идёт через Expo — и если вы платите из России, разговор обычно заканчивается именно здесь.
3. Хостинговый сервис со своим SDK
Место закрывшегося CodePush заняли несколько продуктов, и у каждого свой React Native SDK. Они работают. Но вы уходите от одной проприетарной клиентской библиотеки к другой — то есть ровно в то положение, из-за которого март 2025-го оказался дорогим. Остановится этот вендор — переезжать снова.
4. Сервис на открытом протоколе Expo Updates
expo-updates — публичная клиентская библиотека, реализующая опубликованный протокол. Любой сервер, который на нём говорит, может обслуживать ваше приложение, а переход между такими серверами — это URL в конфигурации, а не замена SDK. Otapush — один из таких серверов. EAS Update — тоже. Это сделано намеренно: два аргумента ниже — единственные, которые конкурент не может просто скопировать.
Сравнение
| Свой CodePush | EAS Update | Otapush | |
|---|---|---|---|
| Клиентская библиотека | react-native-code-push (архив) |
expo-updates |
expo-updates |
| Кто поддерживает клиент | никто | Expo | Expo |
| Кто держит сервер | вы | Expo | мы |
| Протокол | CodePush, проприетарный | Expo Updates v1 | Expo Updates v1 |
| Нужен аккаунт Expo | нет | да | нет |
| Цена ухода | переписать клиент | один URL | один URL |
| Оплата в рублях, счёт для юрлиц | ваш счёт за хостинг | нет | да |
Вопрос, который на самом деле всё решает
Не функции. Кому принадлежит библиотека внутри вашего бинарника.
Проприетарный SDK обновлений — единственная зависимость, которую нельзя заменить без релиза в сторе, потому что она вкомпилирована в приложение, уже установленное у пользователей. Когда CodePush закрылся, дорогим оказался не сервер, а клиент.
expo-updates — единственный клиент в этой нише, который не принадлежит поставщику обновлений. Выбрав сервер, говорящий на его протоколе, вы делаете следующий переезд — в том числе от нас — правкой конфигурации.
Переход с react-native-code-push
Работа сводится к замене клиентской библиотеки. Серверная часть — это URL.
1. Убрать CodePush
Отвяжите и удалите react-native-code-push, снимите обёртку codePush() с корневого компонента и уберите нативную конфигурацию: CodePushDeploymentKey в Info.plist, записи CodePush в strings.xml и MainApplication.
2. Поставить expo-updates
В bare-проекте React Native:
npx install-expo-modules@latest
npm install expo-updates
cd ios && pod install
install-expo-modules добавляет ядро Expo-модулей, без которого expo-updates не работает. Managed-проектом Expo ваш проект от этого не становится — что именно меняется, а что нет, разобрано в Bare React Native.
3. Направить его на ваше приложение
npm install -g otapush
otapush login
otapush init
otapush init прописывает URL обновлений, runtime version и сертификат подписи вашего приложения в AndroidManifest.xml и Expo.plist (или в app.json для managed-проектов Expo). Managed-случай разобран в настройке Expo.
4. Собрать один раз и публиковать
URL обновлений и сертификат подписи лежат в бинарнике, поэтому переезд требует одного релиза в сторе. Дальше публикация выглядит так:
otapush publish --channel prod --platform ios
Что меняется в вашем JavaScript
codePush.sync() делал проверку, загрузку и перезапуск одним вызовом. expo-updates разделяет их: Updates.checkForUpdateAsync(), Updates.fetchUpdateAsync(), Updates.reloadAsync() — плюс хук useUpdates(), если состоянием обновления нужно управлять из интерфейса. По умолчанию библиотека проверяет обновления при запуске и применяет их при следующем — то есть ведёт себя так, как и было настроено большинство установок CodePush.
Ключи развёртывания превращаются в каналы. Там, где у CodePush были Staging и Production, у приложения в Otapush есть dev, staging и prod, а перевод проверенной сборки между ними — одна команда, см. справочник CLI.
Оплата из России
Именно из-за этого нам пишет большинство команд.
Expo выставляет счета через международные платёжные сервисы. Otapush принимает карты и СБП в рублях через российский эквайринг, а юрлица могут оплатить по счёту на российскую компанию. Цены — в разделе тарифов, тарификация по MAU (уникальные устройства, которые за календарный месяц проверили или скачали обновление), а превышение лимита не останавливает раздачу обновлений.
Если вы за пределами России, самостоятельной оплаты пока нет — напишите нам, договоримся.
Вопросы
Придётся ли переходить на Expo, чтобы использовать expo-updates?
Нет. expo-updates работает в bare-проекте React Native. Ему нужно ядро Expo-модулей, которое добавляет install-expo-modules, но проект сохраняет свою нативную сборку, свой CI и свой процесс релизов. Аккаунт Expo при этом не участвует.
Можно ли остаться на CodePush и решить позже?
Можно, и на коротком горизонте это защитимый выбор. Вы ставите на то, что ничто в React Native не сломает неподдерживаемый нативный модуль раньше, чем вы переедете. С каждым релизом эта ставка становится хуже.
Разрешает ли это App Store?
Да, для обновлений JavaScript и ассетов. Лицензионный договор Apple (§3.3.1(B)) разрешает загружать интерпретируемый код, пока он не меняет заявленное назначение приложения и не обходит защиту ОС; в Google Play есть такое же исключение для интерпретируемых языков. Нативные изменения по-прежнему требуют релиза через стор. Обе нормы процитированы полностью в правилах сторов.
Что будет, если ваш сервер упадёт?
expo-updates запустит бандл, который уже лежит на устройстве, — последнее скачанное обновление или версию из сборки, — и повторит попытку при следующем запуске. Недоступность сервера обновлений не роняет приложение. Это свойство клиента, и у CodePush оно было таким же.
Чем это отличается от сервиса со своим SDK, который я уже почти выбрал?
Механически — почти ничем: оба доставляют JavaScript-бандл. Разница проявляется в тот день, когда вы захотите уйти. От нас уход стоит одного URL, потому что клиент не наш.