应用门禁

自定义 onboarding、协议同意、版本、生物识别、认证和评分流程。

Expo 模板的启动门禁是围绕 router <Stack> 的兄弟组件,不是 native wrapper chain。自定义时要区分哪些 gate 会 redirect,哪些 gate 会覆盖当前页面。

真实拓扑

app/_layout.tsx 先挂载 providers,再按这个顺序渲染 gates:

RootErrorBoundary
  -> providers
  -> OnboardingGate
  -> AuthGate
  -> VersionGate
  -> <Stack />
  -> ConsentGate
  -> BiometricGate
  -> PortalHost
Gate行为说明
RootErrorBoundaryError boundary包住整个 app,并上报到 Sentry
OnboardingGateRedirect首次启动用户会去 /onboarding,但 onboarding、refer、legal 路由除外
AuthGateRedirect cleanupguest-first;只在登录成功后关闭 auth 页面
VersionGateOverlay modal/dialog强制更新会阻断;软更新可关闭
ConsentGateOverlay modal要求接受当前 legal version;阅读 legal 页面时不弹出
BiometricGate全屏 overlay对启用生物识别锁的已登录用户锁住全局页面

Onboarding

lib/onboarding.tsx 把完成状态存在自己的 cache key:

growth.onboarding.v1

app/onboarding.tsx 渲染四张 slide:

launch -> protect -> grow -> permissions

完成 onboarding 会发送 onboarding completed analytics event、记录一次评分触发、持久化 { completed: true, completedAt },然后替换路由到 Home。

Auth gate

应用是 guest-first。AuthGate 不会在启动时把整个 app 锁在登录页。需要登录的动作由具体屏幕或组件里的 SignInGate 处理。

当用户已经登录,但仍停留在 (auth) 组且不是 password recovery 时,AuthGate 会关闭认证流程:

canGoBack() -> router.back()
otherwise   -> router.replace("/")

这样登录流程像由当前任务唤起的 modal,同时也允许冷启动直接进入登录路由。

版本门禁

lib/app-update-config.ts 读取这些 env 配置:

EXPO_PUBLIC_MIN_APP_VERSION=
EXPO_PUBLIC_LATEST_APP_VERSION=
EXPO_PUBLIC_APP_UPDATE_URL=
EXPO_PUBLIC_APP_UPDATE_MESSAGE=
EXPO_PUBLIC_APP_UPDATE_CONFIG_URL=

如果设置了 APP_UPDATE_CONFIG_URL,app 会拉取远程 JSON,并让远程配置覆盖 env 值。TanStack Query 缓存的 staleTime 是 10 分钟。

状态规则
强制更新CURRENT_APP_VERSION < minVersion;显示不可关闭的 modal
软更新CURRENT_APP_VERSION < latestVersion;显示可关闭 dialog
不显示没有配置、当前版本不旧,或打开 URL 失败

本地测试可以在 app.config.ts 仍为 1.0.0 时设置 EXPO_PUBLIC_MIN_APP_VERSION=2.0.0,重启 Metro 后打开 app。

协议同意门禁

LEGAL_VERSION 定义在 lib/legal.ts

export const LEGAL_VERSION = "2026-04-30";

ConsentProvider 把已接受版本存在:

legal.consent.v1

版本变化后,老用户会再次看到提示。Legal 文档在 app/legal/ 下;外部法律链接来自 EXPO_PUBLIC_TERMS_URLEXPO_PUBLIC_PRIVACY_URLEXPO_PUBLIC_EULA_URL

这是 legal consent gate,不是 analytics consent gate。当前 provider 顺序中, AnalyticsProviderConsentProvider 之前挂载,所以只要配置了 PostHog key, PostHog 就可以初始化并开始 screen tracking。

如果你的政策要求用户同意后才启动 analytics,请修改实现:在挂载 PostHog 前读取 consent,或让 isAnalyticsEnabled() 依赖一个已持久化的 analytics-consent 值。

生物识别锁

lib/biometric.tsx 使用 expo-local-authentication。它会检查硬件、是否已录入生物识别、支持类型,并把用户 opt-in 状态保存到:

cache.biometric.enabled.v1

已登录用户启用后,app 会立即锁定;后台超过 30 秒再回到前台时也会重新锁定。BiometricGate 渲染在 <Stack /> 外,因此能覆盖所有当前页面。

这是 Native-only 功能,需要真机硬件或已录入的设备认证方式。

评分提示

评分不是 gate。lib/rating.ts 会在 onboarding 完成或分享邀请链接时累加 action counter。只有满足以下条件才会请求系统评分:

actionCount >= 3
当前 app version 没有提示过
距离上次提示至少 90 天
expo-store-review 当前有可用 action

lib/store-review.web.ts 永远返回 false,所以 web 不会弹出评分提示。

自定义

  • 删除某个 gate 时,从 app/_layout.tsx 移除对应 provider state 和组件。
  • 调整顺序要谨慎:redirect gate 适合放在 <Stack /> 前;必须覆盖当前路由的 overlay 适合放在 <Stack /> 后。
  • QA 时可以清空 app 本地 storage/cache,或临时做一个 debug screen 调 provider 的 reset helper。
  • App Review 说明要和代码一致:账号删除在 Account & Security;legal consent 有版本;ATT 和这个 consent gate 是两回事。

相关页面

On this page