getsentry / getsentry/sentry-java
Nav3: Multistack support
- 主要語言
- Kotlin
- 星號
- 1.4k
- 分支
- 478
- 平均合併
- 3 天 4 小時
- 30 天內合併 PR
- 72
描述
### Problem Statement
Apps with bottom tabs, drawer navigation, or similar patterns often maintain multiple independent backstacks – one per top-level destination – so that users can switch tabs without losing their place. [Nav3]() doesn't provide a built-in multi-back-stack API; instead, apps own multiple `NavBackStack` instances and merge their entries before passing them to `NavDisplay` (see the [`multiplestacks` recipe]()).
The Stage 1 integration (getsentry/sentry-java#5000) and multipane support (getsentry/sentry-java#5649) handle a single `SnapshotStateList` backstack. When an app uses multiple stacks, the SDK needs to understand which stack is active and scope its telemetry accordingly.
### Solution Brainstorm
* **Stack identification.** Introduce a `stack_id` concept so breadcrumbs, transactions, and crash context can group navigations per stack. This could be a user-supplied label per stack (e.g. the tab route key's name), or inferred from the `NavBackStack` identity.
* **API surface.** Provide a way to register multiple backstacks with a shared `SentryNavStateHolder`, or create per-stack holders that coordinate. The app tells us which stack is currently active (likely by passing the active `topLevelRoute` or equivalent).
* `scope.screen` – set to the active stack's top route. When the user switches tabs, this triggers a navigation breadcrumb and updates `scope.screen` to the new stack's current top.
* **Breadcrumbs** – capture both intra-stack navigation (push/pop within a tab) and inter-stack switches (tab change). Include `stack_id` in breadcrumb data so the two can be distinguished. A tab switch breadcrumb might look like `{ from: "/settings/profile", to: "/home/feed", stack_id: "home" }`.
* **Transactions** – when the user switches to a stack whose top entry hasn't changed, should we start a new transaction? Probably not – the screen was already loaded. Only start a transaction on an actual new destination within the stack.
* **Crash context (**`contexts.navigation`**)** – include all stacks (not just the active one), capped by `maxBackstackSize` total across stacks. Mark which stack is active.
Open questions:
* Should `contexts.navigation.backstack` flatten all stacks into one list, or nest them by `stack_id`?
* How do multistack and multipane compose? A tablet app might have bottom tabs (multistack) where one tab shows a list-detail layout (multipane). The primary pane logic from Stage 2 should still apply within the active stack.
* Should tab switches reuse the existing `"navigation"` breadcrumb category or get a distinct one (e.g. `"stack_switch"`)?
* Do we want to revisit Nav2 simplifications alongside this (nested nav graphs, dialog/bottom-sheet transaction behavior)?
### Existing Nav2 support
Nav2 supports multiple backstacks natively via `NavController.navigate()` with `saveState = true` / `restoreState = true`, commonly used with `NavigationBar` or `BottomNavigation`. However, the current Nav2 integration does not distinguish between stacks – it sees a flat stream of destination changes on a single `NavController` and treats every destination change identically. There is no `stack_id`, no differentiation between intra-tab navigation and tab switches, and no per-stack grouping in crash context. A tab switch looks the same as a forward navigation in telemetry.
貢獻指南
研究方向
首先查看 Nav3 的 multistacks recipe,以及 issue 中引用的 Stage 1 和 multipane 整合。確定多個 NavBackStack instance、作用中的頂層 route 和 NavDisplay 的表示方式,然後再解決未決的 API 和 telemetry 問題。完成的標準是:multistack 行為及其與 Nav2、multipane 支援、breadcrumbs、transactions 和 navigation context 的互動已完成規格說明,並由測試涵蓋。
由索引模型根據 Issue 內容生成。
評估
- 技術堆疊
- android, kotlin
- 領域
- mobile, observability
- Issue 類型
- 功能
- 難度
- 5/5
- 預估耗時
- 一週以上
- 活躍度
- 冷清
- 描述清晰度
- 需要釐清
- 新手友好度
- 30/100