04 React Native工程化、质量、发布与生态选型

React Native 工程化比 Web 更复杂,因为它同时包含 JavaScript 工程、Android 工程、iOS 工程、原生依赖、证书签名、应用商店发布和线上崩溃监控。

1. 开发路线选择

常见路线:

  • Expo Managed:上手快,适合大多数常规应用。
  • Expo Development Build:保留 Expo 体验,同时支持自定义原生模块。
  • React Native CLI:原生控制力强,适合深度原生集成。

选择建议:

场景 推荐
快速业务应用 Expo
需要推送、相机、定位等常见能力 Expo
需要少量自定义原生模块 Expo Dev Build
大量原生 SDK / 复杂原生工程 RN CLI
原生团队深度参与 RN CLI

2. 项目结构

推荐:

text 复制代码
src/
├── app/
│   ├── navigation/
│   └── providers/
├── screens/
├── features/
│   └── learning/
├── entities/
├── shared/
│   ├── ui/
│   ├── hooks/
│   ├── api/
│   └── theme/
└── main.tsx

移动端 feature-first 的价值:

  • 屏幕多但业务边界清晰。
  • 离线、权限、导航和服务层可分离。
  • 便于多人协作。

3. TypeScript

React Navigation 参数:

ts 复制代码
type RootStackParamList = {
  Home: undefined;
  Detail: { id: string };
};

组件 Props:

tsx 复制代码
type LessonCardProps = {
  item: Lesson;
  completed: boolean;
  onPress: (id: string) => void;
};

领域类型:

ts 复制代码
type Lesson = {
  id: string;
  title: string;
  level: '入门' | '进阶' | '高级' | '精通' | '专家';
  summary: string;
  tags: string[];
};

4. 样式与主题

基础 theme:

ts 复制代码
export const theme = {
  colors: {
    background: '#F4F7F8',
    surface: '#FFFFFF',
    text: '#172026',
    primary: '#296A59',
  },
  spacing: {
    xs: 4,
    sm: 8,
    md: 16,
    lg: 24,
  },
};

使用:

jsx 复制代码
const styles = StyleSheet.create({
  card: {
    padding: theme.spacing.md,
    backgroundColor: theme.colors.surface,
  },
});

组件库要统一:

  • 颜色。
  • 字体。
  • 间距。
  • 圆角。
  • 阴影。
  • 点击态。
  • 禁用态。
  • 可访问性。

5. 可访问性

jsx 复制代码
<Pressable
  accessibilityRole="button"
  accessibilityLabel="收藏课程"
  onPress={toggleFavorite}
>
  <Text>收藏</Text>
</Pressable>

常用属性:

  • accessible
  • accessibilityLabel
  • accessibilityHint
  • accessibilityRole
  • accessibilityState

移动端要考虑:

  • VoiceOver。
  • TalkBack。
  • 动态字体。
  • 触摸目标大小。
  • 颜色对比。
  • 减少动画。

6. 国际化

不要硬编码文案:

jsx 复制代码
<Text>{t('lesson.completed')}</Text>

日期和数字:

js 复制代码
new Intl.DateTimeFormat(locale).format(date);
new Intl.NumberFormat(locale).format(value);

移动端 i18n 要考虑:

  • 系统语言变化。
  • RTL。
  • 长文本撑爆布局。
  • App Store 多语言元数据。

7. 测试策略

单元测试:

  • reducer。
  • selector。
  • 领域函数。
  • 工具函数。

组件测试:

jsx 复制代码
render(<LessonCard item={item} onPress={onPress} />);
fireEvent.press(screen.getByText(item.title));
expect(onPress).toHaveBeenCalledWith(item.id);

E2E:

  • Detox。
  • Maestro。
  • Appium。

关键路径:

  • 登录。
  • 首屏加载。
  • 搜索。
  • 收藏。
  • 离线恢复。
  • 深链打开。
  • 权限拒绝。

8. 调试工具

常用:

  • React Native DevTools。
  • Flipper。
  • Xcode Instruments。
  • Android Studio Profiler。
  • Hermes debugger。
  • React DevTools。
  • Metro logs。
  • Sentry / Bugsnag。

调试方向:

  • JS error。
  • Native crash。
  • 网络。
  • 性能。
  • 内存。
  • UI 层级。
  • 原生日志。

9. 日志和错误上报

线上必须接入:

  • JS 异常。
  • Native 崩溃。
  • 网络错误。
  • 用户设备信息。
  • app version / build number。
  • source map。

错误边界:

jsx 复制代码
class ErrorBoundary extends React.Component {
  state = { hasError: false };

  static getDerivedStateFromError() {
    return { hasError: true };
  }

  componentDidCatch(error, info) {
    reportError(error, info);
  }

  render() {
    if (this.state.hasError) {
      return <FallbackScreen />;
    }

    return this.props.children;
  }
}

