Files
2026-01-28 23:41:03 +08:00
..
2026-01-28 22:54:21 +08:00
2026-01-28 23:41:03 +08:00
2026-01-28 22:54:21 +08:00
2026-01-28 23:41:03 +08:00
2026-01-28 22:54:21 +08:00
2026-01-28 22:54:21 +08:00

正念 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 工程(示例):

cd client
npx create-expo-app@latest .

执行后按提示选择模板即可;如果你希望固定使用 TypeScript 模板,也可以在创建时选择对应模板(以实际 CLI 提示为准)。

2安装依赖

cd client
pnpm install

3配置环境变量dev / prod

按根目录约定,客户端使用 .env.dev.env.prod 区分环境;.env 文件不提交到 Git仓库内应提供 .env.example 作为模板。

本地开发如何注入环境变量(推荐)

Expo 在本地开发时会自动读取当前目录下的 .env / .env.local(仅以 EXPO_PUBLIC_ 前缀变量注入到客户端运行时)。推荐做法:

cd client
cp .env.example .env.local
# 然后按需修改 .env.local
pnpm start

修改 .env* 后需要重启 pnpm start 才会生效。

本地开发如何区分 dev / prod可选

如果你希望坚持使用 .env.dev / .env.prod 文件名可以在启动前导出环境变量zsh 示例):

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:固定默认语言(仍允许用户在设置中切换并持久化)

建议字段(示例):

EXPO_PUBLIC_API_BASE_URL=http://localhost:8000
EXPO_PUBLIC_ENV=dev
EXPO_PUBLIC_DEFAULT_LANGUAGE=auto

提示:在 Expo 中建议使用 EXPO_PUBLIC_ 前缀,方便在运行时读取并支持 EAS 构建注入。

4启动开发服务器

cd client
pnpm start

启动后你会看到终端输出的二维码QR Code与可用命令提示。

5运行到 iOS / Android / 真机 / Web

  • iOS 模拟器macOS + Xcode
    • 方式一:在 pnpm start 的终端里按 i
    • 方式二:直接运行:
cd client
pnpm ios
  • Android 模拟器Android Studio
    • 方式一:在 pnpm start 的终端里按 a
    • 方式二:直接运行:
cd client
pnpm android
  • 真机(推荐使用 Expo Go

    • 手机安装 Expo Go
    • 确保手机与电脑在同一局域网
    • 运行 pnpm start 后,用 Expo Go 扫描终端二维码即可打开 App
  • Web可选

cd client
pnpm web

常用命令(脚本):

pnpm ios
pnpm android
pnpm web

6常见问题

  • 真机打不开 / 扫码后卡住
    • 检查手机与电脑是否同一 Wi-Fi
    • 尝试重启 pnpm start -- --clear 清缓存
  • 启动时提示 Networking has been disabled / Network connection is unreliable
    • 这是 Expo CLI 的网络探测/请求失败导致的,按下面方式跳过网络请求即可:
cd client
EXPO_OFFLINE=1 pnpm start
  • 如果你本机设置了代理(例如 HTTP_PROXY/ALL_PROXY),也可以临时关闭代理后再启动:
cd client
unset HTTP_PROXY HTTPS_PROXY ALL_PROXY
pnpm start
  • Watchman 提示 Recrawl不影响运行但建议处理
    • 按提示执行一次即可清除警告:
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

建议目录结构

src/
└── i18n/
    ├── index.ts               # i18n 初始化(默认语言、回退语言、资源注册)
    ├── locales/
    │   ├── zh-CN.json
    │   ├── en.json
    │   ├── es.json
    │   ├── pt.json
    │   └── zh-TW.json
    └── types.ts               #(可选)语言码与 key 的类型定义

约定与最佳实践

  • key 规则:使用稳定的点分层 key例如 common.okpush.permissionTitlecards.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

  • devcom.damer.mindfulness.dev
  • prodcom.damer.mindfulness

常见流程(示例):

cd client
eas login
eas build --platform ios --profile development

实际 profile、证书、bundle id、环境变量注入方式以工程内 eas.json / app config 为准。

目录结构(建议)

当客户端工程落地后建议使用更标准、可扩展的目录结构Expo + TypeScript 常见组织方式):

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 工程

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 勾选:情绪小组件)。

Widget 点击跳转使用:

  • client:///(app)/home

代码里已通过 widgetURL 设置(见 MindfulnessWidget.swift)。