perf: fix Android WebView jank (confetti, instrumentation, wrapper) - #2588
Draft
innolope-dev wants to merge 5 commits into
Draft
perf: fix Android WebView jank (confetti, instrumentation, wrapper)#2588innolope-dev wants to merge 5 commits into
innolope-dev wants to merge 5 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.
|
Contributor
|
Important Review skippedDraft detected. 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 |
Contributor
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)
|
Contributor
🧪 UI test report — ✅ all greenSuites
📊 Coverage (unit)
⏱ 10 slowest test cases
|
The updater runs on every launch and captureConsoleIntegration turns each console.error into a Sentry event — ~95/day for CDN and network failures the user never sees and that retry on the next launch anyway. Split by whether the failure can retry its way out. disable_auto_update_under_native (the served bundle sorts below the installed binary) and a checksum mismatch mean OTA is dead for this build, so those keep error level. Everything else drops to console.info.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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).