You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
echo 54bf84b19b feat: 首页更新 4 weeks ago
app feat: 首页更新 4 weeks ago
assets feat: 首页更新 4 weeks ago
components feat: 首页更新 4 weeks ago
constants feat: 首页更新 4 weeks ago
docs feat: update 1 month ago
hooks feat: 首页更新 4 weeks ago
pages feat: 首页更新 4 weeks ago
schemas feat: 首页更新 4 weeks ago
scripts feat: 首页更新 4 weeks ago
services feat: 首页更新 4 weeks ago
stores feat: 首页更新 4 weeks ago
theme feat: 首页更新 4 weeks ago
types feat: 首页更新 4 weeks ago
utils feat: 首页更新 4 weeks ago
.env.development feat: update 1 month ago
.env.example feat: update 1 month ago
.env.production feat: update 1 month ago
.gitignore feat: update react-native-paper 1 month ago
.prettierignore feat: update 1 month ago
.prettierrc.json feat: update 1 month ago
README.md feat: 首页更新 4 weeks ago
app.json feat: app.json配置修改 1 month ago
eas.json feat: update 1 month ago
metro.config.js feat: update 1 month ago
package.json feat: 首页更新 4 weeks ago
pnpm-lock.yaml feat: 首页更新 4 weeks ago
tsconfig.json feat: 首页更新 4 weeks ago

README.md

React Native Expo 热更新项目

基于 Expo Router 和 EAS Update 的完整 React Native 项目,支持热更新(OTA)功能

Expo React Native TypeScript pnpm

📖 目录

项目特性

核心特性

  • 🎯 Expo Router - 文件路由系统,类似 Next.js,支持类型安全的导航
  • 📘 TypeScript - 完整的类型支持,提升代码质量
  • 🔥 EAS Update - 热更新支持(CodePush 的官方替代方案)
  • React Native 新架构 - 启用 Fabric 渲染器和 TurboModules
  • 📦 pnpm - 快速、节省磁盘空间的包管理器
  • 🧭 标签导航 - 开箱即用的导航示例
  • 🎨 完整主题系统 - 深色/浅色/自动主题切换,完整的颜色配置 🎯
  • 📱 跨平台 - 支持 iOS、Android 和 Web

架构特性 🎯

  • 📁 扁平化目录结构 - 清晰的模块组织,符合社区最佳实践
  • 🔄 模块化导出 - 每个目录独立导出,避免循环依赖
  • 💾 双存储系统 - AsyncStorage(持久化)+ SessionStorage(临时)
  • 🎨 主题化组件 - ThemedText 和 ThemedView,自动适配主题
  • 🔐 API 加密 - 请求/响应自动加密解密
  • 📊 状态管理 - Zustand + AsyncStorage 持久化
  • 数据验证 - Zod 表单验证
  • 🎯 类型安全 - 完整的 TypeScript 类型定义

🚀 快速开始

前置要求

第一步:安装依赖

pnpm install

第二步:启动开发服务器

pnpm start

启动后,你会看到一个二维码和几个选项:

  • a - 在 Android 模拟器/设备上运行
  • i - 在 iOS 模拟器上运行(仅 macOS)
  • w - 在浏览器中运行
  • 扫描二维码 - 在 Expo Go App 中运行

第三步:在设备上查看

方法 1:使用 Expo Go(推荐用于快速预览)

  1. 在手机上安装 Expo Go
  2. 扫描终端中显示的二维码
  3. 应用会自动加载并运行

方法 2:使用模拟器

Android 模拟器:

pnpm android

iOS 模拟器(仅 macOS):

pnpm ios

Web 浏览器:

pnpm web

📁 项目结构

