IOS-DOC-003 实现阅读事件本地收集 #20

Open
opened 2026-05-30 19:56:07 +08:00 by wangdl · 1 comment
Owner

需要收集用户阅读行为:打开资料、停留时间、上次阅读位置、标记已读。

目标:iOS 侧接入 Rust ReadingEvent 并本地暂存。

事件:MaterialOpened、MaterialClosed、PositionChanged、Heartbeat、MarkedAsRead

实现建议:打开 MaterialReaderView 时记录 MaterialOpened、页面停留期间每 15 秒生成 Heartbeat、滚动/翻页时生成 PositionChanged、退出页面时生成 MaterialClosed、用户点击标记已读时生成 MarkedAsRead

验收标准:打开资料有事件、退出资料有事件、阅读时长可计算、Markdown 能记录 block/scroll 位置、PDF 至少能记录 pageNumber、事件可本地缓存

需要收集用户阅读行为:打开资料、停留时间、上次阅读位置、标记已读。 目标:iOS 侧接入 Rust ReadingEvent 并本地暂存。 事件:MaterialOpened、MaterialClosed、PositionChanged、Heartbeat、MarkedAsRead 实现建议:打开 MaterialReaderView 时记录 MaterialOpened、页面停留期间每 15 秒生成 Heartbeat、滚动/翻页时生成 PositionChanged、退出页面时生成 MaterialClosed、用户点击标记已读时生成 MarkedAsRead 验收标准:打开资料有事件、退出资料有事件、阅读时长可计算、Markdown 能记录 block/scroll 位置、PDF 至少能记录 pageNumber、事件可本地缓存
wangdl added this to the M3:iOS 主 App 资料阅读闭环 milestone 2026-05-30 19:56:07 +08:00
wangdl added the
priority:p0
type:implementation
area:ios
area:progress
labels 2026-05-30 19:56:07 +08:00
Author
Owner

实现完成 (2026-06-02)

新增文件

Features/MaterialReader/ReadingEventCollector.swift (~120 行)

单例 ReadingEventCollector,负责阅读事件生命周期管理:

  • open(materialId:) — 记录 MaterialOpened,启动 15s 心跳定时器
  • close(materialId:) — 停止心跳,记录 MaterialClosed(含 active_seconds)
  • updatePosition(materialId:position:) — 2s 防抖,记录 PositionChanged
  • markAsRead(materialId:) — 记录 MarkedAsRead
  • exportPending() → [ReadingEvent] — 导出所有未上报事件
  • clearExported(count:) — 确认前 count 条已上传

修改文件

MaterialReaderView.swift — 集成事件采集:

  • .onAppear → 触发 MaterialOpened
  • .onDisappear → 触发 MaterialClosed
  • Markdown 滚动跟踪 → 通过 GeometryReader + PreferenceKey 检测可见 block
  • 自动计算 scrollProgress,上报 PositionChanged

事件流程

打开页面 → MaterialOpened
15s → Heartbeat(含 activeSeconds + position)
滚动 → PositionChanged(2s 防抖)
15s → Heartbeat
...
关闭页面 → MaterialClosed(含累计 activeSeconds)
→ exportPending() → POST /reading/events → clearExported()
## 实现完成 (2026-06-02) ### 新增文件 **`Features/MaterialReader/ReadingEventCollector.swift`** (~120 行) 单例 `ReadingEventCollector`,负责阅读事件生命周期管理: - `open(materialId:)` — 记录 MaterialOpened,启动 15s 心跳定时器 - `close(materialId:)` — 停止心跳,记录 MaterialClosed(含 active_seconds) - `updatePosition(materialId:position:)` — 2s 防抖,记录 PositionChanged - `markAsRead(materialId:)` — 记录 MarkedAsRead - `exportPending() → [ReadingEvent]` — 导出所有未上报事件 - `clearExported(count:)` — 确认前 count 条已上传 ### 修改文件 **`MaterialReaderView.swift`** — 集成事件采集: - `.onAppear` → 触发 MaterialOpened - `.onDisappear` → 触发 MaterialClosed - Markdown 滚动跟踪 → 通过 `GeometryReader` + `PreferenceKey` 检测可见 block - 自动计算 scrollProgress,上报 PositionChanged ### 事件流程 ``` 打开页面 → MaterialOpened 15s → Heartbeat(含 activeSeconds + position) 滚动 → PositionChanged(2s 防抖) 15s → Heartbeat ... 关闭页面 → MaterialClosed(含累计 activeSeconds) → exportPending() → POST /reading/events → clearExported() ```
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: wangdl/zhixi-document-runtime#20
No description provided.