jutsu-react-native:react-native-platform

React Native Platform APIs

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "jutsu-react-native:react-native-platform" with this command: npx skills add thebushidocollective/han/thebushidocollective-han-jutsu-react-native-react-native-platform

React Native Platform APIs

Use this skill when writing platform-specific code for iOS and Android, handling platform differences, and accessing native functionality.

Key Concepts

Platform Detection

Detect the current platform:

import { Platform } from 'react-native';

// Simple check if (Platform.OS === 'ios') { console.log('Running on iOS'); } else if (Platform.OS === 'android') { console.log('Running on Android'); }

// Platform.select const styles = StyleSheet.create({ container: { ...Platform.select({ ios: { paddingTop: 20, }, android: { paddingTop: 0, }, }), }, });

// Get platform version console.log(Android API Level: ${Platform.Version}); // Android console.log(iOS Version: ${Platform.Version}); // iOS

Platform-Specific Files

Create platform-specific files:

components/ Button.ios.tsx # iOS implementation Button.android.tsx # Android implementation Button.tsx # Shared/default implementation

// Button.ios.tsx import React from 'react'; import { View, Text } from 'react-native';

export default function Button({ title, onPress }: ButtonProps) { return ( <View style={{ /* iOS-specific styles */ }}> <Text>{title}</Text> </View> ); }

// Button.android.tsx import React from 'react'; import { View, Text } from 'react-native';

export default function Button({ title, onPress }: ButtonProps) { return ( <View style={{ /* Android-specific styles */ }}> <Text>{title}</Text> </View> ); }

// Usage - React Native automatically picks the right file import Button from './components/Button';

Platform-Specific Components

Use platform-specific components:

import { Platform, StatusBar, TouchableOpacity, TouchableNativeFeedback, View, } from 'react-native';

// StatusBar <StatusBar barStyle={Platform.OS === 'ios' ? 'dark-content' : 'light-content'} backgroundColor={Platform.OS === 'android' ? '#007AFF' : undefined} />

// Touchable components const Touchable = Platform.OS === 'android' ? TouchableNativeFeedback : TouchableOpacity;

<Touchable onPress={() => console.log('Pressed')}> <View> <Text>Press Me</Text> </View> </Touchable>

Best Practices

Use Platform.select for Inline Differences

import { Platform, StyleSheet } from 'react-native';

const styles = StyleSheet.create({ button: { padding: Platform.select({ ios: 12, android: 16, default: 12, }), fontFamily: Platform.select({ ios: 'System', android: 'Roboto', default: 'System', }), }, });

Handle Safe Areas

Properly handle notches and safe areas:

import { SafeAreaView, Platform, StyleSheet } from 'react-native';

export default function App() { return ( <SafeAreaView style={styles.container}> {/* Content */} </SafeAreaView> ); }

const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: '#fff', // Additional padding for Android status bar paddingTop: Platform.OS === 'android' ? 25 : 0, }, });

Permissions Handling

Request platform-specific permissions:

import { Platform, PermissionsAndroid, Alert } from 'react-native';

