React Native 开发规范与完整流程指南
适用对象:中大型 React Native 项目团队 / 独立开发者
技术栈基线:React Native 0.74+ / TypeScript / React Navigation / 主流状态管理
维护原则:随 RN 版本迭代持续更新,团队共识优先于个人偏好
目录
- 一、环境搭建
- 二、项目初始化
- 三、目录结构规范
- 四、代码规范与工具链
- [五、Git 与协作规范](#五、Git 与协作规范)
- 六、开发流程
- 七、调试方法
- 八、测试策略
- 九、预览与真机运行
- 十、打包与发布
- 十一、性能优化注意事项
- 十二、常见问题与排错
- 附录:推荐依赖清单
一、环境搭建
1.1 必需软件
| 工具 | 版本要求 | 说明 |
|---|---|---|
| Node.js | LTS 18+ / 20+ | 推荐使用 nvm 管理多版本 |
| npm / yarn / pnpm | 最新稳定版 | 团队统一包管理器,推荐 pnpm |
| JDK | 17(Android) | RN 0.73+ 要求 JDK 17 |
| Android Studio | 最新稳定版 | 提供 SDK、模拟器、构建工具 |
| Xcode | 15+(iOS,仅 macOS) | 提供 iOS SDK、模拟器、签名工具 |
| CocoaPods | 1.14+ | iOS 原生依赖管理 |
| Watchman | 最新版 | 文件监听,提升 Metro 性能 |
1.2 macOS 环境配置(iOS + Android)
bash
# 1. 安装 Homebrew
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
# 2. 安装基础工具
brew install node watchman cocoapods
brew install --cask android-studio
# 3. 配置 Android 环境变量(写入 ~/.zshrc)
export ANDROID_HOME=$HOME/Library/Android/sdk
export PATH=$PATH:$ANDROID_HOME/emulator
export PATH=$PATH:$ANDROID_HOME/platform-tools
export PATH=$PATH:$ANDROID_HOME/tools
export PATH=$PATH:$ANDROID_HOME/tools/bin
# 4. 安装 iOS 依赖
sudo gem install cocoapods
pod setup
# 5. 验证
npx react-native doctor
1.3 Windows 环境配置(仅 Android)
powershell
# 1. 安装 Node.js LTS、Python 3(构建原生模块需要)
# 2. 安装 Android Studio,勾选 Android SDK / Platform-tools / Emulator
# 3. 配置环境变量
ANDROID_HOME = C:\Users\<用户名>\AppData\Local\Android\Sdk
Path 追加: %ANDROID_HOME%\platform-tools; %ANDROID_HOME%\emulator
# 4. 安装 Visual Studio Build Tools(C++ 桌面开发工作负载)
1.4 环境验证
bash
# 检查所有依赖是否就绪
npx @react-native-community/cli doctor
# 预期输出:Common ✓ Node ✓ Watchman ✓ Android ✓ JDK ✓ Xcode ✓ CocoaPods ✓
二、项目初始化
2.1 创建项目(推荐 TypeScript 模板)
bash
# 方式一:官方 CLI(推荐,最新稳定版)
npx @react-native-community/cli@latest init MyApp --template react-native-template-typescript
# 方式二:指定版本
npx react-native@0.74.5 init MyApp --version 0.74.5
# 方式三:Expo(适合快速原型 / 不依赖原生模块的项目)
npx create-expo-app MyApp --template expo-template-blank-typescript
选型建议:
- 需要大量原生模块、自定义原生代码 → 纯 RN(React Native CLI)
- 快速迭代、OTA 热更新、团队小 → Expo(EAS Build)
- 中大型商业项目 → 纯 RN + CodePush(或自建热更新)
2.2 初始化后必做配置
bash
cd MyApp
# 1. 安装依赖
pnpm install # 或 npm install / yarn
# 2. iOS 安装原生依赖
cd ios && pod install && cd ..
# 3. 首次运行验证
# Android
npx react-native run-android
# iOS
npx react-native run-ios
2.3 package.json 脚本规范
json
{
"scripts": {
"android": "react-native run-android",
"android:release": "react-native run-android --mode=release",
"ios": "react-native run-ios",
"ios:release": "react-native run-ios --configuration Release",
"start": "react-native start",
"start:reset": "react-native start --reset-cache",
"lint": "eslint . --ext .ts,.tsx",
"lint:fix": "eslint . --ext .ts,.tsx --fix",
"format": "prettier --write \"src/**/*.{ts,tsx,json,md}\"",
"typecheck": "tsc --noEmit",
"test": "jest",
"test:watch": "jest --watch",
"test:coverage": "jest --coverage",
"pod": "cd ios && pod install && cd ..",
"clean": "react-native clean",
"build:android": "cd android && ./gradlew assembleRelease && cd ..",
"build:ios": "cd ios && xcodebuild -workspace MyApp.xcworkspace -scheme MyApp -configuration Release -archivePath ./build/MyApp.xcarchive archive && cd .."
}
}
三、目录结构规范
3.1 推荐目录结构
MyApp/
├── android/ # Android 原生工程
├── ios/ # iOS 原生工程
├── src/
│ ├── assets/ # 静态资源
│ │ ├── images/
│ │ ├── icons/
│ │ ├── fonts/
│ │ └── animations/ # Lottie 动画
│ ├── components/ # 通用组件
│ │ ├── Button/
│ │ │ ├── index.tsx
│ │ │ ├── styles.ts
│ │ │ └── types.ts
│ │ └── Card/
│ ├── screens/ # 页面(按业务模块划分)
│ │ ├── Home/
│ │ │ ├── index.tsx
│ │ │ ├── styles.ts
│ │ │ └── hooks.ts
│ │ └── Profile/
│ ├── navigation/ # 路由配置
│ │ ├── RootNavigator.tsx
│ │ ├── TabNavigator.tsx
│ │ └── linking.ts
│ ├── store/ # 状态管理
│ │ ├── index.ts
│ │ ├── slices/
│ │ └── hooks.ts
│ ├── services/ # API / 网络请求
│ │ ├── api.ts # axios 实例
│ │ ├── interceptors.ts
│ │ └── modules/
│ │ ├── user.ts
│ │ └── order.ts
│ ├── hooks/ # 自定义 Hooks
│ │ ├── useAuth.ts
│ │ └── useDebounce.ts
│ ├── utils/ # 工具函数
│ │ ├── format.ts
│ │ ├── storage.ts
│ │ └── validate.ts
│ ├── constants/ # 常量
│ │ ├── colors.ts
│ │ ├── sizes.ts
│ │ └── config.ts
│ ├── theme/ # 主题 / 样式系统
│ │ ├── index.ts
│ │ ├── colors.ts
│ │ ├── typography.ts
│ │ └── spacing.ts
│ ├── types/ # 全局 TypeScript 类型
│ │ ├── env.d.ts
│ │ └── global.d.ts
│ ├── i18n/ # 国际化
│ │ ├── index.ts
│ │ └── locales/
│ │ ├── zh.json
│ │ └── en.json
│ ├── App.tsx # 根组件
│ └── main.tsx # 入口注册
├── __tests__/ # 测试文件
├── .env.development # 环境变量
├── .env.production
├── .eslintrc.js
├── .prettierrc
├── tsconfig.json
├── jest.config.js
├── metro.config.js
├── babel.config.js
└── package.json
3.2 命名规范
| 类型 | 规范 | 示例 |
|---|---|---|
| 组件文件 | PascalCase | UserCard.tsx |
| 页面文件 | PascalCase | HomeScreen.tsx |
| Hook 文件 | camelCase,use 开头 | useAuth.ts |
| 工具函数 | camelCase | formatDate.ts |
| 常量 | UPPER_SNAKE_CASE | MAX_RETRY_COUNT |
| 样式文件 | 与组件同名 + .styles.ts |
UserCard.styles.ts |
| 类型文件 | 与组件同名 + .types.ts |
UserCard.types.ts |
| 文件夹 | PascalCase(组件/页面)/ camelCase(其他) | components/UserCard/ |
3.3 组件文件模板
tsx
// src/components/Button/index.tsx
import React from 'react';
import { TouchableOpacity, Text, ActivityIndicator } from 'react-native';
import { styles } from './styles';
import type { ButtonProps } from './types';
export const Button: React.FC<ButtonProps> = ({
title,
onPress,
disabled = false,
loading = false,
variant = 'primary',
}) => {
return (
<TouchableOpacity
style={[styles.button, styles[variant], disabled && styles.disabled]}
onPress={onPress}
disabled={disabled || loading}
activeOpacity={0.7}
>
{loading ? (
<ActivityIndicator color="#fff" />
) : (
<Text style={styles.text}>{title}</Text>
)}
</TouchableOpacity>
);
};
四、代码规范与工具链
4.1 ESLint 配置
bash
pnpm add -D eslint @react-native/eslint-config @typescript-eslint/parser @typescript-eslint/eslint-plugin eslint-plugin-react eslint-plugin-react-hooks eslint-plugin-react-native
js
// .eslintrc.js
module.exports = {
root: true,
extends: [
'@react-native',
'eslint:recommended',
'plugin:@typescript-eslint/recommended',
'plugin:react/recommended',
'plugin:react-hooks/recommended',
'plugin:react-native/all',
'prettier',
],
parser: '@typescript-eslint/parser',
plugins: ['@typescript-eslint', 'react', 'react-hooks', 'react-native'],
rules: {
'react/react-in-jsx-scope': 'off',
'react-native/no-inline-styles': 'warn',
'react-native/no-unused-styles': 'error',
'react-native/split-platform-components': 'off',
'@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_' }],
'@typescript-eslint/no-explicit-any': 'warn',
'react-hooks/rules-of-hooks': 'error',
'react-hooks/exhaustive-deps': 'warn',
'no-console': ['warn', { allow: ['warn', 'error'] }],
},
settings: {
react: { version: 'detect' },
},
ignorePatterns: ['node_modules/', 'android/', 'ios/', '*.config.js'],
};
4.2 Prettier 配置
json
// .prettierrc
{
"semi": true,
"singleQuote": true,
"trailingComma": "all",
"printWidth": 100,
"tabWidth": 2,
"useTabs": false,
"bracketSpacing": true,
"arrowParens": "always",
"endOfLine": "lf"
}
# .prettierignore
node_modules/
android/
ios/
*.md
4.3 TypeScript 配置
json
// tsconfig.json
{
"compilerOptions": {
"target": "esnext",
"module": "esnext",
"lib": ["es2021"],
"jsx": "react-native",
"moduleResolution": "node",
"allowJs": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
"noImplicitAny": true,
"strictNullChecks": true,
"skipLibCheck": true,
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"baseUrl": ".",
"paths": {
"@/*": ["src/*"],
"@components/*": ["src/components/*"],
"@screens/*": ["src/screens/*"],
"@utils/*": ["src/utils/*"],
"@hooks/*": ["src/hooks/*"],
"@services/*": ["src/services/*"],
"@store/*": ["src/store/*"],
"@theme/*": ["src/theme/*"],
"@assets/*": ["src/assets/*"]
}
},
"include": ["src", "__tests__", "*.ts", "*.tsx"],
"exclude": ["node_modules", "android", "ios", "babel.config.js", "metro.config.js"]
}
4.4 路径别名配置(babel)
js
// babel.config.js
module.exports = {
presets: ['module:metro-react-native-babel-preset'],
plugins: [
[
'module-resolver',
{
root: ['./src'],
extensions: ['.ios.ts', '.android.ts', '.ts', '.ios.tsx', '.android.tsx', '.tsx', '.json'],
alias: {
'@': './src',
'@components': './src/components',
'@screens': './src/screens',
'@utils': './src/utils',
'@hooks': './src/hooks',
'@services': './src/services',
'@store': './src/store',
'@theme': './src/theme',
'@assets': './src/assets',
},
},
],
],
};
bash
pnpm add -D babel-plugin-module-resolver
4.5 提交前自动检查(Husky + lint-staged)
bash
pnpm add -D husky lint-staged
npx husky install
npx husky add .husky/pre-commit "npx lint-staged"
json
// package.json 追加
{
"lint-staged": {
"src/**/*.{ts,tsx}": ["eslint --fix", "prettier --write"],
"src/**/*.{json,md}": ["prettier --write"]
}
}
五、Git 与协作规范
5.1 分支策略
main # 生产分支,仅接受 PR,必须通过 CI
├── develop # 开发分支,日常开发合并目标
│ ├── feature/user-login # 功能分支
│ ├── feature/payment
│ ├── bugfix/login-error # Bug 修复分支
│ └── hotfix/urgent-crash # 紧急修复(基于 main)
└── release/v1.2.0 # 发布分支
5.2 Commit Message 规范(Conventional Commits)
<type>(<scope>): <subject>
<body>
<footer>
type 类型:
| type | 说明 |
|---|---|
feat |
新功能 |
fix |
修复 Bug |
docs |
文档变更 |
style |
代码格式(不影响功能) |
refactor |
重构 |
perf |
性能优化 |
test |
测试相关 |
chore |
构建/工具/依赖变更 |
ci |
CI/CD 配置变更 |
revert |
回滚 |
示例:
feat(auth): 添加手机号验证码登录功能
- 集成短信验证码 API
- 添加倒计时 Hook
- 完成登录态持久化
Closes #123
5.3 .gitignore 关键项
# 依赖
node_modules/
# iOS
ios/Pods/
ios/build/
ios/*.xcworkspace/xcuserdata/
# Android
android/build/
android/app/build/
android/.gradle/
android/local.properties
# 环境
.env
.env.local
# 编辑器
.vscode/
.idea/
*.swp
# 系统
.DS_Store
Thumbs.db
# 产物
*.apk
*.aab
*.ipa
*.xcarchive
# 测试覆盖率
coverage/
六、开发流程
6.1 标准开发流程
需求评审 → 技术方案设计 → 分支创建 → 编码实现 → 自测 → Code Review → 合并 develop → 测试环境验证 → 发布
6.2 每日开发步骤
bash
# 1. 拉取最新代码
git checkout develop
git pull origin develop
# 2. 创建功能分支
git checkout -b feature/xxx
# 3. 启动开发服务器
pnpm start --reset-cache
# 4. 运行到模拟器/真机(另开终端)
pnpm android
# 或
pnpm ios
# 5. 开发完成后
pnpm lint
pnpm typecheck
pnpm test
# 6. 提交
git add .
git commit -m "feat(xxx): ..."
git push origin feature/xxx
# 7. 创建 PR,请求 Code Review
6.3 新增页面的标准步骤
- 在
src/screens/下创建页面文件夹 - 编写
index.tsx(组件逻辑)、styles.ts(样式)、types.ts(类型) - 在
src/navigation/中注册路由 - 在
src/services/modules/中添加对应 API - 如需全局状态,在
src/store/slices/中添加 slice - 编写单元测试 / 组件测试
- 自测通过后提交 PR
七、调试方法
7.1 调试工具矩阵
| 工具 | 用途 | 适用平台 |
|---|---|---|
| React Native DevTools | 元素检查、网络、性能 | iOS / Android |
| Flipper | 原生调试、网络、数据库、布局 | iOS / Android |
| Reactotron | 日志、网络、状态、AsyncStorage | iOS / Android |
| Chrome DevTools | JS 断点调试 | 全部 |
| Xcode Instruments | iOS 性能分析(内存、CPU、卡顿) | iOS |
| Android Studio Profiler | Android 性能分析 | Android |
| Sentry / Bugly | 线上崩溃监控 | 全部 |
7.2 开启调试菜单
- iOS 模拟器 :
Cmd + D - Android 模拟器 :
Cmd + M(macOS)/Ctrl + M(Windows) - 真机:摇晃设备
调试菜单选项:
Reload:重新加载 JS(Cmd + R)Open Debugger:打开 Chrome 调试器Enable Fast Refresh:开启热刷新(默认开启)Toggle Inspector:元素检查器Show Perf Monitor:性能监视器Debug with Chrome/Debug with Safari
7.3 Chrome DevTools 断点调试
- 摇一摇打开菜单 →
Open Debugger(或Debug with Chrome) - 浏览器自动打开
http://localhost:8081/debugger-ui - 按
F12打开 DevTools →Sources面板 - 在
debuggerWorker.js中找到源码,打断点 - 操作 App 触发断点,查看调用栈和变量
7.4 React Native DevTools(新版 Hermes 推荐)
RN 0.70+ 默认使用 Hermes 引擎,推荐使用新版 DevTools:
bash
# 安装独立 DevTools(可选,新版已内置)
npx react-devtools
# 启动后会自动连接到运行中的 App
功能:
- Components 面板:查看组件树、Props、State、Hooks
- Profiler 面板:录制渲染性能,分析重渲染
- 支持直接修改 Props 实时预览
7.5 Flipper 配置
bash
# 1. 下载安装 Flipper
# https://fbflipper.com/
# 2. 项目集成(RN 0.62+ 默认支持)
# iOS: pod 'Flipper' 已在 Podfile 中
# Android: debugImplementation 已在 build.gradle 中
# 3. 安装常用插件
# - Network(网络请求抓包)
# - Layout(布局检查)
# - Database(数据库查看)
# - Shared Preferences(本地存储)
7.6 日志调试
tsx
// 基础日志
console.log('用户信息:', user);
console.warn('警告信息');
console.error('错误信息', error);
// 自定义日志工具(推荐封装)
// src/utils/logger.ts
class Logger {
static debug(tag: string, ...args: unknown[]) {
if (__DEV__) console.log(`[${tag}]`, ...args);
}
static info(tag: string, ...args: unknown[]) {
console.info(`[${tag}]`, ...args);
}
static error(tag: string, ...args: unknown[]) {
console.error(`[${tag}]`, ...args);
}
}
export default Logger;
7.7 网络请求调试
tsx
// 方式一:axios 拦截器打印
apiClient.interceptors.request.use((config) => {
Logger.debug('API', `→ ${config.method?.toUpperCase()} ${config.url}`);
return config;
});
apiClient.interceptors.response.use(
(response) => {
Logger.debug('API', `← ${response.status} ${response.config.url}`);
return response;
},
(error) => {
Logger.error('API', `✗ ${error.message}`, error.response?.data);
return Promise.reject(error);
},
);
// 方式二:Reactotron 自动捕获
// 方式三:Flipper Network 插件
7.8 常见调试命令
bash
# 查看设备列表
adb devices
xcrun simctl list devices
# 查看日志
adb logcat *:S ReactNative:V ReactNativeJS:V
# iOS 日志
xcrun simctl spawn booted log stream --level=debug --predicate 'process == "MyApp"'
# 清除缓存(遇到奇怪问题时)
watchman watch-del-all
rm -rf /tmp/metro-*
pnpm start --reset-cache
# 重装 App
adb uninstall com.myapp
# iOS 模拟器
xcrun simctl uninstall booted com.myapp
八、测试策略
8.1 测试金字塔
/ E2E 测试 \ (少量,关键流程)
/ 集成测试 \ (中等,模块协作)
/ 组件测试 \ (较多,UI 交互)
/ 单元测试 \ (最多,函数/Hook)
8.2 单元测试(Jest)
bash
pnpm add -D jest @testing-library/react-native @testing-library/jest-native react-test-renderer @types/jest
js
// jest.config.js
module.exports = {
preset: 'react-native',
setupFilesAfterEnv: ['@testing-library/jest-native/extend-expect'],
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json'],
transformIgnorePatterns: [
'node_modules/(?!(react-native|@react-native|@react-navigation|react-native-vector-icons)/)',
],
moduleNameMapper: {
'^@/(.*)$': '<rootDir>/src/$1',
},
collectCoverageFrom: ['src/**/*.{ts,tsx}', '!src/**/*.types.ts'],
testPathIgnorePatterns: ['/node_modules/', '/android/', '/ios/'],
};
Hook 测试示例:
tsx
// __tests__/hooks/useCounter.test.tsx
import { renderHook, act } from '@testing-library/react-native';
import { useCounter } from '@/hooks/useCounter';
describe('useCounter', () => {
it('初始值为 0', () => {
const { result } = renderHook(() => useCounter());
expect(result.current.count).toBe(0);
});
it('increment 增加计数', () => {
const { result } = renderHook(() => useCounter());
act(() => result.current.increment());
expect(result.current.count).toBe(1);
});
});
组件测试示例:
tsx
// __tests__/components/Button.test.tsx
import React from 'react';
import { render, fireEvent } from '@testing-library/react-native';
import { Button } from '@/components/Button';
describe('Button', () => {
it('渲染标题文本', () => {
const { getByText } = render(<Button title="点击我" onPress={() => {}} />);
expect(getByText('点击我')).toBeTruthy();
});
it('点击触发 onPress', () => {
const onPress = jest.fn();
const { getByText } = render(<Button title="点击我" onPress={onPress} />);
fireEvent.press(getByText('点击我'));
expect(onPress).toHaveBeenCalledTimes(1);
});
it('disabled 时不触发 onPress', () => {
const onPress = jest.fn();
const { getByText } = render(
<Button title="点击我" onPress={onPress} disabled />,
);
fireEvent.press(getByText('点击我'));
expect(onPress).not.toHaveBeenCalled();
});
});
8.3 E2E 测试(Detox)
bash
# 1. 安装
pnpm add -D detox
# iOS 额外依赖
brew tap wix/brew
brew install applesimutils
# 2. 初始化
npx detox init -r jest
js
// .detoxrc.json
{
"testRunner": "jest",
"runnerConfig": "e2e/config.json",
"configurations": {
"ios": {
"type": "ios.simulator",
"binaryPath": "ios/build/Build/Products/Debug-iphonesimulator/MyApp.app",
"build": "xcodebuild -workspace ios/MyApp.xcworkspace -scheme MyApp -configuration Debug -sdk iphonesimulator -derivedDataPath ios/build",
"device": { "type": "iPhone 15" }
},
"android": {
"type": "android.emulator",
"binaryPath": "android/app/build/outputs/apk/debug/app-debug.apk",
"build": "cd android && ./gradlew assembleDebug assembleAndroidTest -DtestBuildType=debug && cd ..",
"device": { "avdName": "Pixel_6_API_34" }
}
}
}
tsx
// e2e/login.test.ts
describe('登录流程', () => {
beforeAll(async () => {
await device.launchApp();
});
beforeEach(async () => {
await device.reloadReactNative();
});
it('应该显示登录页面', async () => {
await expect(element(by.id('login-screen'))).toBeVisible();
});
it('输入账号密码后登录成功', async () => {
await element(by.id('username-input')).typeText('testuser');
await element(by.id('password-input')).typeText('password123');
await element(by.id('login-button')).tap();
await expect(element(by.id('home-screen'))).toBeVisible();
});
});
bash
# 运行 E2E 测试
detox build --configuration ios
detox test --configuration ios
8.4 测试覆盖率要求
- 工具函数:≥ 80%
- 自定义 Hooks:≥ 70%
- 通用组件:≥ 60%
- 业务页面:≥ 40%
- 核心业务逻辑:≥ 90%
九、预览与真机运行
9.1 Android 模拟器
bash
# 列出可用模拟器
emulator -list-avds
# 启动模拟器
emulator -avd Pixel_6_API_34
# 运行 App
npx react-native run-android
# 指定设备
npx react-native run-android --deviceId emulator-5554
9.2 iOS 模拟器
bash
# 列出可用模拟器
xcrun simctl list devices available
# 运行 App(默认 iPhone)
npx react-native run-ios
# 指定设备
npx react-native run-ios --simulator="iPhone 15 Pro"
# 指定 iOS 版本
npx react-native run-ios --simulator="iPhone 15 (17.2)"
9.3 Android 真机预览
bash
# 1. 手机开启「开发者选项」→「USB 调试」
# 2. 连接 USB,确认设备被识别
adb devices
# 3. 运行
npx react-native run-android
# 4. 无线调试(Android 11+)
adb pair <ip>:<port> # 配对
adb connect <ip>:<port> # 连接
9.4 iOS 真机预览
bash
# 1. Xcode 打开 ios/MyApp.xcworkspace
# 2. 选择 Team(签名),修改 Bundle Identifier
# 3. 连接 iPhone,选择真机设备
# 4. 点击 Run(或 Cmd + R)
# 命令行方式
npx react-native run-ios --device "iPhone 名称"
注意:iOS 真机调试需要 Apple 开发者账号(免费账号也可,但 7 天过期)。
9.5 局域网真机联调
确保手机和电脑在同一 WiFi 下:
bash
# Android:反向代理(USB 连接时自动)
adb reverse tcp:8081 tcp:8081
# iOS:修改 AppDelegate 中的 sourceURL 为电脑 IP
# 或在 Info.plist 中配置 NSAppTransportSecurity 允许 HTTP
# 查看电脑 IP
ifconfig | grep "inet "
# Windows
ipconfig
9.6 二维码预览(Expo 项目)
如果使用 Expo:
bash
npx expo start
# 手机安装 Expo Go,扫描二维码即可预览
# 支持 iOS / Android,无需原生构建
十、打包与发布
10.1 Android 打包
10.1.1 生成签名密钥
bash
# 生成 keystore(记住密码和别名)
keytool -genkeypair -v -storetype PKCS12 -keystore my-upload-key.keystore -alias my-key-alias -keyalg RSA -keysize 2048 -validity 10000
# 移动到 android/app/
mv my-upload-key.keystore android/app/
10.1.2 配置签名
gradle
// android/app/build.gradle
android {
...
signingConfigs {
release {
if (project.hasProperty('MYAPP_UPLOAD_STORE_FILE')) {
storeFile file(MYAPP_UPLOAD_STORE_FILE)
storePassword MYAPP_UPLOAD_STORE_PASSWORD
keyAlias MYAPP_UPLOAD_KEY_ALIAS
keyPassword MYAPP_UPLOAD_KEY_PASSWORD
}
}
}
buildTypes {
release {
...
signingConfig signingConfigs.release
minifyEnabled true // 代码混淆
shrinkResources true // 资源压缩
proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
}
}
}
properties
# android/gradle.properties
MYAPP_UPLOAD_STORE_FILE=my-upload-key.keystore
MYAPP_UPLOAD_KEY_ALIAS=my-key-alias
MYAPP_UPLOAD_STORE_PASSWORD=你的密码
MYAPP_UPLOAD_KEY_PASSWORD=你的密码
⚠️
gradle.properties中的密码不要提交到 Git,应加入.gitignore或使用 CI 环境变量。
10.1.3 构建 APK / AAB
bash
cd android
# 构建 APK(用于分发测试)
./gradlew assembleRelease
# 产物:android/app/build/outputs/apk/release/app-release.apk
# 构建 AAB(Google Play 上架必需)
./gradlew bundleRelease
# 产物:android/app/build/outputs/bundle/release/app-release.aab
# 清理后重新构建
./gradlew clean
./gradlew assembleRelease
10.1.4 多渠道打包(可选)
gradle
// android/app/build.gradle
android {
flavorDimensions "default"
productFlavors {
dev {
applicationIdSuffix ".dev"
versionNameSuffix "-dev"
}
staging {
applicationIdSuffix ".staging"
}
production {
// 默认
}
}
}
bash
# 构建指定渠道
./gradlew assembleProductionRelease
10.2 iOS 打包
10.2.1 配置签名
- Xcode 打开
ios/MyApp.xcworkspace - 选中 Target →
Signing & Capabilities - 勾选
Automatically manage signing(自动管理) - 选择 Team(Apple 开发者账号)
- 修改 Bundle Identifier(唯一标识)
- 配置 Capabilities(推送、内购、Keychain 等)
10.2.2 构建 Archive
bash
# 方式一:Xcode 图形化
# 1. 选择 Generic iOS Device(或 Any iOS Device)
# 2. Product → Archive
# 3. Organizer 中选择 Archive → Distribute App
# 方式二:命令行
cd ios
# 清理
xcodebuild clean -workspace MyApp.xcworkspace -scheme MyApp -configuration Release
# 归档
xcodebuild archive \
-workspace MyApp.xcworkspace \
-scheme MyApp \
-configuration Release \
-archivePath ./build/MyApp.xcarchive
# 导出 IPA(需要 ExportOptions.plist)
xcodebuild -exportArchive \
-archivePath ./build/MyApp.xcarchive \
-exportPath ./build/ipa \
-exportOptionsPlist ExportOptions.plist
xml
<!-- ExportOptions.plist -->
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>method</key>
<string>app-store</string> <!-- app-store / ad-hoc / development / enterprise -->
<key>teamID</key>
<string>你的TeamID</string>
<key>uploadSymbols</key>
<true/>
</dict>
</plist>
10.2.3 上传到 App Store
bash
# 使用 xcrun altool 上传
xcrun altool --upload-app --type ios \
--file ./build/ipa/MyApp.ipa \
--username "你的AppleID" \
--password "应用专用密码"
10.3 版本号管理
json
// package.json
{
"version": "1.2.0"
}
- versionName (Android)/ CFBundleShortVersionString (iOS):
1.2.0(主版本.次版本.修订号) - versionCode (Android)/ CFBundleVersion(iOS):递增整数,每次构建 +1
bash
# 推荐使用脚本同步版本号
# android/app/build.gradle
versionCode 12
versionName "1.2.0"
# ios/MyApp/Info.plist
<key>CFBundleShortVersionString</key>
<string>1.2.0</string>
<key>CFBundleVersion</key>
<string>12</string>
10.4 热更新(CodePush / OTA)
bash
# 安装 CodePush CLI
npm install -g code-push-cli
# 注册应用
code-push app add MyApp-Android android react-native
code-push app add MyApp-iOS ios react-native
# 集成 SDK
pnpm add react-native-code-push
cd ios && pod install && cd ..
tsx
// App.tsx
import CodePush from 'react-native-code-push';
const codePushOptions = {
checkFrequency: CodePush.CheckFrequency.ON_APP_START,
installMode: CodePush.InstallMode.ON_NEXT_RESTART,
};
export default CodePush(codePushOptions)(App);
bash
# 发布热更新
code-push release-react MyApp-Android android --d Production --description "修复登录Bug"
code-push release-react MyApp-iOS ios --d Production --description "修复登录Bug"
# 查看更新状态
code-push deployment ls MyApp-Android -k
⚠️ 注意:Apple 审核对热更新有限制,不能修改核心功能和 UI 布局,只能修复 Bug 和小改动。
十一、性能优化注意事项
11.1 渲染性能
tsx
// ❌ 避免:每次渲染都创建新函数/对象
<Button onPress={() => handlePress(item.id)} />
// ✅ 推荐:使用 useCallback 缓存
const handlePress = useCallback((id: string) => {
navigation.navigate('Detail', { id });
}, [navigation]);
// ❌ 避免:内联样式
<View style={{ flex: 1, padding: 10, backgroundColor: '#fff' }} />
// ✅ 推荐:StyleSheet.create
const styles = StyleSheet.create({
container: { flex: 1, padding: 10, backgroundColor: '#fff' },
});
11.2 列表性能
tsx
// ✅ FlatList 关键配置
<FlatList
data={data}
keyExtractor={(item) => item.id}
renderItem={renderItem}
getItemLayout={(data, index) => ({
length: ITEM_HEIGHT,
offset: ITEM_HEIGHT * index,
index,
})}
initialNumToRender={10}
maxToRenderPerBatch={10}
windowSize={5}
removeClippedSubviews={true}
ListEmptyComponent={<EmptyView />}
/>
11.3 图片优化
tsx
// ✅ 使用 resizeMode 避免大图缩放
<Image
source={{ uri: imageUrl }}
style={{ width: 100, height: 100 }}
resizeMode="cover"
/>
// ✅ 大图使用 react-native-fast-image(缓存 + 预加载)
import FastImage from 'react-native-fast-image';
<FastImage source={{ uri: url, priority: FastImage.priority.normal }} style={styles.image} />
11.4 内存管理
tsx
// ✅ 组件卸载时清理定时器和事件监听
useEffect(() => {
const timer = setInterval(fetchData, 30000);
const subscription = eventEmitter.addListener('refresh', handleRefresh);
return () => {
clearInterval(timer);
subscription.remove();
};
}, []);
// ✅ 避免在全局变量中缓存大量数据
// ✅ 长列表及时释放图片内存
11.5 启动优化
- 使用
Hermes引擎(默认开启,JS 执行更快) - 开启
Inline Requires(延迟加载模块) - 首屏只加载必要资源,懒加载非首屏页面
- 使用
react-native-bootsplash做启动屏
js
// metro.config.js
module.exports = {
transformer: {
getTransformOptions: async () => ({
transform: {
experimentalImportSupport: false,
inlineRequires: true, // 开启内联 require
},
}),
},
};
11.6 包体积优化
- Android:开启
minifyEnabled+shrinkResources - iOS:使用
Bitcode(已废弃,改用 App Thinning) - 移除未使用的依赖(
depcheck检测) - 图片使用 WebP 格式(Android)
- 字体只打包需要的字重
十二、常见问题与排错
12.1 常见构建错误
| 错误 | 原因 | 解决方案 |
|---|---|---|
Unable to resolve module |
模块未安装 / 缓存问题 | pnpm install + pnpm start --reset-cache |
SDK location not found |
Android SDK 路径未配置 | 创建 android/local.properties 配置 sdk.dir |
CocoaPods could not find compatible versions |
Pod 版本冲突 | cd ios && pod update && pod install |
Command PhaseScriptExecution failed |
构建脚本错误 | 查看详细日志,检查 Node 版本 |
app:mergeDexRelease |
方法数超限 | 开启 multidex 或优化依赖 |
Undefined symbol |
iOS 原生库缺失 | pod deintegrate && pod install |
duplicate resources |
资源重复 | 清理 android/app/src/main/res/drawable-* |
12.2 运行时常见问题
红屏错误(Red Screen):
- JS 异常,查看错误堆栈定位
- 常见:未定义变量、组件引用错误、Props 类型错误
黄屏警告(Yellow Box):
- 非致命警告,生产环境不显示
- 常见:
setState on unmounted component、VirtualizedList missing keys
白屏:
- JS 加载失败,检查 Metro 是否运行
- 检查
index.js入口是否正确注册 - 真机检查网络是否连通电脑
12.3 缓存清理大全
bash
# 终极清理脚本(遇到玄学问题时执行)
rm -rf node_modules
rm -rf ios/Pods
rm -rf ios/build
rm -rf android/build
rm -rf android/app/build
rm -rf android/.gradle
rm -rf /tmp/metro-*
rm -rf ~/Library/Developer/Xcode/DerivedData
watchman watch-del-all
# 重新安装
pnpm install
cd ios && pod install && cd ..
pnpm start --reset-cache
12.4 原生模块开发注意事项
- 新增原生模块后必须重新构建 App(不是热刷新)
- iOS:
pod install后重新run-ios - Android:重新
run-android - 注意线程安全:UI 操作必须在主线程
- 注意生命周期:组件卸载时移除原生监听
附录:推荐依赖清单
基础库
| 库名 | 用途 |
|---|---|
@react-navigation/native |
路由导航 |
@react-navigation/native-stack |
栈导航 |
@react-navigation/bottom-tabs |
底部 Tab |
react-native-screens |
原生屏幕优化 |
react-native-safe-area-context |
安全区域 |
react-native-gesture-handler |
手势处理 |
react-native-reanimated |
动画库(性能优秀) |
状态管理
| 库名 | 用途 |
|---|---|
@reduxjs/toolkit + react-redux |
Redux 状态管理 |
zustand |
轻量级状态管理(推荐) |
@tanstack/react-query |
服务端状态 / 数据请求缓存 |
网络与存储
| 库名 | 用途 |
|---|---|
axios |
HTTP 请求 |
@react-native-async-storage/async-storage |
本地存储 |
react-native-mmkv |
高性能本地存储(推荐) |
react-native-keychain |
安全存储(密码/Token) |
UI 与工具
| 库名 | 用途 |
|---|---|
react-native-svg |
SVG 支持 |
react-native-vector-icons |
图标库 |
react-native-fast-image |
高性能图片 |
react-native-bootsplash |
启动屏 |
react-native-device-info |
设备信息 |
react-native-permissions |
权限管理 |
dayjs |
日期处理 |
zod |
数据校验 |
质量与监控
| 库名 | 用途 |
|---|---|
@sentry/react-native |
崩溃监控 |
react-native-code-push |
热更新 |
detox |
E2E 测试 |
reactotron-react-native |
开发调试 |
文档维护说明:本文档随 React Native 版本演进持续更新。团队成员如发现过时内容或有更好实践,请提交 PR 修订。
最后更新 :2026-08-12
适用版本:React Native 0.74+