[Feature] Android 移动端交付方案:先落地 PWA,再评估 TWA/Capacitor

Author: ZhuLinsenCreated Jul 31, 2026Updated Aug 1, 2026
Labelsenhancement

功能描述 / Feature Description

评估并分阶段提供 Android 移动端体验。基于当前架构,建议先把现有 React Web 做成可安装 PWA;确认存在商店分发或原生能力需求后,再选择 TWA 或 Capacitor。现阶段不建议重写原生 UI,也不建议把完整 Python/FastAPI 分析后端打进 APK。

核心结论:

  • 近期推荐:移动端适配完善 + 可安装 PWA。
  • 可选第二阶段:有固定官方 HTTPS 域名并需要 Google Play 分发时,使用 TWA/Bubblewrap 打包 AAB。
  • 条件触发方案:需要原生推送、系统分享、扫码配对、生物识别等能力时,再引入 Capacitor。
  • 暂不实施:Flutter/React Native 重写;Android 本地嵌入完整 Python 分析后端。

使用场景 / Use Case

  • 用户希望在 Android 桌面直接打开 Web 工作台,查看报告、任务、持仓、预警和策略对话。
  • 官方托管服务需要 Google Play 商店入口。
  • 自托管用户希望从手机访问自己的 DSA 服务。
  • 后续可能需要推送通知、扫码绑定服务器、系统分享或文件导出。

需要先明确产品模式:

  1. 官方托管模式:Android 客户端固定连接官方 HTTPS 域名,适合 PWA/TWA。
  2. 自托管模式:用户访问各自服务器并安装 PWA;如需统一商店客户端,则要用 Capacitor 增加服务器地址配置、配对与移动端认证。
  3. 手机离线独立分析:需要把 Python 和重依赖搬到 Android,当前不建议进入实现范围。

当前实现分析

  • Web 使用 React + Vite,已有移动抽屉、响应式布局等基础,主要可复用代码位于 apps/dsa-web/
  • 当前不是 PWA:没有 Web App Manifest、Service Worker 注册和完整的应用图标/安装更新流程。
  • Vite 产物输出到根目录 static/,由 FastAPI 托管,适合继续保持同源部署。
  • Web API 默认同源,Axios 使用 withCredentials: true
  • 现有登录依赖 HttpOnly Session Cookie,Cookie 使用 SameSite=Lax;同源 PWA/TWA 可继续复用,Capacitor 跨源访问则需要重新设计 CORS 和移动端认证。
  • 页面中仍有多处 100vh 布局,需要验证 Android 地址栏、软键盘和安全区。
  • Electron 桌面端的“独立运行”来自本地 FastAPI + PyInstaller 后端。Android 无法低成本复用该打包链。
  • 后端包含 pandas、numpy、交易日历和多个数据源 SDK;嵌入 APK 会带来原生依赖、多架构、体积、后台执行和密钥安全风险。

方案复杂度

方案 适用范围 粗略工作量 复杂度
可安装 PWA Web/自托管/快速验证移动需求 3~7 人日 低到中
PWA + TWA 固定官方域名、Google Play 分发 PWA 后增加 2~5 人日
Capacitor + 官方服务 原生能力、固定后端 1~2 周
Capacitor + 任意自托管服务 服务器配置、配对、token、证书管理 2~4 周 中到高
APK 内置 Python 后端 手机离线独立分析 2~4 月以上 极高,不建议

以上是单人熟悉现有 Web/API 代码时的粗略估算,不包含商店审核等待时间。

期望实现 / Proposed Solution

Phase 1:先落地 PWA

  • 增加 manifest.webmanifest,配置名称、主题色、显示模式、scope、start URL。
  • 增加 192/512 图标和 maskable 图标,替换当前默认 Vite 图标和标题。
  • 增加 Service Worker;只缓存 UI 静态资源和离线提示,不缓存分析结果、配置、会话和其他敏感 API 响应。
  • 增加安装提示、版本更新提示和失败回退。
  • 处理 Android 软键盘、返回导航、下载/上传、外部链接和网络恢复。
  • 审核 100vh,按需迁移为 100dvh 并处理 safe-area。
  • 在 HTTPS 同源部署下验证登录、退出和 Session Cookie。
  • 补充 PWA 使用、部署与故障排查文档。
  • 更新 docs/CHANGELOG.md
  • 如改变页面视觉或安装交互,在 PR 描述附 Android 真机截图,不把一次性验收截图提交进仓库。

