应用门禁

生物识别锁、更新、引导、法律同意和认证路由。

App gates 是进入 main shell 之前和跨应用的关键流程:生物识别解锁、错误兜底、更新、 onboarding、法律 consent,以及由 session 驱动的 auth routing。

部分模板说明列的是旧顺序。当前代码顺序是 BiometricGate -> ErrorBoundary -> UpdateGate -> OnboardingGate -> ConsentGate -> MainNavGraph

提供什么

Gate状态实现
Biometric app lockIntegratedBiometricGate 包裹整个应用内容
Error fallbackIntegratedErrorBoundary 观察 AppErrorBus
Update gatePlay-onlyUpdateGate 显示 force 或 soft update dialogs
OnboardingIntegrated四页 HorizontalPager,状态保存在 DataStore
Legal consentIntegrated版本化 terms/privacy/EULA consent 存在 DataStore
Auth routingIntegratedSessionController.currentUser 登录后弹出 auth graph
Store reviewPlay-onlyRatingController 通过 smart triggers 触发

关键文件

启动组合

MainActivity 设置主题和 locale host,然后这样包裹导航图:

LocalizedAppHost
  -> BiometricGate
  -> ErrorBoundary
  -> AppNavGraph
      -> UpdateGate
      -> OnboardingGate
      -> ConsentGate
      -> MainNavGraph
          -> MainShell or AuthGraph

MainNavGraph 由 session 驱动。它从 main shell 开始,在需要登录的页面打开 auth graph,并在 SessionController.currentUser 变为非空时 pop auth graph。

Biometric gate

BiometricGate 只在用户从 Account Security 启用 biometric lock 后保护整个应用。它使用 BIOMETRIC_STRONGBiometricManager,把启用状态保存在 DataStore,并把 lastAuthenticatedAtMillis 保存在内存中。

行为:

  • biometric lock 关闭时,gate 直接渲染内容。
  • 没有注册 strong biometric 时,Account Security 会显示 NotEnrolledUnavailable
  • 启用后且超过 relock delay,gate 显示锁屏并打开 BiometricPrompt
  • 默认 relock delay 是 30_000 毫秒。

Update gate

真实更新流程是 Play-only。UpdateGatelocal.properties 读取这些 BuildConfig 值:

MIN_APP_VERSION=1.0.0
LATEST_APP_VERSION=1.1.0
APP_UPDATE_URL=https://play.google.com/store/apps/details?id=com.soarstarter.kotlin
APP_UPDATE_MESSAGE=Update to keep using the latest experience.

UpdateController 把这些版本和 BuildConfig.VERSION_NAME 比较。如果已安装版本低于 MIN_APP_VERSION,显示不可关闭的 force-update dialog,并请求 Play In-App Updates 的 immediate update。如果低于 LATEST_APP_VERSION,显示可关闭的 soft update,并请求 flexible update。

当 Play In-App Updates 无法启动时,应用会打开 APP_UPDATE_URL,或默认的 Play Store package URL。本地 debug build 可以测试版本比较和 fallback link;真实 in-app update 流程需要 Play-delivered build。

Onboarding gate

OnboardingGate 等待 DataStore 中的 onboardingCompleted flag hydrate。若 flag 为 false, 它会显示 OnboardingScreen,这是一个四页 HorizontalPager,包含 skip、next 和 get-started 动作。

onboarding 完成时,gate 会:

  1. 记录 AnalyticsEvent.OnboardingCompleted(slideCount)
  2. 在 DataStore 中保存 onboarding_completed = true
  3. 用 reason onboarding_completed 记录一次 store-review trigger。

Showcase tab 也有 onboarding replay screen,但 replay 不会修改真实 DataStore flag。

ConsentGate 等待已接受的法律版本 hydrate。当前版本是代码常量:

const val LEGAL_VERSION = "2026-04-30"

它不是 local.properties key。当 bundled terms/privacy/EULA 文案变化,并且你希望用户重新 接受时,更新这个常量。

法律文档是 bundled string resources,并可使用这些在线 URL:

LEGAL_TERMS_URL=https://example.com/terms
LEGAL_PRIVACY_URL=https://example.com/privacy
LEGAL_EULA_URL=https://example.com/eula

gate 会把已接受版本保存在 DataStore 的 accepted_legal_version

当前应用在 SoarApp.onCreate() 中启动 PostHog,早于 ConsentGate。法律 gate 记录用户 接受 bundled terms,但当前不会阻止 analytics 初始化。如果你的政策要求 consent-before-tracking, 请把 analyticsController.start() 移到 hasAcceptedCurrent 后面,或在 consent 前保持 POSTHOG_DISABLED=true

Store review

RatingController 封装 Google Play In-App Review。它会在 onboarding 完成和 referral 分享后记录 trigger;Showcase 的 rating demo 也可以手动请求 review flow。

smart prompt 规则:

规则
最少记录动作数3
同版本重复提示阻止
成功展示后的冷却时间90

真实 review UI 是 Play-only,且由 Google Play 控制。debug build 可以调用 controller,但 Play 可能不会显示 dialog。

自定义 gates

  • 通过修改 MainActivityAppNavGraph 中的 wrappers 来重排 gates。
  • 删除 OnboardingGate 和对应 DataStore key 读取,即可移除 onboarding。
  • 删除 ConsentGate 可移除 legal consent;也可以保留法律页面,仅从 Settings 打开。
  • BiometricGate 传入不同的 relockDelayMillis 来修改 biometric timing。
  • UpdateController.overrideRemoteConfig() 把静态更新值替换成 hosted config。

验证

  • 全新安装会显示 onboarding,然后 legal consent,然后 main shell。
  • 修改 LEGAL_VERSION 会重新显示 consent gate。
  • MIN_APP_VERSION 设置高于当前 versionName 会显示 force update dialog。
  • LATEST_APP_VERSION 设置高于当前 versionName 会显示 soft update dialog,且同版本可关闭一次。
  • 从 Account Security 启用 biometric lock 后,超过 relock delay 会锁住应用。
  • Store review 只有在 action count、version、cooldown 规则允许时才触发。

相关页面

On this page