Files
mindfulness/client/README.md
2026-01-28 22:54:21 +08:00

344 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 正念 APP客户端
本目录用于存放「正念 APP」客户端工程定位是面向宝妈人群的情绪价值与正念练习支持应用。
## 功能概览(一期)
- **APP-PUSH 推送**:定时推送情绪文字(固定时间 / 用户自定义时间),推送内容可由后端配置更新
- **iOS 小组件Widget**:展示当前情绪文字与背景图/渐变色,支持多尺寸与可配置刷新频率
- **情绪卡片滑动**:卡片列表左右滑动切换(类似 Tinder收藏/分享可作为后续迭代
## 技术栈
- **React Native + Expo**
- **TypeScript**
- **React Navigation**:页面路由
- **状态管理**Zustand或 Redux Toolkit
- **网络请求**Axios或 Fetch
- **推送**Expo Notifications
- **环境区分**Expo App Config + `.env.dev` / `.env.prod`
- **iOS 打包**EAS Build
## 开发环境要求
- **Node.js**:建议使用 **20+LTS**
- **包管理器**pnpm
- **Expo CLI**:推荐通过 `npx expo` 使用(避免全局版本漂移)
- **iOS 真机调试**macOS + Xcode如需
> 本项目已内置 `postinstall` 补丁脚本用于兼容(安装依赖后会自动修复),但仍建议升级到 Node 20+。
## 快速开始
> 说明:本仓库已包含 Expo 工程文件;如果你只是想把客户端跑起来,从「安装依赖」开始即可。
### 1初始化工程若尚未创建
`client/` 目录下创建 Expo 工程(示例):
```bash
cd client
npx create-expo-app@latest .
```
执行后按提示选择模板即可;如果你希望固定使用 TypeScript 模板,也可以在创建时选择对应模板(以实际 CLI 提示为准)。
### 2安装依赖
```bash
cd client
pnpm install
```
### 3配置环境变量dev / prod
按根目录约定,客户端使用 `.env.dev``.env.prod` 区分环境;`.env` 文件不提交到 Git仓库内应提供 `.env.example` 作为模板。
#### 本地开发如何注入环境变量(推荐)
Expo 在本地开发时会自动读取当前目录下的 `.env` / `.env.local`(仅以 `EXPO_PUBLIC_` 前缀变量注入到客户端运行时)。推荐做法:
```bash
cd client
cp .env.example .env.local
# 然后按需修改 .env.local
pnpm start
```
> 修改 `.env*` 后需要重启 `pnpm start` 才会生效。
#### 本地开发如何区分 dev / prod可选
如果你希望坚持使用 `.env.dev` / `.env.prod` 文件名可以在启动前导出环境变量zsh 示例):
```bash
cd client
set -a
source .env.dev
set +a
pnpm start
```
> 注意:`source` 方式要求 `.env.dev` 内容是合法的 shell 格式(例如 `KEY=value`),不要带 `export` 以外的复杂语法;值包含空格时需要加引号。
#### 必填环境变量
- **`EXPO_PUBLIC_API_BASE_URL`**:后端 API 基地址
- 本地:`http://localhost:8000`
- 真机联调:改为电脑局域网 IP例如 `http://192.168.1.10:8000`
- **`EXPO_PUBLIC_ENV`**:环境标识(建议 `dev` / `prod`
#### 可选环境变量
- **`EXPO_PUBLIC_DEFAULT_LANGUAGE`**:默认语言策略
- `auto`:优先设备语言(默认)
- `zh-CN/en/es/pt/zh-TW`:固定默认语言(仍允许用户在设置中切换并持久化)
建议字段(示例):
```env
EXPO_PUBLIC_API_BASE_URL=http://localhost:8000
EXPO_PUBLIC_ENV=dev
EXPO_PUBLIC_DEFAULT_LANGUAGE=auto
```
> 提示:在 Expo 中建议使用 `EXPO_PUBLIC_` 前缀,方便在运行时读取并支持 EAS 构建注入。
### 4启动开发服务器
```bash
cd client
pnpm start
```
启动后你会看到终端输出的二维码QR Code与可用命令提示。
### 5运行到 iOS / Android / 真机 / Web
- **iOS 模拟器macOS + Xcode**
- 方式一:在 `pnpm start` 的终端里按 `i`
- 方式二:直接运行:
```bash
cd client
pnpm ios
```
- **Android 模拟器Android Studio**
- 方式一:在 `pnpm start` 的终端里按 `a`
- 方式二:直接运行:
```bash
cd client
pnpm android
```
- **真机(推荐使用 Expo Go**
- 手机安装 **Expo Go**
- 确保手机与电脑在**同一局域网**
- 运行 `pnpm start` 后,用 Expo Go 扫描终端二维码即可打开 App
- **Web可选**
```bash
cd client
pnpm web
```
常用命令(脚本):
```bash
pnpm ios
pnpm android
pnpm web
```
### 6常见问题
- **真机打不开 / 扫码后卡住**
- 检查手机与电脑是否同一 Wi-Fi
- 尝试重启 `pnpm start -- --clear` 清缓存
- **启动时提示 `Networking has been disabled` / `Network connection is unreliable`**
- 这是 Expo CLI 的网络探测/请求失败导致的,按下面方式跳过网络请求即可:
```bash
cd client
EXPO_OFFLINE=1 pnpm start
```
- 如果你本机设置了代理(例如 `HTTP_PROXY/ALL_PROXY`),也可以临时关闭代理后再启动:
```bash
cd client
unset HTTP_PROXY HTTPS_PROXY ALL_PROXY
pnpm start
```
- **Watchman 提示 Recrawl不影响运行但建议处理**
- 按提示执行一次即可清除警告:
```bash
watchman watch-del '/Users/jojo/Desktop/lxy/gitea/mindfulness/client' ; watchman watch-project '/Users/jojo/Desktop/lxy/gitea/mindfulness/client'
```
- **联调时请求打到 localhost**
- 真机上 `localhost` 指向手机自身,请把 `EXPO_PUBLIC_API_BASE_URL` 改成电脑的局域网 IP例如 `http://192.168.1.10:8000`),或使用内网穿透方案
## 与后端联调
- **后端基座**FastAPI详见 `server/README.md`
- **API Base URL**:通过 `EXPO_PUBLIC_API_BASE_URL` 配置
- **本地真机注意**:如果在手机上调试,请将 `localhost` 替换为电脑局域网 IP或使用内网穿透方案
## 多语言i18nCN / EN / ES / PT / TC
### 语言码约定
- **CN简体中文**`zh-CN`
- **EN英语**`en`
- **ES西班牙语**`es`
- **PT葡萄牙语**`pt`
- **TC繁体中文**`zh-TW`
### 推荐选型Expo/RN 常用组合)
- **文案管理**`i18next` + `react-i18next`
- **系统语言读取**`expo-localization`
### 建议目录结构
```text
src/
└── i18n/
├── index.ts # i18n 初始化(默认语言、回退语言、资源注册)
├── locales/
│ ├── zh-CN.json
│ ├── en.json
│ ├── es.json
│ ├── pt.json
│ └── zh-TW.json
└── types.ts #(可选)语言码与 key 的类型定义
```
### 约定与最佳实践
- **key 规则**:使用稳定的点分层 key例如 `common.ok``push.permissionTitle``cards.swipeHint`
- **默认与回退**:默认优先跟随用户当前设备语言(在支持列表内时生效);设备语言不支持时回退到 `zh-CN`(或团队指定默认)
- **插值与复数**:优先使用 i18next 的插值(例如 `{{name}}`),避免在代码里拼字符串
- **动态切换**:提供“语言设置”入口允许手动切换;切换后持久化(例如 AsyncStorage后续启动优先生效并立即刷新文案
- **语言优先级**:用户设置(若存在)> 设备语言(在支持列表内)> 默认回退(`zh-CN` 或团队指定默认)
- **设置入口建议**:设置页 -> 语言(或 设置页 -> 通用 -> 语言)
- **与服务端一致性**:若后端也需要多语言(推送文案等),建议统一语言码(`zh-CN/en/es/pt/zh-TW`)并在接口里明确 `lang`
## 推送Expo Notifications
客户端侧通常需要:
- **申请通知权限**
- **获取 Expo Push Token**
- **将 Token 上报后端**(用于定时推送任务)
后端侧通常需要:
- **保存用户 Push Token**
- **按策略触发推送**(固定时间 / 用户自定义时间)
- **支持后台配置推送文案并更新**
> 具体实现以客户端工程代码为准;当代码接入后,建议在 README 补充「Token 上报接口」与「字段定义」。
## iOS 小组件Widget
小组件通常需要:
- **数据源**:来自本地缓存或后端拉取(需要设计刷新策略与缓存)
- **展示内容**:当前情绪文字 + 背景图/渐变
- **尺寸**:小 / 中 / 大
- **刷新频率**:如每小时/每天iOS 对频率有系统限制,以实际效果为准)
> 若你计划使用 Expo 的相关能力,请在工程中明确选型与实现路径,并补充到本 README。
## EAS BuildiOS 打包)
建议按根目录约定区分 dev/prod
- **dev**`com.damer.mindfulness.dev`
- **prod**`com.damer.mindfulness`
常见流程(示例):
```bash
cd client
eas login
eas build --platform ios --profile development
```
> 实际 profile、证书、bundle id、环境变量注入方式以工程内 `eas.json` / app config 为准。
## 目录结构(建议)
当客户端工程落地后建议使用更标准、可扩展的目录结构Expo + TypeScript 常见组织方式):
```text
client/
├── app/ #推荐expo-router 路由目录(若使用 expo-router
│ ├── (tabs)/ # Tabs 分组(可选)
│ ├── _layout.tsx # 根布局
│ └── index.tsx # 首页
├── src/ # 业务源码(与路由/平台代码解耦)
│ ├── components/ # 通用 UI 组件
│ ├── features/ # 按功能域拆分(推荐)
│ │ ├── push/ # 推送相关权限、token、上报等
│ │ ├── widget/ # 小组件数据与样式相关
│ │ └── cards/ # 情绪卡片滑动相关
│ ├── hooks/ # 自定义 hooks
│ ├── navigation/ #(若不用 expo-routerReact Navigation 配置
│ ├── screens/ #(若不用 expo-router页面
│ ├── services/ # API 封装request、接口定义
│ ├── store/ # 状态管理Zustand/RTK
│ ├── utils/ # 工具函数(时间、格式化、校验等)
│ ├── constants/ # 常量与配置(主题、枚举等)
│ └── types/ # 全局类型声明
├── assets/ # 静态资源(图片/字体/音频等)
├── app.json / app.config.ts # Expo 配置(环境区分可在此处理)
├── eas.json # EAS Build 配置(如使用)
├── package.json
└── README.md
```
> 说明:如果你不使用 `expo-router`,可以删除 `app/`,并以 `src/navigation/` + `src/screens/` 作为主路由结构;其余目录保持不变即可。
## iOS 小组件开发V1写死文案
> 重要:**Expo Go 不支持 WidgetKit**。要做真正的小组件,必须预构建 iOS 工程并用 Xcode 跑。
### 1生成 iOS 工程
```bash
cd client
npx expo prebuild -p ios --no-install
```
生成后会得到 `client/ios/`Xcode 工程文件都在里面)。
### 2在 Xcode 创建 Widget Extension
- 用 Xcode 打开:`client/ios/client.xcworkspace`
- 菜单:`File -> New -> Target... -> Widget Extension`
- Target 名称示例:`MindfulnessWidget`
### 3写死文案与三尺寸布局
仓库里已提供 SwiftUI 代码骨架(写死文案 + Small/Medium/Large + 点击跳转):
- `client/ios/情绪小组件/EmotionWidget.swift`
创建 Widget target 后,把该文件加入到 Widget target 中即可Target Membership 勾选:`情绪小组件`)。
### 4点击跳转到 HomeDeep Link
Widget 点击跳转使用:
- `client:///(app)/home`
代码里已通过 `widgetURL` 设置(见 `MindfulnessWidget.swift`)。