rn-demo/
├── 📱 app/                          # Expo Router 路由文件
│   ├── (tabs)/                      # 标签导航组
│   │   ├── index.tsx               # 首页 - 热更新演示 ⭐
│   │   ├── two.tsx                 # 第二个标签页
│   │   ├── demo.tsx                # 完整示例页面 🎯
│   │   ├── paper.tsx               # React Native Paper 示例
│   │   └── _layout.tsx             # 标签布局
│   ├── test.tsx                    # 测试页面(无 tabs)🎯
│   ├── _layout.tsx                 # 根布局 - 自动检查更新 ⭐
│   ├── modal.tsx                   # 模态页面示例
│   ├── +html.tsx                   # Web HTML 模板
│   └── +not-found.tsx              # 404 页面
│
├── 💻 业务代码目录
├── utils/                           # 工具函数
│   ├── network/                    # 网络相关
│   │   ├── api.ts                 # Axios API 配置
│   │   ├── helper.ts              # 加密/解密工具
│   │   └── error.ts               # 错误处理
│   ├── storage.ts                  # AsyncStorage 封装
│   ├── sessionStorage.ts           # Session Storage 实现 🎯
│   ├── storageManager.ts           # 统一存储管理器 🎯
│   ├── config.ts                   # 配置管理
│   ├── date.ts                     # Day.js 日期工具
│   ├── common.ts                   # 通用工具
│   └── index.ts                    # 统一导出
│
├── stores/                          # Zustand 状态管理
│   ├── userStore.ts                # 用户状态
│   ├── settingsStore.ts            # 应用设置
│   ├── tenantStore.ts              # 租户状态 🎯
│   └── index.ts                    # 统一导出
│
├── schemas/                         # Zod 验证规则
│   ├── auth.ts                     # 认证验证
│   ├── user.ts                     # 用户验证
│   └── index.ts                    # 统一导出
│
├── services/                        # API 服务层
│   ├── authService.ts              # 认证服务
│   ├── userService.ts              # 用户服务
│   ├── tenantService.ts            # 租户服务 🎯
│   └── index.ts                    # 统一导出
│
├── hooks/                           # 自定义 Hooks
│   ├── useDebounce.ts              # 防抖 Hook
│   ├── useThrottle.ts              # 节流 Hook
│   ├── useHaptics.ts               # 触觉反馈 Hook
│   ├── useRequest.ts               # 请求 Hook 🎯
│   ├── useTheme.ts                 # 主题 Hooks 🎯
│   ├── useColorScheme.ts           # 颜色方案 Hook 🎯
│   ├── useColorScheme.web.ts       # Web 平台颜色方案 🎯
│   ├── useClientOnlyValue.ts       # 客户端值 Hook 🎯
│   ├── useClientOnlyValue.web.ts   # Web 平台客户端值 🎯
│   └── index.ts                    # 统一导出
│
├── types/                           # TypeScript 类型
│   ├── api.ts                      # API 类型定义
│   └── index.ts                    # 统一导出
│
├── screens/                         # 业务页面组件 🎯
│   └── index.ts                    # 统一导出
│
├── 🧩 components/                   # 可复用组件
│   ├── Themed.tsx                  # 主题化组件 🎯
│   ├── ThemeDemo.tsx               # 主题演示组件 🎯
│   ├── ExternalLink.tsx            # 外部链接组件
│   └── index.ts                    # 统一导出 🎯
│
├── 🎨 theme/                        # 主题系统 🎯 NEW!
│   ├── index.ts                    # 统一导出
│   ├── utils.ts                    # 主题工具函数
│   └── styles.ts                   # 样式工厂(类似 CSS 类名)
│
├── 🎯 constants/                    # 常量配置
│   ├── Colors.ts                   # 颜色主题(完整配置)🎯
│   └── network.ts                  # 网络常量
│
├── 🎨 assets/                       # 静态资源
│   ├── images/                     # 图片资源
│   └── fonts/                      # 字体文件
│
├── 📚 docs/                         # 项目文档 🎯
│   ├── USAGE_EXAMPLES.md           # 使用示例
│   ├── LIBRARIES.md                # 工具库使用指南
│   ├── PROJECT_STRUCTURE_V2.md     # 项目结构说明 🎯
│   ├── MIGRATION_TO_FLAT_STRUCTURE.md  # 扁平化迁移报告 🎯
│   ├── STORES_ARCHITECTURE.md      # Stores 架构设计 🎯
│   ├── STORAGE_GUIDE.md            # 存储系统使用指南 🎯
│   ├── THEME_GUIDE.md              # 主题系统使用指南 🎯 NEW!
│   └── ... 更多文档
│
├── 🔧 scripts/                      # 脚本文件
│   └── proxy-server.js             # 代理服务器 🎯
│
├── ⚙ 配置文件
│   ├── .env.development            # 开发环境变量 🎯
│   ├── .env.production             # 生产环境变量 🎯
│   ├── app.json                    # Expo 配置 ⭐
│   ├── eas.json                    # EAS 构建和更新配置 ⭐
│   ├── package.json                # 项目依赖
│   ├── pnpm-lock.yaml              # pnpm 锁文件
│   ├── tsconfig.json               # TypeScript 配置
│   └── .gitignore                  # Git 忽略文件
│
└── 📄 文档文件
    ├── README.md                   # 项目主文档(本文件)
    └── CHANGELOG.md                # 更新日志

