Различия iOS и Android, о которых спрашивают
«Один код на две платформы» — правда лишь отчасти. Интервьюер обязательно спросит, где именно платформы расходятся.
Platform-specific код — нормальная часть React Native. Вопрос не в том, есть ли он, а в том, аккуратно ли он изолирован.
Вопрос
«Какие различия между iOS и Android приходилось учитывать? Как организовать платформенный код?»
Что на самом деле проверяет интервьюер
Реальный опыт. Человек, который довёл хотя бы одно приложение до сторов, назовёт эти различия сходу — они бьют по рукам на первой же неделе. Теоретик расскажет про Platform.OS и остановится.
Развёрнутый ответ
Три способа развести платформы
import { Platform, StyleSheet } from 'react-native';
// 1. Точечная проверка
const paddingTop = Platform.OS === 'ios' ? 20 : 0;
// 2. Platform.select — самый читаемый вариант для стилей
const styles = StyleSheet.create({
card: {
backgroundColor: '#fff',
borderRadius: 12,
...Platform.select({
ios: {
shadowColor: '#000',
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.15,
shadowRadius: 6,
},
android: { elevation: 4 },
}),
},
});
// 3. Проверка версии ОС — например, для API, появившихся в Android 13
const canAskNotifications = Platform.OS === 'android' && Platform.Version >= 33;
Четвёртый способ — отдельные файлы. Metro сам выберет нужный:
components/
Picker.ios.tsx
Picker.android.tsx
Picker.tsx # запасной вариант, например для web
# импорт остаётся общим:
# import Picker from './components/Picker';
Различия, которые встречаются в каждом проекте
| Тема | iOS | Android |
| Тени | shadow* | elevation |
| Кнопка «Назад» | жест свайпа от края | аппаратная кнопка, BackHandler |
| Клавиатура | KeyboardAvoidingView с padding | чаще height или настройки windowSoftInputMode |
| Ripple при нажатии | нет, обычно меняют прозрачность | android_ripple у Pressable |
| Шрифты | по имени семейства | по имени файла шрифта |
| Разрешения | Info.plist и запрос при первом использовании | AndroidManifest и рантайм-запрос |
| Статус-бар | прозрачный, контент под ним | занимает место, есть translucent |
Безопасные зоны
Вырез камеры, «чёлка», индикатор жеста снизу, у Android — вырезы и навигационная панель. Вручную это не считают: берут react-native-safe-area-context.
import { useSafeAreaInsets } from 'react-native-safe-area-context';
function Screen({ children }) {
const insets = useSafeAreaInsets();
return (
<View style={{ flex: 1, paddingTop: insets.top, paddingBottom: insets.bottom }}>
{children}
</View>
);
}
Обратная кнопка Android
import { useEffect } from 'react';
import { BackHandler } from 'react-native';
useEffect(() => {
const sub = BackHandler.addEventListener('hardwareBackPress', () => {
if (isModalOpen) {
closeModal();
return true; // событие обработано, экран не закрывается
}
return false; // поведение по умолчанию
});
return () => sub.remove();
}, [isModalOpen]);
Клавиатура
<KeyboardAvoidingView
style={{ flex: 1 }}
behavior={Platform.OS === 'ios' ? 'padding' : undefined}
keyboardVerticalOffset={headerHeight}
>
{form}
</KeyboardAvoidingView>
На Android чаще помогает настройка android:windowSoftInputMode="adjustResize" в манифесте, а не сам компонент. Хороший ответ включает эту деталь.
Как это организовать в проекте
Главный принцип — не рассыпать Platform.OS по всему коду. Платформенные различия прячут внутрь общих компонентов дизайн-системы: экраны используют <Card> и <Screen>, а уже внутри них решается, тень это или elevation. Это то, что интервьюер хочет услышать от middle+.
Типичные ошибки кандидатов
- Знают только
Platform.OSи не слышали проPlatform.selectи файлы с платформенным расширением. - Забывают, что
elevationна Android не только рисует тень, но и влияет на порядок наложения. - Тестируют только на iPhone симуляторе и потом «внезапно» находят проблемы с клавиатурой и вырезами на Android.
- Не упоминают разрешения, хотя рантайм-запросы на Android — источник половины багов в релизе.
Как ответить кратко
«Развожу платформы четырьмя способами: Platform.OS для точечных проверок, Platform.select для стилей, Platform.Version для версионных API и отдельные файлы .ios и .android, которые Metro подставляет сам. Регулярно расходятся тени (shadow против elevation), безопасные зоны — беру safe-area-context, клавиатура: KeyboardAvoidingView на iOS и adjustResize на Android, аппаратная кнопка «Назад» через BackHandler, ripple при нажатии, шрифты и разрешения. Стараюсь прятать различия внутрь компонентов дизайн-системы, а не размазывать проверки по экранам.»