项目初始化
创建新应用
如果之前安装了全局的 react-native-cli 包,请先将其卸载,以避免潜在问题:
npm uninstall -g react-native-cli @react-native-community/cli
接下来,使用 React Native Community CLI 生成一个新项目。例如,创建一个名为 "MyApp" 的项目:
npx @react-native-community/cli@latest init MyApp
如果你是在现有应用中集成 React Native,或项目中已安装 Expo,则不需要此步骤。也可以使用第三方 CLI 来设置 React Native 应用。
在初始化安装阶段,请勿中断过程。如果在 iOS 上遇到问题,可以尝试通过以下步骤重新安装依赖项:
cd ios
bundle install
bundle exec pod install
若希望使用特定 React Native 版本创建项目,可以使用 --version 参数:
npx @react-native-community/cli@X.XX.X init MyApp --version X.XX.X
此外,--template 参数可用于基于自定义模板启动项目。
启动 Metro
Metro 是 React Native 的 JavaScript 构建工具。要启动 Metro 开发服务器,请在项目文件夹中运行:
yarn start
Metro 类似于 Web 开发中的 Vite 或 webpack,但专为 React Native 设计,例如使用 Babel 转换 JSX 等语法。
启动应用程序
保持 Metro Bundler 在独立终端中运行,然后在项目文件夹中打开新终端并执行:
yarn android
如果设置正确,应用将很快在 Android 模拟器中运行。你也可以直接通过 Android Studio 启动应用。
工程化说明
创建项目后,建议优化目录结构如下:
MyApp/
├── android/ # Android 原生代码
├── ios/ # iOS 原生代码
├── node_modules/ # npm 依赖包
├── src/ # 应用源代码
│ ├── components/ # 可复用组件
│ ├── screens/ # 页面组件
│ ├── navigation/ # 路由导航
│ ├── assets/ # 静态资源(图片、字体等)
│ ├── services/ # 网络请求或其他服务
│ └── utils/ # 工具函数
├── App.js # 应用主入口
├── package.json # npm 配置文件
├── babel.config.js # Babel 配置
├── metro.config.js # Metro bundler 配置
└── index.js # React Native 入口文件
重要文件与目录包括:
- android/ 和 ios/:包含各自平台的原生代码和配置,可用于修改平台特性或添加依赖。
- src/:应用的主要源代码目录,推荐将所有逻辑和组件组织于此。
- components/:存放可复用的 UI 组件。
- screens/:应用的各个页面组件。
- navigation/:处理路由和导航逻辑,通常使用库如 @react-navigation/native。
- assets/:存放图片、字体等静态资源。
- services/:处理网络请求或 API 调用。
- utils/:存放通用工具函数,如日期格式化或字符串处理。
- App.js:应用的主组件和入口点。
- package.json:定义项目依赖和脚本。
- babel.config.js:Babel 配置文件,用于代码转译。
- metro.config.js:Metro bundler 的配置文件,可自定义打包行为。
- index.js:React Native 应用的入口文件,用于注册主组件。
项目配置方面,可以使用 npm 或 yarn 管理依赖,在 iOS 和 Android 文件夹内配置环境设置(如 API 地址),并使用 StyleSheet 或样式库(如 styled-components)管理样式。
关于 Expo 框架
Expo 可以简化开发,但会引入额外学习成本。对于初学者,建议直接使用原生 React Native 进行开发,以便更深入地学习。Expo 的 GitHub 链接可供参考。
常用组件与 API
常用组件
React Native 提供了多种内置组件用于快速构建用户界面。
View:最基本组件,用于构建 UI 布局,可容纳其他组件并支持样式和事件处理。它类似于 Web 中的 div。
import { View } from 'react-native';
const MyComponent = () => {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
{/* 其他组件 */}
</View>
);
};
Text:用于显示文本,支持多种样式如字体、颜色和大小。
import { Text } from 'react-native';
const MyText = () => {
return <Text style={{ fontSize: 20, color: 'blue' }}>Hello, React Native!</Text>;
};
Image:用于显示图片,支持本地和网络图片源。
import { Image } from 'react-native';
const MyImage = () => {
return <Image source={{ uri: 'https://example.com/image.png' }} style={{ width: 100, height: 100 }} />;
};
ScrollView:创建可滚动视图,适用于内容较多的场景。
import { ScrollView, Text } from 'react-native';
const MyScrollView = () => {
return (
<ScrollView>
<Text>Item 1</Text>
<Text>Item 2</Text>
<Text>Item 3</Text>
</ScrollView>
);
};
TextInput:接收用户输入,可设置占位符和样式。
import { TextInput } from 'react-native';
const MyTextInput = () => {
return <TextInput style={{ height: 40, borderColor: 'gray', borderWidth: 1 }} placeholder="Type here" />;
};
Button:创建按钮并支持点击事件。
import { Button } from 'react-native';
const MyButton = () => {
return <Button title="Click Me" onPress={() => alert('Button pressed!')} />;
};
FlatList:高效渲染长列表,支持性能优化。
import { FlatList, Text } from 'react-native';
const DATA = [
{ id: '1', title: 'Item 1' },
{ id: '2', title: 'Item 2' },
{ id: '3', title: 'Item 3' },
];
const MyFlatList = () => {
return <FlatList data={DATA} renderItem={({ item }) => <Text>{item.title}</Text>} keyExtractor={item => item.id} />;
};
TouchableOpacity:实现可点击元素,支持透明度变化反馈。
import { TouchableOpacity, Text } from 'react-native';
const MyTouchable = () => {
return (
<TouchableOpacity onPress={() => alert('Tapped!')}>
<Text style={{ fontSize: 20 }}>Tap Me</Text>
</TouchableOpacity>
);
};
Modal:创建模态窗口,适用于对话框等需要用户注意的场景。
import { Modal, View, Text, Button } from 'react-native';
const MyModal = () => {
const [modalVisible, setModalVisible] = useState(false);
return (
<View>
<Button title="Show Modal" onPress={() => setModalVisible(true)} />
<Modal transparent={true} visible={modalVisible} animationType="slide">
<View style={{ marginTop: 50 }}>
<Text>This is a Modal!</Text>
<Button title="Hide Modal" onPress={() => setModalVisible(false)} />
</View>
</Modal>
</View>
);
};
SafeAreaView:确保内容显示在设备安全区域内,常用于处理刘海屏等特殊屏幕。
<SafeAreaView style={backgroundStyle}>
<StatusBar />
</SafeAreaView>
样式表
在 React Native 中,样式管理通过 StyleSheet API 实现,它允许创建样式对象并直接应用到组件,提高可读性和性能。
import { StyleSheet, View, Text } from 'react-native';
const styles = StyleSheet.create({
container: { flex: 1, justifyContent: 'center', alignItems: 'center', backgroundColor: '#f5fcff' },
text: { fontSize: 20, color: 'blue' },
});
const MyComponent = () => {
return (
<View style={styles.container}>
<Text style={styles.text}>Hello, React Native!</Text>
</View>
);
};
StyleSheet.create 方法在内部优化样式,避免每次渲染时重新计算。
主题实现可以通过 React Context API 动态切换样式。例如,创建主题上下文:
import React, { createContext, useContext, useState } from 'react';
const ThemeContext = createContext();
const ThemeProvider = ({ children }) => {
const [theme, setTheme] = useState('light');
const toggleTheme = () => setTheme(prevTheme => (prevTheme === 'light' ? 'dark' : 'light'));
return <ThemeContext.Provider value={{ theme, toggleTheme }}>{children}</ThemeContext.Provider>;
};
const useTheme = () => useContext(ThemeContext);
在组件中使用主题:
const ThemedComponent = () => {
const { theme } = useTheme();
const styles = StyleSheet.create({
container: { flex: 1, justifyContent: 'center', alignItems: 'center', backgroundColor: theme === 'light' ? '#fff' : '#333' },
text: { color: theme === 'light' ? '#000' : '#fff' },
});
return (
<View style={styles.container}>
<Text style={styles.text}>Current Theme: {theme}</Text>
</View>
);
};
StyleSheet 的原理涉及将 JavaScript 样式对象映射到原生代码,通过缓存和优化属性(如 flex、padding)来提高性能。样式合并可通过 StyleSheet.flatten 处理,而跨平台支持则使用 Platform 模块:
import { Platform, StyleSheet } from 'react-native';
const styles = StyleSheet.create({
button: { backgroundColor: Platform.OS === 'ios' ? 'blue' : 'green', padding: 10 },
});
路由处理
React Navigation 是常用的路由库,通过 @react-navigation 系列包管理导航。例如,安装依赖后,可以创建底部标签导航和堆栈导航。
首先,创建底部标签导航:
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
const TabBar = createBottomTabNavigator();
function BottomBar() {
return (
<TabBar.Navigator screenOptions={{ headerShown: false }}>
<TabBar.Screen name="TabHome" component={HomeScreen} options={{ tabBarLabel: '首页' }} />
<TabBar.Screen name="TabOther" component={DetailScreen} options={{ tabBarLabel: '其他' }} />
</TabBar.Navigator>
);
}
然后,创建堆栈导航作为根导航器:
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import { NavigationContainer } from '@react-navigation/native';
const Stack = createNativeStackNavigator();
function Navigator() {
return (
<NavigationContainer>
<Stack.Navigator
screenOptions={{
headerTitleAlign: 'center',
headerBackTitleVisible: false,
gestureEnabled: true,
gestureDirection: 'horizontal',
headerStyle: { backgroundColor: Colors.primary },
}}>
<Stack.Screen name="BottomBar" component={BottomBar} />
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="Details" component={DetailScreen} />
<Stack.Screen name="Topics" component={TopicsScreen} />
</Stack.Navigator>
</NavigationContainer>
);
}
导航状态由 React Navigation 自动管理,用户可以通过 navigation.navigate 方法在屏幕间切换。对于 iOS,可能需要执行 npx pod-install ios 或进入 ios 文件夹运行 pod install 来安装原生依赖。
常用 API
AsyncStorage:用于本地存储简单数据。
import AsyncStorage from '@react-native-async-storage/async-storage';
const storeData = async value => {
try { await AsyncStorage.setItem('@storage_Key', value); } catch (e) {}
};
const getData = async () => {
try {
const value = await AsyncStorage.getItem('@storage_Key');
if (value !== null) { /* 处理数据 */ }
} catch (e) {}
};
Fetch API:进行网络请求。
const fetchData = async () => {
try {
let response = await fetch('https://api.example.com/data');
let json = await response.json();
console.log(json);
} catch (error) { console.error(error); }
};
Linking:处理外部链接,如打开网页或拨打电话。
import { Linking } from 'react-native';
const openURL = async url => {
const supported = await Linking.canOpenURL(url);
if (supported) await Linking.openURL(url);
};
const makeCall = phoneNumber => Linking.openURL(`tel:${phoneNumber}`);
DeviceInfo:获取设备信息,需安装 react-native-device-info。
import DeviceInfo from 'react-native-device-info';
const getDeviceInfo = async () => {
const deviceId = await DeviceInfo.getDeviceId();
const systemVersion = await DeviceInfo.getSystemVersion();
console.log(`Device ID: ${deviceId}, System Version: ${systemVersion}`);
};
Permissions:请求和检查设备权限,需安装 react-native-permissions。
import { PermissionsAndroid } from 'react-native';
const requestLocationPermission = async () => {
try {
const granted = await PermissionsAndroid.request(PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION, {
title: '位置权限',
message: '需要访问您的位置',
buttonNeutral: '稍后询问',
buttonNegative: '取消',
buttonPositive: '确认',
});
if (granted === PermissionsAndroid.RESULTS.GRANTED) console.log('您可以使用位置');
else console.log('位置权限被拒绝');
} catch (err) { console.warn(err); }
};
Vibration:控制设备震动。
import { Vibration } from 'react-native';
const triggerVibration = () => Vibration.vibrate(1000);
Share:分享内容到其他应用。
import { Share } from 'react-native';
const shareMessage = async () => {
try {
const result = await Share.share({ message: '这是要分享的消息' });
if (result.action === Share.sharedAction) { /* 分享成功 */ }
else if (result.action === Share.dismissedAction) { /* 分享取消 */ }
} catch (error) { alert(error.message); }
};
StatusBar:控制状态栏样式和行为。
import { StatusBar } from 'react-native';
const setStatusBar = () => {
StatusBar.setBarStyle('light-content', true);
StatusBar.setBackgroundColor('#000000');
};
多端开发方案
React Native 支持跨平台开发,通过 Platform API 实现 iOS 和 Android 之间的适配。Platform.OS 可用于条件渲染,而 Platform.select 允许为不同平台定义样式或值。
import { Platform, StyleSheet } from 'react-native';
const styles = StyleSheet.create({
container: {
flex: 1,
...Platform.select({ android: { backgroundColor: 'green' }, ios: { backgroundColor: 'red' }, default: { backgroundColor: 'blue' } }),
},
});
平台常量如 Platform.isPad 可用于设备特定逻辑。图片资源也可按平台选择:
const imageSource = Platform.select({
ios: require('./images/image_ios.png'),
android: require('./images/image_android.png'),
});
第三方库如 react-native-elements 或 react-native-paper 提供跨平台 UI 组件。性能和体验优化需考虑平台特性,例如 Android 的返回按钮行为可能与 iOS 导航模式不同,需在逻辑中适配。
原生模块开发与接入
当应用需要平台特有功能时,可通过原生模块连接 JavaScript 与原生代码。新架构引入 Turbo Native Module 和 Fabric Native Components 替代旧版 NativeModules。
以实现 Web Storage API 的 localStorage 为例,使用 Android 的 SharedPreferences 和 iOS 的 NSUserDefaults。
原生模块开发与接入 (iOS)
首先,创建规范文件 NativeLocalStorage.ts 定义接口:
import type { TurboModule } from 'react-native';
import { TurboModuleRegistry } from 'react-native';
export interface Spec extends TurboModule {
setItem(value: string, key: string): void;
getItem(key: string): string | null;
removeItem(key: string): void;
clear(): void;
}
export default TurboModuleRegistry.getEnforcing<Spec>('NativeLocalStorage') as Spec;
配置 package.json 的 codegenConfig 后,运行 Codegen 生成平台代码。然后,在 iOS 项目中实现模块。
创建 RCTNativeLocalStorage 类,实现生成的接口:
#import "RCTNativeLocalStorage.h"
static NSString *const RCTNativeLocalStorageKey = @"local-storage";
@interface RCTNativeLocalStorage()
@property (strong, nonatomic) NSUserDefaults *localStorage;
@end
@implementation RCTNativeLocalStorage
RCT_EXPORT_MODULE(NativeLocalStorage)
- (id)init {
if (self = [super init]) { _localStorage = [[NSUserDefaults alloc] initWithSuiteName:RCTNativeLocalStorageKey]; }
return self;
}
- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:(const facebook::react::ObjCTurboModule::InitParams &)params {
return std::make_shared<facebook::react::NativeLocalStorageSpecJSI>(params);
}
- (NSString * _Nullable)getItem:(NSString *)key { return [self.localStorage stringForKey:key]; }
- (void)setItem:(NSString *)value key:(NSString *)key { [self.localStorage setObject:value forKey:key]; }
- (void)removeItem:(NSString *)key { [self.localStorage removeObjectForKey:key]; }
- (void)clear {
NSDictionary *keys = [self.localStorage dictionaryRepresentation];
for (NSString *key in keys) { [self removeItem:key]; }
}
@end
在 JavaScript 中使用该模块:
import NativeLocalStorage from './specs/NativeLocalStorage';
const storedValue = NativeLocalStorage?.getItem('myKey');
NativeLocalStorage?.setItem('newValue', 'myKey');
原生模块开发与接入 (Android)
在 Android 端,创建 NativeLocalStorageModule 实现接口:
package com.nativelocalstorage;
import android.content.Context;
import android.content.SharedPreferences;
import com.facebook.react.bridge.ReactApplicationContext;
public class NativeLocalStorageModule extends NativeLocalStorageSpec {
private static final String NAME = "NativeLocalStorage";
public NativeLocalStorageModule(ReactApplicationContext reactContext) { super(reactContext); }
@Override public String getName() { return NAME; }
@Override public void setItem(String value, String key) {
SharedPreferences sharedPref = getReactApplicationContext().getSharedPreferences("my_prefs", Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPref.edit();
editor.putString(key, value);
editor.apply();
}
@Override public String getItem(String key) {
SharedPreferences sharedPref = getReactApplicationContext().getSharedPreferences("my_prefs", Context.MODE_PRIVATE);
return sharedPref.getString(key, null);
}
@Override public void removeItem(String key) {
SharedPreferences sharedPref = getReactApplicationContext().getSharedPreferences("my_prefs", Context.MODE_PRIVATE);
sharedPref.edit().remove(key).apply();
}
@Override public void clear() {
SharedPreferences sharedPref = getReactApplicationContext().getSharedPreferences("my_prefs", Context.MODE_PRIVATE);
sharedPref.edit().clear().apply();
}
}
创建 NativeLocalStoragePackage 注册模块:
package com.nativelocalstorage;
import com.facebook.react.TurboReactPackage;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.module.model.ReactModuleInfo;
import com.facebook.react.module.model.ReactModuleInfoProvider;
import java.util.HashMap;
import java.util.Map;
public class NativeLocalStoragePackage extends TurboReactPackage {
@Override
public NativeModule getModule(String name, ReactApplicationContext reactContext) {
if (name.equals(NativeLocalStorageModule.NAME)) return new NativeLocalStorageModule(reactContext);
else return null;
}
@Override
public ReactModuleInfoProvider getReactModuleInfoProvider() {
return () -> {
Map<String, ReactModuleInfo> map = new HashMap<>();
map.put(NativeLocalStorageModule.NAME, new ReactModuleInfo(NativeLocalStorageModule.NAME, NativeLocalStorageModule.NAME, false, false, false, true));
return map;
};
}
}
在 MainApplication 中添加该包:
package com.turbomoduleexample;
import com.facebook.react.PackageList;
import com.facebook.react.ReactPackage;
import com.nativelocalstorage.NativeLocalStoragePackage;
public class MainApplication extends Application implements ReactApplication {
private final ReactNativeHost reactNativeHost = new DefaultReactNativeHost(this) {
@Override public List<ReactPackage> getPackages() {
List<ReactPackage> packages = new PackageList(this).getPackages();
packages.add(new NativeLocalStoragePackage());
return packages;
}
};
}
应用构建发布
构建和发布涉及 iOS 和 Android 平台的配置、图标、打包和发布步骤。
应用信息配置
- iOS:在 Xcode 中配置应用名称、版本、构建号和 Bundle Identifier,修改 Info.plist 文件。启动页通过 LaunchScreen 设置。
- Android:在 AndroidManifest.xml 中配置应用名称和图标,在 build.gradle 中设置版本和包名。
图标配置
图标可通过在线工具一键生成。iOS 图标添加到 Xcode 的 Assets.xcassets,Android 图标放置于 android/app/src/main/res 的相应 mipmap 文件夹中。
打包
- iOS:使用 Xcode 选择 Product > Archive 进行打包,然后通过 Distribute App 导出。
- Android:在项目根目录运行
cd android && ./gradlew assembleRelease,APK 文件生成于 android/app/build/outputs/apk/release。
发布
- iOS:通过 App Store Connect 创建应用条目,使用 Xcode 或 Transporter 上传 .ipa 文件,提交审核。
- Android:在 Google Play Console 创建应用,上传 APK 文件并填写描述等信息,提交审核。
补充资料
- React Native 官方文档
- React Navigation 文档
- React Native 样式表文档
- Material Design UI 库:React Native Paper
- 基于 Tailwind 的 UI 库:Gluestack
- 小清新 UI 库:Tamagui
- 构建分发平台
- 苹果发布平台:App Store Connect
- 老架构原生模块开发文档
- 新架构原生模块开发文档
- Turbo Native Module 架构文档
- Fabric Native Components 架构文档
- React Native 新架构概述
- Hermes JavaScript 引擎