目前只有 ios 设备,以下只针对 iPhone 测试。
搭建 React Native 项目
1、前提:准备环境
- 安装 node ,版本 v22+
- 安装 nrm (NPM Registry Manager) ,负责管理 npm 的下载源,解决的是下载缓慢或失败的问题
- 安装 nvm (Node Version Manager) ,负责管理 Node.js 的版本
# 安装 nrm
npm install -g nrm
2、安装依赖
- 必须安装的依赖有:
Node、Watchman、Xcode和CocoaPods。 - 必须安装
Xcode来获得编译 iOS 应用所需的工具和环境 CocoaPods是用 Ruby 编写的包管理器(可以理解为针对 iOS 的 npm)。从0.60版本开始 react native 的 iOS 版本需要使用CocoaPods来管理依赖。
brew install watchman
watchman --version
# 2026.05.25.00
brew install cocoapods
3、命令创建 React native 项目
npx @react-native-community/cli init reactnative_app
启动
react-native start
作用:单独启动 Metro Bundler 服务器(即打包服务)。
执行流程:
- 启动一个本地的 HTTP 服务,默认监听
8081端口。 - 监听项目文件变化,当 JS 或资源文件修改时,自动重新打包并通知客户端更新(热重载 / Fast Refresh)。
- 提供调试工具(如 Chrome DevTools)的连接端点。
npx react-native run-ios
作用:在 iOS 模拟器或真机上构建并运行 React Native 应用。
执行流程:
- 启动 Metro Bundler(如果尚未启动):Metro 是 React Native 的 JavaScript 打包工具,负责将 JS 代码、资源等打包成
main.bundle并提供热更新服务。 - 编译原生 iOS 项目:调用 Xcode 的命令行工具(
xcodebuild)编译 iOS 项目的.xcworkspace或.xcodeproj。 - 安装并启动应用:将编译好的
.app包安装到目标设备(模拟器或真机),并启动应用。 - 建立调试连接:连接 Metro 的调试端口,支持热重载和错误提示。
路由导航
实现路由导航
使用插件 @react-navigation/native-stack
import { NavigationContainer } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
const Stack = createNativeStackNavigator();
<NavigationContainer>
<Stack.Navigator initialRouteName="Home">
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="System" component={SystemScreen} />
<Stack.Screen name="Profile" component={UserProfileScreen} />
<Stack.Screen name="Record" component={Record} />
</Stack.Navigator>
</NavigationContainer>
点击按钮跳转
import { useNavigation } from '@react-navigation/native';
const navigation = useNavigation();
<View>
<Button
onPress={() => {
navigation.navigate('System');
}}
>
Open System Settings
</Button>
</View>
实现底部 Tab
使用插件 @react-navigation/bottom-tabs
function App() {
const isDarkMode = useColorScheme() === 'dark';
return (
<SafeAreaProvider>
<StatusBar barStyle={isDarkMode ? 'light-content' : 'dark-content'} />
<NavigationContainer>
<Tab.Navigator>
<Tab.Screen name="Home" component={HomeScreen} />
<Tab.Screen name="System" component={SystemScreen} />
<Tab.Screen name="Profile" component={UserProfileScreen} />
<Tab.Screen name="Record" component={Record} />
</Tab.Navigator>
</NavigationContainer>
</SafeAreaProvider>
);
}
交互
Linking 打开其他 APP
使用 Linking.canOpenURL 检查百度 App 是否已安装,如果已安装,再用 Linking.openURL 将其打开
打开百度App
<key>LSApplicationQueriesSchemes</key>
<array>
<string>baiduboxapp</string>
</array>
URL Scheme 机制
URL Scheme 是一种让 App 之间能够相互调用的“通用语言”。它允许 App 注册自己独一无二的“网址”,其他 App 或网页浏览器通过这个“网址”就能直接唤醒它,并执行特定操作。
工作流程
- 注册:开发者在 App 里向系统声明自己要处理的 URL Scheme。
- 唤起:当系统遇到一个 URL(如
myapp://page),它会查找注册了该 Scheme 的 App。 - 处理:App 被唤醒后,系统将完整的 URL 传给 App,App 解析 URL 并跳转到对应页面或执行相应操作。
Linking 拨打电话
<key>LSApplicationQueriesSchemes</key>
<array>
<string>tel</string>
<string>telprompt</string>
</array>
<Button
mode="outlined"
onPress={() => {
const phoneNumber = '13800000000';
let url = `tel:${phoneNumber}`;
// iOS 使用 telprompt 会先弹窗询问用户是否确认拨号,体验更友好
if (Platform.OS === 'ios') {
url = `telprompt:${phoneNumber}`;
}
// 3. 检查当前设备是否支持拨号功能
Linking.canOpenURL(url)
.then(supported => {
if (!supported) {
Alert.alert('提示', '您的设备不支持拨打电话功能');
} else {
// 4. 执行拨号
return Linking.openURL(url);
}
})
.catch(err => console.error('An error occurred', err));
}}
>
拨打 电话
</Button>
Vibration 控制设备振动/停止振动
<Button
mode="outlined"
onPress={() => {
const pattern = [100, 200, 100, 200];
Vibration.vibrate(pattern, true); // 第二个参数为 true 表示循环
}}
>
手机振动
</Button>
<View style={styles.placePlaceholder} />
<Button
mode="outlined"
onPress={() => {
Vibration.cancel();
}}
>
手机停止 振动
</Button>
获取当前位置
yarn add @react-native-community/geolocation
import Geolocation, {
type GeolocationResponse,
} from '@react-native-community/geolocation';
<Button
mode="outlined"
onPress={() => {
Geolocation.getCurrentPosition(
(p: GeolocationResponse) => {
console.log('当前位置:', p);
setPosition(p);
// position.coords.latitude, position.coords.longitude
},
error => {
console.log('获取位置失败:', error.code, error.message);
},
{
enableHighAccuracy: true, // 启用高精度 (使用GPS)
timeout: 15000, // 超时时间 (毫秒)
maximumAge: 10000, // 位置缓存有效期 (毫秒)
},
);
}}
>
获取当前位置
</Button>
检测蓝牙状态,引导设置
yarn add react-native-ble-plx
<key>NSBluetoothAlwaysUsageDescription</key>
<string>你的应用需要使用蓝牙的原因</string>
打开相机/图库
yarn add react-native-image-picker
<string>我们需要访问您的相机来拍照</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>我们需要访问您的相机来拍照</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>此应用需要访问您的相册来选择照片</string>
使用字体图标
react-native-vector-icons 需要手动添加字体到 iOS 工程,否则图标字体无法加载,只显示空框/不显示。
<key>UIAppFonts</key>
<array>
<string>MaterialCommunityIcons.ttf</string>
</array>
在 底部导航栏 配置 icon
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import { Icon } from 'react-native-paper';
const Tab = createBottomTabNavigator();
function HomeIcon({ color, size }: { color: string; size: number }) {
return <Icon source="home" color={color} size={size} />;
}
function AccountIcon({ color, size }: { color: string; size: number }) {
return <Icon source="account" color={color} size={size} />;
}
function App() {
const isDarkMode = useColorScheme() === 'dark';
return (
<SafeAreaProvider>
<StatusBar barStyle={isDarkMode ? 'light-content' : 'dark-content'} />
<NavigationContainer>
<Tab.Navigator>
<Tab.Screen
name="Home"
component={HomeScreen}
options={{
tabBarIcon: HomeIcon,
}}
/>
<Tab.Screen name="System" component={SystemScreen} />
<Tab.Screen name="Profile" component={UserProfileScreen}
options={{
tabBarIcon: AccountIcon,
}}
/>
<Tab.Screen name="Record" component={Record} />
</Tab.Navigator>
</NavigationContainer>
</SafeAreaProvider>
);
}
Bridge(桥接)原理
传统 Bridge
JS 和 Native 是独立环境,通过异步消息队列通信,数据需经过 JSON 序列化/反序列化,存在性能瓶颈。
JSI (JavaScript Interface)
RN 0.60+ 推出的接口,让 JS 可以直接持有 Native 对象的引用,实现同步调用,无需序列化
Hermes 引擎是什么?
Hermes 是 Facebook 专为 RN 打造的轻量级 JS 引擎。
主要优势:
- 启动更快:支持将 JS 源码预编译为字节码,省去运行时解析 AST 的过程。
- 内存占用更低:比 JS Core 节省约 50% 的内存。
- 包体积更小:字节码格式更紧凑
JSI 架构
JSI 的核心是为 C++ 应用嵌入 JavaScript 引擎提供了一套标准 API。这套 API 让 C++ 代码可以直接操作 JavaScript 的对象和函数,反之亦然。
- 直接引用:通过 JSI,JavaScript 可以持有对 C++ 对象的引用(
HostObject),并像调用普通 JS 对象一样调用它。 - 同步调用:由于是直接引用,JS 调用原生方法可以立即得到返回值,无需通过异步队列等待。
- 数据零拷贝:数据在 JS 和原生层之间传递时,不再需要序列化为 JSON 字符串,而是直接传递 C++ 对象或基础类型,大大减少了内存和 CPU 开销。
navite module
在 RN 中,Native Module主要分为旧版和新版(Turbo Module)两种:
旧版 Native Modules
基于Bridge通信,在启动时会一次性加载所有模块。适合快速原型或维护老项目
新版 实现一个 Turbo Module 的通用步骤
- 编写类型规范 (Spec) :在
specs目录下创建NativeXXX.ts文件,用TypeScript或Flow定义模块接口,文件名必须以Native为前缀。 - 配置 Codegen:在
package.json中添加codegenConfig字段,告诉工具去哪里找规范文件。 - 实现原生代码:
- Android:用Java/Kotlin创建类,继承
ReactContextBaseJavaModule并实现方法。 - iOS:用Objective-C/Swift创建类,实现
RCTBridgeModule协议。 - 跨平台C++ :在
shared文件夹中创建.h和.cpp文件,实现核心逻辑,实现一次代码在双端共享。
- Android:用Java/Kotlin创建类,继承
- 注册模块:将实现注册到
ReactPackage中。 - 在JS中调用:直接导入并使用生成的模块对象。
如何优化 React Native 应用的性能?
- 列表优化:长列表务必使用
FlashList替代FlatList,前者性能远优于后者。 - 渲染优化:使用
React.memo、useCallback和useMemo避免不必要的组件重渲染。 - 动画优化:使用
React Native Reanimated,它的动画在 UI 线程执行,不会因为 JS 线程繁忙而卡顿。 - 引擎与架构:开启 Hermes 引擎,并确保项目兼容新架构
FlatList 和 ScrollView 的区别是什么?如何优化长列表?
- 核心区别:
ScrollView会一次性渲染所有子组件,适合内容很少的视图;FlatList采用虚拟化(Virtualization) 技术,只渲染当前屏幕可见的元素,适合长列表。 - 优化手段:为
FlatList设置 getItemLayout 属性来跳过测量过程;在 keyExtractor 中提供稳定的 key;避免在 renderItem 中使用匿名函数。