perf: fix Android WebView jank (confetti, instrumentation, wrapper) - #2588
perf: fix Android WebView jank (confetti, instrumentation, wrapper)#2588innolope-dev wants to merge 4 commits into
Conversation
…View - PostHog: disable rrweb session recording and autocapture on all native builds — recording serializes the DOM on every mutation and autocapture walks the ancestor chain on every tap; explicit capture events keep working. The old capability gate enabled recording on exactly the devices reporting jank (Pixel 8 Pro passes deviceMemory>=4 && cores>=6). - Sentry native: drop BrowserTracing (it wraps fetch/XHR, patches history and runs PerformanceObservers in 100% of sessions — tracesSampleRate only gates sending) and stop capturing console.warn as events. Error capture unchanged. - Sentry web: delete replaysSessionSampleRate/replaysOnErrorSampleRate — dead config, replayIntegration() was never registered. - reactComponentAnnotation off: stamps data-sentry-* on every DOM node for a replay product that isn't running. - gtag.js no longer ships into the Capacitor WebView. - NEXT_PUBLIC_PERF_BARE=true builds strip all instrumentation, for A/B-testing jank against a control build.
- canvas-confetti now fires through a persistent worker-backed OffscreenCanvas (falls back to main thread where unsupported) instead of a fresh main-thread canvas per burst - native builds get one half-sized burst instead of two full ones (400->100 particles worst case on qr-pay, where payment-success and perk-claim bursts can stack) - 1.5s module-level throttle collapses duplicate celebrations racing on the same screen - respects prefers-reduced-motion; library is now lazy-imported off the startup chunk; celebration preset's particleCount is honored instead of silently overridden; rAF cancelled on unmount
- MainActivity extends BridgeWebViewClient instead of replacing it with a bare WebViewClient that forwarded only 2 of 8 callbacks: onRenderProcessGone is back (a renderer OOM/crash recovered instead of killing the app — reads as 'random freeze' on low-RAM devices), as are plugin page-load listeners. findPageHtml now honors an active Capgo OTA bundle via getServerBasePath, so post-OTA navigation can't serve stale APK HTML. - noCompress for js/css/html/json/svg/woff2/map assets: the WebView mmaps them instead of inflating ~23MB of chunks per read on every full-document load. Play recompresses for transfer, so download size is unaffected. - native-release.sh exports NODE_ENV=production so release builds stop shipping with webContentsDebuggingEnabled=true; WEBVIEW_DEBUG=true re-enables it for on-device profiling. - backgroundColor kills the white flash between splash teardown and first paint. - native-build.js prunes /dev test pages and iOS-PWA install videos (~8MB) from the bundled export; KEEP_DEV_PAGES=true retains /dev for test builds.
…work - pull-to-refresh rewritten without pulltorefreshjs: the library registered non-passive touch listeners on body, forcing every touch in the app through the main thread before the compositor could scroll — the classic WebView scroll-jank pattern. The replacement uses passive listeners and a compositor-only transform indicator; same hook API. - QR scanner: decoder lazy-imported off the app-shell critical path, scan rate 8->4Hz (halves per-second canvas draws + worker decodes), per-frame code outline overlay off, camera released 300ms after close instead of 1.5s (it used to keep streaming through the qr-pay success confetti). - Crisp native SDK configured on first support open instead of every app launch; logout reset tolerates never-configured. - Capgo update check deferred 5s past first paint (notifyAppReady stays immediate — it must land within appReadyTimeout).
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Comment |
Code-analysis diffPainscore total: 6800.43 → 6798.12 (-2.31) 🆕 New findings (53)
…and 33 more. ✅ Resolved (52)
…and 32 more. 📈 Painscore deltas (top movers)
|
🧪 UI test report — ✅ all greenSuites
📊 Coverage (unit)
⏱ 10 slowest test cases
|
Why
The Android (Capacitor) build feels jittery vs the same app as a PWA — confetti on reward claim stutters on a Pixel 8 Pro, and low-end devices (Realme Narzo 50) see random slowness on navigation and camera open. Investigation found multiple independent causes rather than one:
replayIntegration()was never registered).onRenderProcessGone(renderer OOM = app death, reads as 'random freeze'), pulltorefreshjs put non-passive touch listeners onbody(every touch blocked compositor scrolling on the main thread), release APKs shipped ~23MB of per-read-inflated JS with remote debugging left on, and the QR scanner decoded 8×/sec on the app-shell critical path.What
posthog.captureevents unchanged — heads-up to analytics owners). Sentry native: BrowserTracing dropped, console.warn capture dropped; error capture untouched. Sentry web: dead replay config deleted. GA no longer ships into the WebView.BridgeWebViewClient(all 8 callbacks restored, incl. renderer-crash recovery; also picks up the OTA-awarefindPageHtmlfrom mobile-release so post-OTA navigation can't serve stale APK HTML),noCompressfor web assets,NODE_ENV=productionin the release script (killswebContentsDebuggingEnabledin release;WEBVIEW_DEBUG=trueoverrides for profiling), splashbackgroundColor, ~8MB of web-only assets pruned from the bundle.NEXT_PUBLIC_PERF_BARE=truebuilds strip all instrumentation, for A/B-ing a bare APK against a control on the affected devices.Verification
pnpm typecheck✅, full jest suite 182/182 suites ✅,:app:compileDebugJavaWithJavac✅_fallbacks, offline nav, pull-to-refresh feel, QR scan, support chat open) — profiling protocol and before/after metrics tracked internally.Notes
minifyEnabled(R8 shrinks Java only, plugin-reflection risk), flag sprites (runtime-resolved by country code).