Phase 1 非目标:

  • 不提供业务数据离线分析。
  • 不实现 Android 原生推送。
  • 不引入新的移动端认证协议。
  • 不打包 Python/FastAPI 后端。
  • 不承诺 Google Play 上架。

Phase 2:按条件选择 TWA

仅在以下条件满足后进入:

  • 已有稳定的官方 HTTPS 域名和可用性保障。
  • PWA 真机验收通过并有明确的商店分发需求。
  • 隐私政策、Data Safety、账号删除/数据删除路径和金融功能声明已评估。
  • 签名密钥和发布责任人已明确。

实现范围:

  • apps/dsa-android/ 建立 TWA/Bubblewrap 工程。
  • 配置包名、版本、图标、启动行为和 Android Target SDK。
  • 在官网发布 .well-known/assetlinks.json,同时验证本地签名和 Play App Signing 指纹。
  • 构建测试 APK 和商店用签名 AAB。
  • 增加 Android 构建/发布工作流,签名材料只通过 GitHub Secrets 注入。
  • 准备商店描述、截图、隐私政策及必要声明。

Phase 3:仅在需要原生能力时评估 Capacitor

进入条件建议为:至少存在一个 PWA/TWA 无法可靠满足的核心能力,例如原生推送、系统分享、扫码配对、生物识别或受控文件访问。

在开始前必须先收敛:

  • 固定官方后端还是允许连接任意自托管后端。
  • 运行时 API 地址及 HTTPS/证书策略。
  • 移动端 token/配对认证、Android Keystore、安全退出和设备吊销。
  • CORS 白名单,不使用允许全部来源代替正式认证设计。
  • Android 返回键、深链、下载、网络恢复和应用生命周期契约。
  • Web、Desktop 与 Android 的认证/API 兼容策略。

Phase 1 验收标准

  • Android Chrome 可识别为可安装应用,并能从桌面以 standalone 模式启动。
  • 首次加载、安装、升级、退出登录和重新登录行为正确。
  • 无网络时明确显示离线状态,不展示过期行情或分析结果冒充实时数据。
  • Service Worker 更新不会使用户长期停留在旧 JS/API 契约。
  • 首页、聊天、持仓、决策信号、筛选、回测、预警、设置等关键页面在真机可操作。
  • 软键盘弹出、横竖屏切换、返回键、长报告滚动、文件上传/下载无阻断问题。
  • cd apps/dsa-web && npm run lint && npm run test && npm run build 通过。
  • 运行受影响的 Playwright smoke;真机验收结果记录在 PR 描述或 Actions artifact。

风险与边界

  • Service Worker 不得缓存鉴权响应、用户配置、报告数据或股票实时接口。
  • 自托管用户若使用明文 HTTP、无效证书或直接暴露局域网端口,不应被移动客户端静默绕过安全检查。
  • TWA 绑定具体域名,不适合直接作为连接任意自托管服务器的通用客户端。
  • Capacitor “生成 Android 工程”本身不难,真正工作量主要来自跨源认证和自托管服务器信任模型。
  • 股票分析应用进入 Google Play 时,需要单独评估金融功能分类、免责声明、隐私和数据处理声明。
  • 当前项目仅供学习研究、不构成投资建议的边界应继续在移动端用户可见位置保留。

备选方案 / Alternatives Considered

  1. 保持当前响应式 Web:成本最低,但缺少安装、更新、离线壳和应用化体验。
  2. 直接 TWA:需要先具备合格 PWA 和固定官方域名,不适合作为第一步。
  3. 直接 Capacitor:可扩展原生能力,但会提前引入 Android 工程、认证和发布维护面。
  4. Flutter/React Native 重写:重复实现现有 React UI、API 类型和测试,当前收益不足。
  5. Android 内置 Python 后端:重依赖、SDK、多架构及后台运行风险过高,暂不采用。

相关信息 / Additional Context

分析基线:

  • 已执行 git fetch --all --prune

  • 使用最新 origin/main@831ada53 分析。

  • 本地工作树位于 2d1545b2;当前功能分支相对其远端 ahead 1 / behind 24,无法 fast-forward,因此未执行 pull、切分支、stash、reset 或覆盖本地提交。

  • 是否愿意贡献代码实现 / Willing to implement: 待确认

Source: ZhuLinsen/daily_stock_analysis