Нативные модули, отладка и публикация в сторы
Завершающий блок собеседования: что делать, когда JS не хватает, и как приложение попадает к пользователю.
Нативный модуль — кусок кода на Swift, Kotlin, Objective-C или Java, доступный из JS. В новой архитектуре он описывается спецификацией и подключается как TurboModule.
Вопрос
«Приходилось ли писать нативные модули и в каких случаях? Как отлаживаете и профилируете приложение? Как устроен процесс релиза?»
Что на самом деле проверяет интервьюер
Дошли ли вы до конца цикла разработки. Многие кандидаты уверенно говорят про хуки, но теряются на вопросе «как ваша сборка попадает в TestFlight». Ответ показывает уровень самостоятельности.
Развёрнутый ответ
Когда нативный модуль действительно нужен
- Нужен системный API, которого нет в JS: HealthKit, виджеты, работа с NFC, специфичные датчики.
- Требуется интеграция нативного SDK: платежи банка, биометрия конкретного вендора, карты, аналитика.
- Тяжёлая обработка, которую нельзя держать в JS-потоке: обработка кадров камеры, аудио, шифрование больших файлов.
- Нужно фоновое выполнение по правилам платформы.
Что не повод писать нативный код: желание «ускорить JS-логику» — сама по себе передача данных туда и обратно съест выигрыш.
// Спецификация TurboModule — источник правды для Codegen
import type { TurboModule } from 'react-native';
import { TurboModuleRegistry } from 'react-native';
export interface Spec extends TurboModule {
isBiometryAvailable(): boolean; // синхронно
authenticate(reason: string): Promise<boolean>; // асинхронно
}
export default TurboModuleRegistry.getEnforcing<Spec>('Biometry');
Полезно упомянуть, что перед написанием своего модуля стоит проверить экосистему: для большинства задач уже есть поддерживаемая библиотека, и «написал сам» здесь не достоинство, а риск сопровождения.
Отладка
| Инструмент | Для чего |
| React Native DevTools (Hermes) | консоль, точки останова, профиль JS |
| React DevTools Profiler | дерево компонентов и причины рендеров |
| Perf Monitor из dev-меню | FPS JS- и UI-потоков |
| Xcode Instruments и Android Studio Profiler | память, CPU, нативные утечки |
| Sentry и подобные | ошибки и падения у реальных пользователей |
| Flipper или Reactotron | сеть, хранилище, логи (по вкусу команды) |
Важная деталь для ответа: измеряют только release-сборку на реальном устройстве, желательно на слабом Android. Debug-сборка не минифицирована и содержит проверки разработки.
Читаемые падения в проде
Стек-трейс из релизной сборки бесполезен без source maps: код минифицирован, а Hermes выполняет байт-код. Загрузка source maps в систему мониторинга при каждой сборке — обязательный шаг CI, о котором часто забывают.
Релиз
# типичный конвейер в CI
yarn lint && yarn test
yarn tsc --noEmit
# сборка через EAS (Expo) или нативными командами
eas build --platform ios --profile production
eas submit --platform ios --latest
# для «голого» проекта
cd android && ./gradlew bundleRelease # .aab для Google Play
xcodebuild -workspace App.xcworkspace -scheme App -configuration Release archive
Что стоит назвать словами:
- Подписи: keystore для Android, сертификаты и provisioning profiles для iOS — хранятся в CI, а не на ноутбуке одного разработчика.
- Версионирование:
versionNameиversionCodeна Android,CFBundleShortVersionStringи build number на iOS. Номер сборки обязан расти. - Тестирование: TestFlight на iOS, internal и closed testing в Google Play.
- Раскатка: staged rollout в Google Play и phased release в App Store — чтобы поймать падения на 1% пользователей, а не на всех.
- Ревью: у Apple оно ручное; разрешения нужно объяснять в Info.plist, иначе приложение отклонят.
OTA-обновления
CodePush и EAS Update доставляют новый JS-бандл и ассеты без похода в стор — это спасает при срочных фиксах. Ограничение принципиальное: нативную часть так обновить нельзя. Добавили библиотеку с нативным кодом или подняли версию React Native — нужна новая сборка и публикация. И политика магазинов не разрешает менять OTA-обновлением суть приложения.
Типичные ошибки кандидатов
- Обещают, что через CodePush можно выкатить «вообще любое обновление».
- Измеряют производительность в debug-сборке на флагманском телефоне и делают выводы.
- Не знают про source maps и потом не могут разобрать реальный стек падения.
- Пишут собственный нативный модуль там, где есть зрелая библиотека, — и берут на себя её поддержку.
Как ответить кратко
«Нативный модуль пишу, когда нужен системный API или SDK без JS-обёртки либо тяжёлая работа вне JS-потока; в новой архитектуре это TurboModule со спецификацией на TypeScript, по которой Codegen генерирует обвязку. Сначала всегда проверяю, нет ли готовой библиотеки. Отлаживаю через React Native DevTools и Profiler, потоки смотрю в Perf Monitor, память и CPU — в Instruments и Android Studio Profiler, а выводы делаю только по release-сборке на слабом устройстве. Падения собираю в Sentry с загрузкой source maps. Релиз: CI гоняет линт, типы и тесты, собирает через EAS или Gradle и Xcode, подписи лежат в CI, дальше TestFlight и internal testing, затем поэтапная раскатка. Срочные JS-фиксы — через OTA, но нативные изменения так не доставить.»