React Native 开发规范与完整流程指南

React Native 开发规范与完整流程指南

适用对象:中大型 React Native 项目团队 / 独立开发者

技术栈基线:React Native 0.74+ / TypeScript / React Navigation / 主流状态管理

维护原则:随 RN 版本迭代持续更新,团队共识优先于个人偏好


目录


一、环境搭建

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 新增页面的标准步骤

  1. src/screens/ 下创建页面文件夹
  2. 编写 index.tsx(组件逻辑)、styles.ts(样式)、types.ts(类型)
  3. src/navigation/ 中注册路由
  4. src/services/modules/ 中添加对应 API
  5. 如需全局状态,在 src/store/slices/ 中添加 slice
  6. 编写单元测试 / 组件测试
  7. 自测通过后提交 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 断点调试

  1. 摇一摇打开菜单 → Open Debugger(或 Debug with Chrome
  2. 浏览器自动打开 http://localhost:8081/debugger-ui
  3. F12 打开 DevTools → Sources 面板
  4. debuggerWorker.js 中找到源码,打断点
  5. 操作 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 配置签名
  1. Xcode 打开 ios/MyApp.xcworkspace
  2. 选中 Target → Signing & Capabilities
  3. 勾选 Automatically manage signing(自动管理)
  4. 选择 Team(Apple 开发者账号)
  5. 修改 Bundle Identifier(唯一标识)
  6. 配置 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 componentVirtualizedList 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+

相关推荐
小林ixn1 小时前
全栈项目实战:前端独立开发,不再傻等后端接口
前端·javascript·react.js
Asize1 小时前
前端接口工程:axios + mock,前端不再傻等后端
前端·javascript
张元清1 小时前
React useElementSize Hook:用 ResizeObserver 实时追踪元素宽高 (2026)
javascript·react.js
渣波1 小时前
React 性能优化与状态管理双雄:useMemo 与 useReducer 深度解析
前端·javascript
渣波1 小时前
告别 LLM 幻觉:用 Harness 工程化思维打造生产级 AI 应用
前端·javascript
breeze jiang2 小时前
React Todos 前端独立开发全解:用 vite-plugin-mock + axios 封装,再也不等后端接口
前端·react.js·状态模式
cyadyx2 小时前
【vue】Pinia相对Vuex
前端·javascript·vue.js
IMPYLH3 小时前
HTML 的 <figure> 元素
前端·javascript·html