名称: react-native-platform 用户可调用: false 描述: 用于在React Native中处理iOS和Android的平台特定代码。涵盖Platform API、平台特定组件、原生模块和跨平台最佳实践。 允许工具:
- Read
- Write
- Edit
- Bash
- Grep
- Glob
React Native 平台API
当为iOS和Android编写平台特定代码、处理平台差异和访问原生功能时使用此技能。
关键概念
平台检测
检测当前平台:
import { Platform } from 'react-native';
// 简单检查
if (Platform.OS === 'ios') {
console.log('运行在iOS上');
} else if (Platform.OS === 'android') {
console.log('运行在Android上');
}
// 平台选择
const styles = StyleSheet.create({
container: {
...Platform.select({
ios: {
paddingTop: 20,
},
android: {
paddingTop: 0,
},
}),
},
});
// 获取平台版本
console.log(`Android API 级别: ${Platform.Version}`); // Android
console.log(`iOS 版本: ${Platform.Version}`); // iOS
平台特定文件
创建平台特定文件:
components/
Button.ios.tsx # iOS实现
Button.android.tsx # Android实现
Button.tsx # 共享/默认实现
// Button.ios.tsx
import React from 'react';
import { View, Text } from 'react-native';
export default function Button({ title, onPress }: ButtonProps) {
return (
<View style={{ /* iOS特定样式 */ }}>
<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特定样式 */ }}>
<Text>{title}</Text>
</View>
);
}
// 使用 - React Native自动选择正确文件
import Button from './components/Button';
平台特定组件
使用平台特定组件:
import {
Platform,
StatusBar,
TouchableOpacity,
TouchableNativeFeedback,
View,
} from 'react-native';
// 状态栏
<StatusBar
barStyle={Platform.OS === 'ios' ? 'dark-content' : 'light-content'}
backgroundColor={Platform.OS === 'android' ? '#007AFF' : undefined}
/>
// 可触摸组件
const Touchable = Platform.OS === 'android'
? TouchableNativeFeedback
: TouchableOpacity;
<Touchable onPress={() => console.log('已按下')}>
<View>
<Text>按我</Text>
</View>
</Touchable>
最佳实践
使用Platform.select进行内联差异处理
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',
}),
},
});
处理安全区域
正确处理刘海屏和安全区域:
import { SafeAreaView, Platform, StyleSheet } from 'react-native';
export default function App() {
return (
<SafeAreaView style={styles.container}>
{/* 内容 */}
</SafeAreaView>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
// Android状态栏额外内边距
paddingTop: Platform.OS === 'android' ? 25 : 0,
},
});
权限处理
请求平台特定权限:
import { Platform, PermissionsAndroid, Alert } from 'react-native';
async function requestCameraPermission() {
if (Platform.OS === 'android') {
try {
const granted = await PermissionsAndroid.request(
PermissionsAndroid.PERMISSIONS.CAMERA,
{
title: '相机权限',
message: '应用需要访问您的相机',
buttonNeutral: '稍后询问',
buttonNegative: '取消',
buttonPositive: '确定',
}
);
return granted === PermissionsAndroid.RESULTS.GRANTED;
} catch (err) {
console.warn(err);
return false;
}
} else {
// iOS权限通过Info.plist处理
return true;
}
}
返回按钮处理(Android)
处理Android硬件返回按钮:
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]);
}
// 使用
function MyScreen() {
useBackHandler(() => {
Alert.alert('退出应用', '确定要退出吗?', [
{ text: '取消', style: 'cancel' },
{ text: '退出', onPress: () => BackHandler.exitApp() },
]);
return true; // 阻止默认行为
});
return <View />;
}
常见模式
自适应组件
创建适应平台的组件:
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',
},
});
平台特定导航
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特定
...(Platform.OS === 'android' && {
animation: 'slide_from_right',
}),
// iOS特定
...(Platform.OS === 'ios' && {
headerLargeTitle: true,
}),
}}
>
<Stack.Screen name="Home" component={HomeScreen} />
</Stack.Navigator>
);
}
链接到原生应用
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('错误', '无法打开地图应用');
}
}
async function openPhoneDialer(phoneNumber: string) {
const url = `tel:${phoneNumber}`;
const supported = await Linking.canOpenURL(url);
if (supported) {
await Linking.openURL(url);
} else {
Alert.alert('错误', '无法打开电话拨号器');
}
}
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('错误', '无法打开邮件客户端');
}
}
键盘避免视图
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="姓名"
/>
<TextInput
style={styles.input}
placeholder="邮箱"
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,
},
});
状态栏配置
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 }}>
{/* 应用内容 */}
</SafeAreaView>
</>
);
}
反模式
不要仅使用平台检查进行样式设置
// 不好 - 内联平台检查
<View style={{
padding: Platform.OS === 'ios' ? 12 : 16,
marginTop: Platform.OS === 'android' ? 20 : 0,
}}>
<Text>内容</Text>
</View>
// 好 - 在StyleSheet中使用Platform.select
const styles = StyleSheet.create({
container: {
...Platform.select({
ios: {
padding: 12,
marginTop: 0,
},
android: {
padding: 16,
marginTop: 20,
},
}),
},
});
<View style={styles.container}>
<Text>内容</Text>
</View>
不要忘记Android返回按钮
// 不好 - 无返回按钮处理
function MyScreen() {
return <View />;
}
// 好 - 处理返回按钮
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 />;
}
不要硬编码平台值
// 不好 - 魔术数字
<View style={{ paddingTop: 20 }}>
<Text>内容</Text>
</View>
// 好 - 使用常量或安全区域
import { useSafeAreaInsets } from 'react-native-safe-area-context';
function MyComponent() {
const insets = useSafeAreaInsets();
return (
<View style={{ paddingTop: insets.top }}>
<Text>内容</Text>
</View>
);
}
不要假设平台功能
// 不好 - 假设功能存在
await Linking.openURL('mailto:test@example.com');
// 好 - 检查是否支持
const url = 'mailto:test@example.com';
const supported = await Linking.canOpenURL(url);
if (supported) {
await Linking.openURL(url);
} else {
Alert.alert('错误', '邮件客户端不可用');
}
相关技能
- react-native-components: 构建平台感知组件
- react-native-styling: 平台特定样式
- react-native-native-modules: 构建自定义原生模块