⭐ = 热更新相关的关键文件
🎯 = 新增/更新的文件/目录

关键目录说明

📱 app/ - 路由和页面

  • app/_layout.tsx - 应用启动时自动检查更新
  • app/(tabs)/index.tsx - 热更新演示页面
  • app/(tabs)/demo.tsx - 完整示例页面,展示所有工具的使用 🎯
  • app/test.tsx - 测试页面示例(不包含底部 tabs)🎯

💻 业务代码目录(扁平化结构)🎯

项目采用扁平化目录结构,所有业务模块都在根目录下:

  • utils/ - 工具函数

    • 网络请求(Axios + 加密)
    • 存储管理(AsyncStorage + SessionStorage)🎯
    • 日期处理(Day.js)
    • 配置管理
  • stores/ - 状态管理(Zustand)

    • 用户状态(登录、用户信息)
    • 应用设置(主题、语言、触觉反馈)
    • 租户状态 🎯
  • schemas/ - 数据验证(Zod)

    • 认证表单验证
    • 用户数据验证
  • services/ - API 服务层

    • 认证服务
    • 用户服务
    • 租户服务 🎯
  • hooks/ - 自定义 Hooks

    • 防抖/节流
    • 触觉反馈
    • 请求管理 🎯
    • 主题 Hooks(useColorScheme, useTheme, useClientOnlyValue)🎯
  • types/ - TypeScript 类型定义

  • screens/ - 业务页面组件 🎯

  • theme/ - 主题系统 🎯 NEW!

    • 统一的主题配置导出
    • 主题工具函数
    • 样式工厂(类似 CSS 类名)

每个目录都有 index.ts 文件,负责统一导出该目录下的所有模块。

🧩 components/ - 可复用组件

  • Themed.tsx - 主题化组件(ThemedText, ThemedView)🎯
  • ThemeDemo.tsx - 主题演示组件 🎯

📚 docs/ - 项目文档 🎯

完善的项目文档,包含:

  • 使用指南 - 如何使用各个工具
  • 代码示例 - 实际的代码示例
  • 配置说明 - 项目配置详解
  • 架构设计 - Stores 架构、存储系统等
  • 主题系统 - 主题配置和样式使用指南 🎯 NEW!
  • 迁移报告 - 扁平化目录结构迁移

核心文件说明

热更新相关

  • app.json - Expo 配置,包含热更新设置
  • eas.json - EAS 构建和更新通道配置
  • app/_layout.tsx - 自动检查更新逻辑
  • app/(tabs)/index.tsx - 手动检查更新功能