10. 构建类型

Android:

  • debug。
  • release。
  • productFlavors。
  • signingConfig。
  • ProGuard/R8。

iOS:

  • Debug。
  • Release。
  • Schemes。
  • Provisioning Profile。
  • Certificates。

Expo:

  • development build。
  • preview build。
  • production build。
  • EAS Build profiles。

11. 环境配置

常见环境:

  • development。
  • staging。
  • production。

配置示例:

ts 复制代码
export const config = {
  apiBaseUrl: process.env.EXPO_PUBLIC_API_BASE_URL,
};

注意:

  • 前端环境变量不安全。
  • 密钥不要打进客户端。
  • 不同环境 bundle 要可追踪。

12. 发布

Android:

  • 生成 AAB。
  • Play Console。
  • 内测轨道。
  • 分阶段发布。

iOS:

  • Archive。
  • TestFlight。
  • App Store Connect。
  • 审核。

Expo EAS:

bash 复制代码
eas build --profile production --platform all
eas submit --platform all

13. OTA 更新

Expo Updates / CodePush 类能力可更新 JS bundle 和资源。

适合:

  • 修复 JS bug。
  • 调整文案。
  • 小功能。

不适合:

  • 原生代码变化。
  • 权限变化。
  • 原生依赖变化。
  • App Store 审核要求相关变化。

必须设计:

  • 版本兼容。
  • 回滚。
  • 灰度。
  • 崩溃监控。

14. 依赖治理

React Native 依赖要额外检查:

  • 是否支持当前 RN 版本。
  • 是否支持 New Architecture。
  • 是否支持 Hermes。
  • iOS/Android 是否都支持。
  • 是否需要 Pod install。
  • 是否有原生权限配置。
  • 是否仍在维护。

15. Native Directory

选库建议查:

  • 维护状态。
  • 新架构兼容。
  • Expo 兼容。
  • 平台支持。
  • issue 活跃度。
  • 替代方案。

16. Monorepo

React Native monorepo 要处理:

  • Metro watchFolders。
  • Babel 配置。
  • TypeScript path。
  • iOS Pod 路径。
  • Android Gradle 路径。
  • hoist 依赖冲突。

不要轻易上 monorepo,除非确实需要多包协作。

17. 安全

客户端不可信:

  • 不存明文 token。
  • 不把密钥打包进 app。
  • 权限由服务端校验。
  • HTTPS。
  • 证书固定按业务风险决定。
  • 敏感信息使用 Keychain / Keystore。

安全存储:

  • Expo SecureStore。
  • react-native-keychain。

18. 专家上线清单

  • Release 包测试通过。
  • Android/iOS 真机覆盖。
  • 权限文案检查。
  • 深链测试。
  • 离线场景测试。
  • 崩溃上报接入。
  • source map 上传。
  • OTA 回滚策略。
  • App Store / Play 合规检查。
  • 新架构依赖兼容检查。

19. Expo 与 RN CLI 深度取舍

Expo 优势:

  • 启动快。
  • OTA/EAS 体系完善。
  • 常见设备能力有模块。
  • 团队不必立刻维护复杂原生工程。

Expo 风险:

  • 特殊原生 SDK 可能需要 config plugin。
  • 原生能力超出 Expo 模块时需要 Dev Build。
  • 依赖 Expo SDK 版本节奏。

RN CLI 优势:

  • 原生控制力强。
  • 深度 SDK 集成自由。
  • 原生团队协作顺畅。

RN CLI 风险:

  • Android/iOS 工程复杂。
  • 证书、Gradle、Pods、Xcode 成本高。
  • 升级更费力。

20. EAS / CI 发布流水线

推荐流水线:

text 复制代码
lint -> typecheck -> unit test -> build preview -> e2e smoke -> production build -> submit

版本治理:

  • app version 面向用户。
  • build number / versionCode 面向商店。
  • JS bundle version 面向 OTA。
  • release commit 面向排查。

21. Source Map 与崩溃定位

没有 source map,线上 JS 错误很难定位。

上线必须记录:

  • app version。
  • build number。
  • update id。
  • commit sha。
  • sourcemap。

错误上报平台要能区分:

  • 原生崩溃。
  • JS 异常。
  • Promise rejection。
  • 网络错误。
  • OTA 版本。

22. 测试矩阵

最低矩阵:

  • iOS 真机。
  • Android 真机。
  • 小屏。
  • 大屏。
  • 弱网。
  • 离线。
  • 深色模式。
  • 字体放大。
  • 权限拒绝。
  • 冷启动 deep link。

自动化覆盖不了全部,发布前需要手工冒烟清单。

23. 依赖升级策略

React Native 升级要看:

  • RN changelog。
  • React 版本。
  • Gradle。
  • Android SDK。
  • Xcode。
  • CocoaPods。
  • Hermes。
  • New Architecture。
  • 社区库兼容。

