Урок 11

Платформенные различия

iOS и Android отличаются. Иногда нужно писать разный код.

Platform

import { Platform } from 'react-native';

Platform.OS;           // 'ios' | 'android' | 'web'
Platform.Version;      // номер версии ОС
Platform.isPad;        // iPad (iOS)
Platform.isTV;         // Apple TV или Android TV

Условные стили

const styles = StyleSheet.create({
    header: {
        paddingTop: Platform.OS === 'ios' ? 50 : 30,
    },
});

Platform.select

const styles = StyleSheet.create({
    shadow: Platform.select({
        ios: {
            shadowColor: '#000',
            shadowOffset: { width: 0, height: 2 },
            shadowOpacity: 0.1,
            shadowRadius: 4,
        },
        android: {
            elevation: 4,
        },
        default: {},
    }),
});

Разные компоненты

function Component() {
    if (Platform.OS === 'ios') {
        return <IOSComponent />;
    }
    return <AndroidComponent />;
}

Файлы по платформам

Один и тот же файл с разными расширениями:

components/
├── Button.ios.tsx
├── Button.android.tsx
└── Button.tsx         # fallback для других платформ

При импорте import { Button } from './components/Button' React Native сам выберет подходящий файл.

Ключевые отличия

Навигация

iOS — кнопка «Назад» в хедере. Android — системная кнопка «Назад».

Клавиатура

iOS — есть кнопка «Готово». Android — нет. Разное поведение keyboardType.

Статус-бар

iOS — SafeAreaView для учёта «челки». Android — StatusBar.

import { SafeAreaView } from 'react-native-safe-area-context';

<SafeAreaView style={{ flex: 1 }}>
    {/* контент */}
</SafeAreaView>

Разрешения

iOS — запрашивает разрешения через модальные окна. Android — через диалоги с другим UX.

Кнопка «Назад» (Android)

import { BackHandler } from 'react-native';
import { useEffect } from 'react';

useEffect(() => {
    const sub = BackHandler.addEventListener('hardwareBackPress', () => {
        if (hasUnsavedChanges) {
            Alert.alert('Выйти?', 'Изменения не сохранятся', [
                { text: 'Отмена', style: 'cancel' },
                { text: 'Выйти', onPress: () => navigation.goBack() },
            ]);
            return true; // обработано
        }
        return false; // стандартное поведение
    });

    return () => sub.remove();
}, [hasUnsavedChanges]);

Scroll indicators

  • iOS: showsVerticalScrollIndicator
  • Android: тоже работает, но визуально отличается

Тени

  • iOS: shadowColor, shadowOffset, shadowOpacity, shadowRadius
  • Android: elevation

Safe area

«Челка», домашняя кнопка — react-native-safe-area-context:

npm install react-native-safe-area-context
import { SafeAreaView } from 'react-native-safe-area-context';

<SafeAreaView edges={['top', 'bottom']}>
    {/* контент */}
</SafeAreaView>

StatusBar

import { StatusBar } from 'expo-status-bar';

<StatusBar style="auto" />
<StatusBar style="light" />
<StatusBar style="dark" />
<StatusBar hidden />

Если ты уже знаешь React

В вебе — один браузер. В мобильной разработке — две платформы с разным поведением. Иногда придётся писать разный код.

Итоги

  • Platform.OS для проверки
  • Platform.select для стилей
  • Файлы .ios.tsx и .android.tsx
  • SafeAreaView для «челки»
  • BackHandler для Android
  • Тени разные