工具配置 🎯

  • 各目录的 index.ts - 统一导出,从这里导入所有工具
  • .env.development / .env.production - 环境变量配置 🎯
  • tsconfig.json - 配置了路径别名 @/*

已安装的工具库

项目已安装并配置好以下工具库:

类别 工具库 用途 状态
工具类 lodash-es JavaScript 工具函数
dayjs 日期处理
axios HTTP 请求
状态管理 zustand 轻量级状态管理
表单处理 react-hook-form 表单管理
zod 数据验证
原生功能 @react-native-async-storage/async-storage 本地存储
expo-image 优化的图片组件
expo-haptics 触觉反馈
UI 组件 react-native-paper Material Design 组件

快速开始

  1. 查看完整示例 - 运行应用,点击 "Demo" tab 🎯
  2. 阅读文档 - 查看 docs/ 目录中的文档
  3. 使用工具 - 从各个模块目录导入所需的工具
// ✅ 推荐:从模块目录导入
import { Storage, SessionStorage, StorageManager, formatDate } from '@/utils';
import { useUser, useTheme, useLanguage } from '@/stores';
import { authService, userService } from '@/services';
import {
  useDebounce,
  useHaptics,
  useColorScheme,
  useThemeColors,
  useClientOnlyValue,
} from '@/hooks';
import { loginSchema } from '@/schemas';

// ✅ 主题系统:统一从 theme 目录导入 🎯 NEW!
import {
  useColorScheme,
  useThemeColors,
  ThemedText,
  ThemedView,
  commonStyles,
  createThemeStyles,
} from '@/theme';

// ✅ 也可以:直接从具体文件导入
import { useUser } from '@/stores/userStore';
import { formatDate } from '@/utils/date';

🔥 热更新使用指南

重要提示:热更新功能需要在真实构建(Development Build 或 Production Build)中测试,Expo Go 不支持自定义热更新配置。

步骤 1:登录 EAS

eas login

如果没有账号,访问 expo.dev 注册一个免费账号。

步骤 2:初始化 EAS 项目

eas init

这会:

  • 创建一个唯一的项目 ID
  • 自动更新 app.json 中的 extra.eas.projectId

步骤 3:构建开发版本

Android 开发构建:

eas build --profile development --platform android

iOS 开发构建(需要 macOS 和 Apple 开发者账号):

eas build --profile development --platform ios

构建过程需要 10-20 分钟。完成后:

  1. expo.dev 控制台下载构建的 APK/IPA 文件
  2. 安装到你的设备上

步骤 4:发布热更新

  1. 修改代码(例如修改 app/(tabs)/index.tsx 中的文本)

  2. 发布更新到指定通道:

# 发布到开发通道
eas update --channel development --message "测试热更新功能"

# 发布到预览通道
eas update --channel preview --message "修复了某个 bug"

# 发布到生产通道
eas update --channel production --message "v1.0.1: 添加了新功能"

步骤 5:测试更新

  1. 打开已安装的应用
  2. 点击首页的 "检查更新" 按钮
  3. 应用会自动下载更新
  4. 点击 "立即重启" 应用更新
  5. 重启后即可看到更新内容 🎉

更新通道说明

项目配置了三个更新通道(在 eas.json 中定义):

通道 用途 适用场景
development 开发环境 日常开发和测试
preview 预览环境 内部测试和 QA
production 生产环境 正式发布给用户

不同的构建配置会订阅不同的更新通道:

# 构建订阅 development 通道的版本
eas build --profile development --platform android

# 构建订阅 preview 通道的版本
eas build --profile preview --platform android

# 构建订阅 production 通道的版本
eas build --profile production --platform android

推荐的发布流程

# 1. 开发和本地测试
pnpm start

# 2. 发布到 preview 通道进行内部测试
eas update --channel preview --message "测试新功能"

# 3. 测试通过后,发布到 production 通道
eas update --channel production --message "v1.0.1: 修复了登录问题"

# 4. 如果需要回滚
eas update --channel production --branch main --message "回滚到稳定版本"

监控和管理更新

# 查看所有更新历史
eas update:list

# 查看特定通道的更新
eas update:list --channel production

# 查看更新详情
eas update:view [update-id]

💻 开发指南

常用命令

# 开发相关
pnpm start              # 启动开发服务器
pnpm android            # 在 Android 上运行
pnpm ios                # 在 iOS 上运行(仅 macOS)
pnpm web                # 在浏览器中运行

# 热更新相关
eas login               # 登录 EAS
eas init                # 初始化 EAS 项目
eas build --profile development --platform android  # 构建开发版本
eas update --channel development --message "更新说明"  # 发布热更新
eas update:list         # 查看更新历史

# 构建相关
eas build --profile preview --platform android      # 构建预览版本
eas build --profile production --platform android   # 构建生产版本

修改代码示例

尝试修改以下内容来测试热更新:

示例 1:修改首页标题

打开 app/(tabs)/index.tsx,找到:

<Text style={styles.title}>🚀 热更新演示</Text>

改为:

<Text style={styles.title}>🎉 热更新测试成功!</Text>

示例 2:修改按钮样式

app/(tabs)/index.tsxstyles 中修改:

button: {
  backgroundColor: '#FF6B6B',  // 改为红色
  paddingHorizontal: 30,
  paddingVertical: 15,
  borderRadius: 10,
  marginBottom: 20,
  minWidth: 200,
  alignItems: 'center',
},

示例 3:添加新功能

在首页添加一个计数器:

const [count, setCount] = useState(0);

// 在 JSX 中添加
<TouchableOpacity style={styles.button} onPress={() => setCount(count + 1)}>
  <Text style={styles.buttonText}>点击次数: {count}</Text>
</TouchableOpacity>;

修改后,运行 eas update 发布更新,然后在应用中检查更新即可看到变化。

自定义更新行为

自动静默更新

修改 app/_layout.tsx 中的更新逻辑,移除 Alert 提示:

if (update.isAvailable) {
  await Updates.fetchUpdateAsync();
  await Updates.reloadAsync(); // 直接重启,不提示
}

强制更新

不提供"稍后"选项:

Alert.alert(
  '发现新版本',
  '请更新到最新版本',
  [
    {
      text: '立即更新',
      onPress: async () => {
        await Updates.reloadAsync();
      },
    },
  ],
  { cancelable: false } // 不可取消
);

配置说明

app.json 配置

关键配置项:

{
  "expo": {
    "name": "rn-demo",
    "slug": "rn-demo",
    "version": "1.0.0",
    "newArchEnabled": true, // 启用 React Native 新架构
    "updates": {
      "url": "https://u.expo.dev/your-project-id" // EAS Update 服务器
    },
    "runtimeVersion": {
      "policy": "appVersion" // 运行时版本策略
    },
    "plugins": [
      "expo-router", // Expo Router 插件
      "expo-updates" // 热更新插件
    ],
    "ios": {
      "bundleIdentifier": "com.rndemo.app"
    },
    "android": {
      "package": "com.rndemo.app"
    }
  }
}

配置说明:

  • updates.url - EAS Update 服务器地址(运行 eas init 后自动生成)
  • runtimeVersion.policy - 运行时版本策略,确保更新兼容性
    • appVersion - 基于 version 字段(当前使用)
    • nativeVersion - 基于原生构建号
  • plugins - 启用的 Expo 插件
  • newArchEnabled - 启用 React Native 新架构(Fabric + TurboModules)

eas.json 配置

构建和更新配置:

{
  "build": {
    "development": {
      "developmentClient": true, // 开发客户端
      "distribution": "internal", // 内部分发
      "channel": "development" // 订阅 development 更新通道
    },
    "preview": {
      "distribution": "internal",
      "channel": "preview" // 订阅 preview 更新通道
    },
    "production": {
      "channel": "production" // 订阅 production 更新通道
    }
  }
}

配置说明:

  • developmentClient - 是否为开发客户端(包含开发工具)
  • distribution - 分发方式(internalstore
  • channel - 更新通道,决定应用接收哪个通道的更新

📋 热更新最佳实践

何时使用热更新

适合热更新的场景:

  • 修复 JavaScript/TypeScript 代码 bug
  • 更新 UI 样式和布局
  • 修改业务逻辑
  • 更新文本内容和翻译
  • 调整配置参数
  • 添加新的 JS 功能

不适合热更新的场景(需要重新构建):

  • 添加/删除原生依赖(如 react-native-camera
  • 修改原生代码(iOS/Android)
  • 更改应用权限(如相机、位置权限)
  • 修改 app.json 中的原生配置
  • 升级 React Native 或 Expo SDK 版本
  • 修改应用图标或启动屏幕

版本管理策略

appVersion 策略(当前使用):

  • 基于 app.json 中的 version 字段
  • 优点:简单直观,易于理解
  • 注意:每次原生构建需要手动更新版本号

nativeVersion 策略

  • 基于原生构建号(iOS 的 buildNumber,Android 的 versionCode
  • 优点:自动管理,无需手动更新
  • 注意:需要配置原生构建号

更新策略建议

  1. 开发阶段:频繁发布到 development 通道
  2. 测试阶段:发布到 preview 通道,进行 QA 测试
  3. 生产发布:测试通过后发布到 production 通道
  4. 紧急修复:直接发布到 production 通道,快速修复线上问题

常见问题

Q: 为什么在 Expo Go 中看不到热更新功能?

A: Expo Go 是开发工具,不支持自定义热更新。需要使用 eas build 构建真实应用。

Q: 更新后没有生效?

A: 检查以下几点:

  1. 确保应用完全关闭后重新打开(不是后台切换)
  2. 检查更新通道是否匹配(development/preview/production)
  3. 确保 runtimeVersion 匹配
  4. 查看控制台是否有错误信息
  5. 检查网络连接

Q: 如何回滚到之前的版本?

A:

# 查看更新历史
eas update:list --channel production

# 重新发布之前的更新
eas update --channel production --branch main --message "回滚到稳定版本"

Q: 热更新的大小限制是多少?

A: EAS Update 没有严格的大小限制,但建议:

  • 保持更新包 < 10MB 以确保良好的用户体验
  • 避免在更新中包含大量图片或资源文件
  • 使用 CDN 托管大型资源

Q: 如何强制用户更新?

A: 修改 app/_layout.tsx 中的更新逻辑:

if (update.isAvailable) {
  await Updates.fetchUpdateAsync();
  Alert.alert(
    '发现新版本',
    '请更新到最新版本',
    [{ text: '立即更新', onPress: async () => await Updates.reloadAsync() }],
    { cancelable: false } // 不可取消
  );
}

Q: 更新检查的频率是多少?

A:

  • 应用启动时:自动检查(在 app/_layout.tsx 中配置)
  • 手动检查:用户点击"检查更新"按钮
  • 后台检查:可以配置定时检查(需要自己实现)

Q: 如何在开发时测试热更新?

A:

  1. 构建 Development Build:eas build --profile development --platform android
  2. 安装到设备
  3. 修改代码
  4. 发布更新:eas update --channel development --message "测试"
  5. 在应用中点击"检查更新"

Q: Web 平台的警告信息怎么处理?

A: 运行 pnpm web 时可能会看到 pointerEvents 的弃用警告,这是 react-native-web 库的内部问题,不影响功能,可以安全忽略。详见 docs/KNOWN_ISSUES.md

💡 开发提示

  • 开发时使用 pnpm start 即可,支持快速刷新(Fast Refresh)
  • 只有在测试热更新功能时才需要构建真实应用
  • 热更新只能更新 JavaScript/TypeScript 代码,不能更新原生代码
  • 建议使用 Git 管理代码版本,方便回滚
  • 每次发布更新时添加清晰的 --message 说明,便于追踪

📚 相关资源

官方文档

学习资源

社区

📚 项目文档

更多详细文档请查看 docs 目录:

使用指南


祝你开发愉快! 🎉

如有问题,请查看 常见问题 或访问 Expo 官方文档