升级步骤:

  1. 建升级分支。
  2. 升 RN/Expo SDK。
  3. 跑 iOS/Android build。
  4. 修原生编译错误。
  5. 跑核心 E2E。
  6. 真机回归。
  7. 灰度发布。

24. 工程专家题

  • 为什么选择 Expo 或 RN CLI?
  • OTA 更新是否可能破坏原生兼容?
  • source map 是否和 release 对得上?
  • 原生依赖是否支持新架构?
  • 证书过期谁负责?
  • Android/iOS 权限文案是否合规?
  • E2E 是否覆盖登录、深链、离线和推送?

25. 工程知识点索引

  1. Expo Managed。
  2. Expo Dev Build。
  3. RN CLI。
  4. Metro。
  5. Babel。
  6. Hermes。
  7. Gradle。
  8. CocoaPods。
  9. Xcode Scheme。
  10. Android Product Flavors。
  11. EAS Build。
  12. EAS Submit。
  13. OTA Updates。
  14. CodePush。
  15. Sentry。
  16. Source Map。
  17. Detox。
  18. Maestro。
  19. Appium。
  20. TestFlight。
  21. Play Console。
  22. App Store Review。
  23. Provisioning Profile。
  24. Keystore。
  25. SecureStore。

26. 发布反模式

  • 只测模拟器不测真机。
  • Debug 包当性能依据。
  • 不上传 source map。
  • OTA 更新修改了依赖原生代码的功能。
  • 没有回滚策略。
  • 证书过期没人知道。
  • Android/iOS 版本号不一致。
  • 权限文案和实际用途不一致。
  • 新架构升级不查依赖兼容。

面试题完整答案总集:React Native 工程、质量与发布

为什么选择 Expo 或 RN CLI?

Expo 适合快速业务应用、常见设备能力、团队原生经验不足或希望使用 EAS/OTA 的场景。RN CLI 适合大量自定义原生 SDK、复杂原生工程、原生团队深度参与的场景。Expo Dev Build 是折中方案,既保留 Expo 工具链,又支持自定义原生能力。

OTA 更新是否可能破坏原生兼容?

可能。OTA 只能更新 JS bundle 和资源,不能更新原生代码、权限、原生依赖或 native 配置。如果 JS 调用了当前 native binary 不存在的 API,就会崩溃。必须用 runtime version 或类似机制保证 OTA 与原生版本兼容。

source map 是否和 release 对得上?

必须对得上。线上 JS 错误需要通过 source map 还原源码。source map 应与 app version、build number、update id、commit sha 对应,否则错误堆栈无法准确定位。

原生依赖是否支持新架构为什么重要?

启用 New Architecture 后,旧原生模块或 UI 组件可能不兼容 Fabric、TurboModules 或 Codegen,导致构建失败或运行时异常。升级前要检查依赖维护状态、issue、版本说明和替代方案。

证书过期谁负责?

必须有明确 owner 和提醒机制。iOS 证书、Provisioning Profile、Android keystore、推送证书过期都会影响构建、发布或推送。成熟团队应把证书管理纳入发布 runbook。

Android/iOS 权限文案是否合规?

权限文案必须准确说明用途,并与实际使用一致。App Store 和 Play 审核会检查权限用途,用户也依赖这些文案判断是否授权。过度请求或说明不清可能导致拒审或用户拒绝。

E2E 是否覆盖登录、深链、离线和推送?

关键移动端路径应覆盖。登录保证认证流正确,深链保证外部入口可用,离线保证弱网体验,推送保证通知点击能进入正确页面。这些问题单元测试难覆盖,适合 E2E 或真机冒烟测试。

为什么不能只测模拟器?

模拟器无法完全代表真实设备,尤其是性能、内存、相机、推送、定位、蓝牙、键盘、系统权限、低端 Android 表现。发布前必须覆盖真机,尤其是目标用户常见设备。

相关推荐
杨超凡2 小时前
豆包收费了?我特么自己用“意念”搓了一个!
javascript
threelab3 小时前
Three.js 咖啡杯烟雾效果 | 三维可视化 / AI 提示词
开发语言·javascript·人工智能
Heo3 小时前
14_React 中的更新队列 updateQueue
前端·javascript·面试
前端 贾公子3 小时前
解决浏览器端 globalThis is not defined 报错
前端·javascript·vue.js
之歆3 小时前
DAY12_CSS3选择器全攻略 + 盒子新特性完全指南(下)
前端·javascript·css3
kyriewen114 小时前
代码写成一锅粥?3个设计模式让你的项目“起死回生”
开发语言·前端·javascript·设计模式·ecmascript
郑生zs4 小时前
Hooks-useEffect
react.js
光影少年4 小时前
react函数组件、类组件、纯组件、受控/非受控组件
前端·react.js·掘金·金石计划