async function requestCameraPermission() { if (Platform.OS === 'android') { try { const granted = await PermissionsAndroid.request( PermissionsAndroid.PERMISSIONS.CAMERA, { title: 'Camera Permission', message: 'App needs access to your camera', buttonNeutral: 'Ask Me Later', buttonNegative: 'Cancel', buttonPositive: 'OK', } ); return granted === PermissionsAndroid.RESULTS.GRANTED; } catch (err) { console.warn(err); return false; } } else { // iOS permissions handled via Info.plist return true; } }

Back Button Handling (Android)

Handle Android hardware back button:

import { useEffect } from 'react'; import { BackHandler, Platform, Alert } from 'react-native';

function useBackHandler(handler: () => boolean) { useEffect(() => { if (Platform.OS !== 'android') return;

const backHandler = BackHandler.addEventListener(
  'hardwareBackPress',
  handler
);

return () => backHandler.remove();

}, [handler]); }

// Usage function MyScreen() { useBackHandler(() => { Alert.alert('Exit App', 'Are you sure you want to exit?', [ { text: 'Cancel', style: 'cancel' }, { text: 'Exit', onPress: () => BackHandler.exitApp() }, ]); return true; // Prevent default behavior });

return <View />; }

Common Patterns

Adaptive Components

Create components that adapt to platform:

import React from 'react'; import { Platform, View, Text, StyleSheet, TouchableOpacity, TouchableNativeFeedback, } from 'react-native';

interface ButtonProps { title: string; onPress: () => void; }

export default function AdaptiveButton({ title, onPress }: ButtonProps) { if (Platform.OS === 'android') { return ( <TouchableNativeFeedback onPress={onPress} background={TouchableNativeFeedback.Ripple('#fff', false)} > <View style={styles.androidButton}> <Text style={styles.androidText}>{title}</Text> </View> </TouchableNativeFeedback> ); }

return ( <TouchableOpacity onPress={onPress} activeOpacity={0.8}> <View style={styles.iosButton}> <Text style={styles.iosText}>{title}</Text> </View> </TouchableOpacity> ); }

const styles = StyleSheet.create({ androidButton: { backgroundColor: '#2196F3', padding: 16, borderRadius: 4, elevation: 4, }, androidText: { color: '#fff', fontSize: 16, fontWeight: 'bold', textAlign: 'center', textTransform: 'uppercase', }, iosButton: { backgroundColor: '#007AFF', padding: 14, borderRadius: 8, }, iosText: { color: '#fff', fontSize: 17, fontWeight: '600', textAlign: 'center', }, });

Platform-Specific Navigation

import { Platform } from 'react-native'; import { createNativeStackNavigator } from '@react-navigation/native-stack';

const Stack = createNativeStackNavigator();

export default function AppNavigator() { return ( <Stack.Navigator screenOptions={{ headerStyle: { backgroundColor: Platform.select({ ios: '#fff', android: '#007AFF', }), }, headerTintColor: Platform.select({ ios: '#007AFF', android: '#fff', }), headerTitleStyle: { fontWeight: Platform.select({ ios: '600', android: 'bold', }), }, // Android-specific ...(Platform.OS === 'android' && { animation: 'slide_from_right', }), // iOS-specific ...(Platform.OS === 'ios' && { headerLargeTitle: true, }), }} > <Stack.Screen name="Home" component={HomeScreen} /> </Stack.Navigator> ); }

Linking to Native Apps

import { Linking, Platform, Alert } from 'react-native';

async function openMaps(address: string) { const url = Platform.select({ ios: maps://app?address=${encodeURIComponent(address)}, android: geo:0,0?q=${encodeURIComponent(address)}, });

if (!url) return;

const supported = await Linking.canOpenURL(url);

if (supported) { await Linking.openURL(url); } else { Alert.alert('Error', 'Cannot open maps application'); } }

async function openPhoneDialer(phoneNumber: string) { const url = tel:${phoneNumber}; const supported = await Linking.canOpenURL(url);

if (supported) { await Linking.openURL(url); } else { Alert.alert('Error', 'Cannot open phone dialer'); } }

async function openEmail(email: string, subject?: string) { const url = mailto:${email}${subject ? ?subject=${encodeURIComponent(subject)} : ''}; const supported = await Linking.canOpenURL(url);

if (supported) { await Linking.openURL(url); } else { Alert.alert('Error', 'Cannot open email client'); } }

Keyboard Avoiding View

import React from 'react'; import { KeyboardAvoidingView, Platform, ScrollView, TextInput, StyleSheet, } from 'react-native';

export default function FormScreen() { return ( <KeyboardAvoidingView style={styles.container} behavior={Platform.OS === 'ios' ? 'padding' : 'height'} keyboardVerticalOffset={Platform.OS === 'ios' ? 64 : 0} > <ScrollView> <TextInput style={styles.input} placeholder="Name" /> <TextInput style={styles.input} placeholder="Email" keyboardType="email-address" /> </ScrollView> </KeyboardAvoidingView> ); }

const styles = StyleSheet.create({ container: { flex: 1, }, input: { height: 50, borderWidth: 1, borderColor: '#ccc', borderRadius: 8, paddingHorizontal: 16, marginVertical: 8, }, });

Status Bar Configuration

import React from 'react'; import { StatusBar, Platform, SafeAreaView } from 'react-native';

export default function App() { return ( <> <StatusBar barStyle={Platform.select({ ios: 'dark-content', android: 'light-content', })} backgroundColor={Platform.OS === 'android' ? '#007AFF' : undefined} translucent={Platform.OS === 'android'} /> <SafeAreaView style={{ flex: 1 }}> {/* App content */} </SafeAreaView> </> ); }

Anti-Patterns

Don't Use Platform Checks for Styling Only

// Bad - Inline platform checks <View style={{ padding: Platform.OS === 'ios' ? 12 : 16, marginTop: Platform.OS === 'android' ? 20 : 0, }}> <Text>Content</Text> </View>

// Good - Use Platform.select in StyleSheet const styles = StyleSheet.create({ container: { ...Platform.select({ ios: { padding: 12, marginTop: 0, }, android: { padding: 16, marginTop: 20, }, }), }, });

<View style={styles.container}> <Text>Content</Text> </View>

Don't Forget Android Back Button

// Bad - No back button handling function MyScreen() { return <View />; }

// Good - Handle back button function MyScreen({ navigation }: any) { useEffect(() => { if (Platform.OS !== 'android') return;

const backHandler = BackHandler.addEventListener(
  'hardwareBackPress',
  () => {
    navigation.goBack();
    return true;
  }
);

return () => backHandler.remove();

}, [navigation]);

return <View />; }

Don't Hardcode Platform Values

// Bad - Magic numbers <View style={{ paddingTop: 20 }}> <Text>Content</Text> </View>

// Good - Use constants or safe area import { useSafeAreaInsets } from 'react-native-safe-area-context';

function MyComponent() { const insets = useSafeAreaInsets();

return ( <View style={{ paddingTop: insets.top }}> <Text>Content</Text> </View> ); }

Don't Assume Platform Features

// Bad - Assuming feature exists await Linking.openURL('mailto:test@example.com');

// Good - Check if supported const url = 'mailto:test@example.com'; const supported = await Linking.canOpenURL(url);

if (supported) { await Linking.openURL(url); } else { Alert.alert('Error', 'Email client not available'); }

Related Skills

  • react-native-components: Building platform-aware components

  • react-native-styling: Platform-specific styling

  • react-native-native-modules: Building custom native modules

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

General

android-jetpack-compose

No summary provided by upstream source.

Repository SourceNeeds Review
General

fastapi-async-patterns

No summary provided by upstream source.

Repository SourceNeeds Review
General

storybook-story-writing

No summary provided by upstream source.

Repository SourceNeeds Review