← Volver al blog

April 4, 2026·10 min read

AppState and background: what actually keeps running

Mobile OSes suspend apps aggressively. Timers pause, network may stop, and your “it worked in the simulator overnight” test lies. Design flows that tolerate resume, not perfect continuity. Users expect apps to recover gracefully when they return—not to finish fragile background work silently.

Listen to AppState

Refresh data on `active` if it’s stale. Pause expensive work on `background`.

Don’t assume `inactive` means the same thing on iOS and Android.

Background modes

Audio, location, VoIP—each needs entitlement justification Apple will review. Fake background modes get rejected.

Use platform APIs for tasks that truly must finish.

User trust

Background location drains battery; explain ongoing notifications when required.

Test low power mode behaviors.

Patterns that survive real life

Persist in-flight form data to disk on blur, refresh auth tokens on `active` if your session is short, and show a “reconnecting” state instead of silent failure when the network was suspended.

For uploads, use resumable APIs or background URL sessions where appropriate—`setInterval` in JS is not a delivery guarantee.

Modeling user expectations when the OS pauses you

Users do not think in AppState transitions—they think in tasks: sending a message, uploading a photo, finishing checkout. When iOS suspends your app or Android throttles background work, those tasks stall. Your job is to make pause and resume feel intentional. Persist partial progress frequently, show status when the user returns, and avoid silent failure. For uploads, use resumable protocols or background-capable APIs where platform policy allows. For payments, never leave ambiguous states—either show pending with polling or a clear ‘try again’ path. Music and navigation apps get more leeway on background time; a shopping cart app does not—design accordingly. Document platform differences in your internal wiki so PMs do not assume Android behaves like iOS. Test with Low Power Mode and Battery Saver enabled—users enable them more than engineers expect.

Timers, intervals, and replacing assumptions with scheduling

JavaScript timers are not reliable across backgrounding. Move time-sensitive logic to server clocks or push notifications for deadlines. If you poll, backoff exponentially and stop when backgrounded unless you have justified background modes. For session expiry, reconcile client timers with server responses—401s should trigger refresh flows, not just local logouts. Websockets need heartbeat strategies that tolerate cellular drops; reconnect with jitter to avoid thundering herds. Consider WorkManager on Android and BGTaskScheduler on iOS for deferrable maintenance—encrypt local caches, compact databases, prune logs. Always log scheduling failures in aggregate; users rarely report them, but metrics will spike if OS policies change in an upgrade.

Background modes and the politics of entitlement

Each background mode—audio, VoIP, location, fetch—comes with review scrutiny. Use only what you need, explain clearly in App Review notes, and ensure user-visible value matches entitlement. Fake modes are a fast path to rejection or removal. Location is especially sensitive: foreground-only versus always-on requires different UX and disclosures. If marketing wants persistent tracking, translate that into engineering costs and legal review—often the answer is geofencing with minimal persistence or server-side inference with consent. Background fetch intervals are hints, not guarantees—design for unknown timing. Test on devices with aggressive OEM battery savers; Xiaomi and Samsung historically killed background work more eagerly than Pixel.

Data integrity across suspend and kill

Assume the OS can kill your process at any time after backgrounding. Transactions should be idempotent; local caches should tolerate partial writes. Use atomic file operations or databases with ACID guarantees for critical state. If you cache API responses, version them and invalidate on auth changes. Encrypt sensitive caches if policy requires, and exclude them from backups when appropriate. On resume, validate assumptions: user may have changed system time, locale, or network type. Provide a lightweight health check that refreshes feature flags and session validity before rendering sensitive UI.

Observability and field debugging

Instrument state transitions in internal builds with breadcrumbs—active to background timestamps help correlate user reports. Capture whether uploads were in-flight at suspension. For crashes on resume, symbolicate stacks promptly and tag OS versions—resume paths often break on new iOS releases first. Train support to ask about battery saver and VPNs; both alter networking and timers. Maintain a small suite of devices on older OS versions; background policy backports sometimes change behavior in point releases.

Shipping and reliability habits (1)

FlatList performance is configuration as much as code. Stable keys, reasonable `windowSize`, and memoized rows beat switching to a different list primitive blindly. Nested virtualized lists are a last resort—redesign first. Profile with production-like data volumes; dev placeholders lie.

Splash screens and launch gates should reflect honest readiness: fonts, theme, session, critical remote config—not every SDK under the sun. Infinite splash is worse than a slightly longer branded hold. Match native and JS background colors to avoid flashes; respect reduced motion for animations.

Platform differences worth rehearsing (2)

Hermes versus JSC is not a lifestyle choice—profile your app. Hermes usually wins on startup; some libraries still assume JSC quirks. Engine toggles are not substitutes for fixing quadratic renders in your own code. Upgrade notes matter: Intl support and debugging tooling evolve.

Reanimated and gesture libraries earn their place when profiling proves UI-thread work and your team can maintain native upgrades. Worklets have constraints—read errors carefully. Respect reduced motion and test Android timing differences—identical JS does not guarantee identical feel.

Security, privacy, and data handling (3)

ScrollView versus FlatList is a data-volume question. Small static content belongs in ScrollView; long feeds belong in virtualized lists. Nested scrollables need explicit height contracts—redesign beats fighting physics. Document intentional choices so future refactors do not ‘optimize’ blindly.

Metro cache issues masquerade as logic bugs. Establish a documented reset ladder: dev server restart, cache flags, Watchman, derived data, then dependency reinstalls. Compare platforms when only one breaks—native steps diverge. Keep CI caches deterministic with lockfiles and pinned toolchains.

Performance and measurement discipline (4)

Performance work should start with measurement, not instinct. Watch JS thread versus UI thread separately; they bottleneck differently. Lists, images, and animations dominate most regressions—optimize those before micro-optimizing pure functions. Hermes, JSC, and bridge internals evolve; re-profile after every major upgrade instead of trusting last year’s numbers. Battery and thermal throttling on mid devices reveal issues flagship phones hide.

Security and privacy expectations move faster than roadmaps. Treat analytics, crash, and attribution SDKs as part of your threat model: initialize them deliberately, document data flows, and verify ‘off’ truly stops network calls. Client-side secrets are public secrets—anything shipped in an APK or IPA should be assumed extractable. Pair mobile changes with backend policies so authorization remains consistent across platforms.

Team process and long-term maintenance (5)

Deep links are a cross-team system: marketing URLs, hosted association files, entitlements, router params, and analytics query preservation. Debug with structured logging of raw URLs (scrub secrets) and reproduce cold-start races with auth hydration. Staging and production should be obviously separated—accidentally opening prod from a QA link erodes trust and pollutes data.

Push notifications walk a line between helpful and intrusive. Prime users with context, respect notification channels on Android, and measure opt-outs after campaigns—spikes mean copy or frequency problems. Payload design affects background behavior; test killed and locked-device states. Tokens belong server-side with rotation strategies; never treat the client as authoritative for subscription state.

Shipping and reliability habits (6)

E2E tests should protect revenue paths, not every permutation. Stable selectors (`testID`) beat text that marketing rewrites weekly. Flake management is a feature: quarantine, fix root causes, and keep smoke suites green on CI devices. Five reliable tests beat fifty flaky ones that everyone ignores.

OTA updates are powerful and risky: runtime compatibility, rollback plans, and user-visible behavior changes need governance. Channels should map to release maturity—staging versus production—with access controls on publish credentials. Large assets over cellular need care; silent failures erode trust more than a frank ‘update failed, retry’ message.

Platform differences worth rehearsing (7)

JWT and session refresh flows need single-flight refresh, clear logout semantics, and secure storage for refresh tokens when appropriate. Parallel 401s should not stampede refresh endpoints. Clock skew and biometrics policies belong in explicit product decisions, not accidental implementation details.

In-app purchases require server validation, restore flows, and support tooling that respects privacy. Sandbox quirks are normal—budget QA time. Subscriptions interact with family sharing, regional pricing, and refunds; engineering must stay aligned with finance and legal narratives users see in receipts.

Security, privacy, and data handling (8)

Analytics schema governance prevents warehouse disasters: version events, avoid high-cardinality strings, and align names across iOS, Android, and web. Consent gating must stop network calls, not just UI. Separate dev and prod projects to avoid polluting dashboards.

Testing onboarding changes with funnel metrics beats debating opinions. Segment by acquisition channel and platform; back behavior differs. Skip paths must be genuine—dark patterns may win short metrics and destroy brand trust. Localization length tests prevent clipped CTAs in verbose languages.

Performance and measurement discipline (9)

Environment variables should be classified: public-by-design, sensitive-with-mitigations, or never-on-device. `EXPO_PUBLIC_` values are extractable—treat them that way. Align env handling across EAS profiles and local dev; fail fast when keys are missing instead of shipping undefined behavior.

Project structure should make ownership obvious: routes as backbone, feature folders for product areas, thin screens, and shared infrastructure that is deliberately named. Refactor in vertical slices with device-tested releases—big-bang rewrites without tests are how teams lose weeks.

Team process and long-term maintenance (10)

Accessibility is compatibility. Labels, focus order, and dynamic type are not polish—they determine whether users can complete tasks at all. Test with VoiceOver and TalkBack on hardware; simulators miss focus bugs. When designs prioritize minimalism, negotiate text alternatives for icon-only controls. Accessibility regressions often follow navigation redesigns—add checklist items to those PRs specifically.

Internationalization is a product feature, not a string swap. Plural rules, RTL layout, and locale-aware formatting change behavior—not just copy length. Pseudolocale helps find clipping early, but real Arabic and German QA catches nuance. Avoid concatenating translated fragments; context matters. Document glossary terms so translators do not invent inconsistent product names.

Shipping and reliability habits (11)

Splash screens and launch gates should reflect honest readiness: fonts, theme, session, critical remote config—not every SDK under the sun. Infinite splash is worse than a slightly longer branded hold. Match native and JS background colors to avoid flashes; respect reduced motion for animations.

JWT and session refresh flows need single-flight refresh, clear logout semantics, and secure storage for refresh tokens when appropriate. Parallel 401s should not stampede refresh endpoints. Clock skew and biometrics policies belong in explicit product decisions, not accidental implementation details.

Platform differences worth rehearsing (12)

Testing onboarding changes with funnel metrics beats debating opinions. Segment by acquisition channel and platform; back behavior differs. Skip paths must be genuine—dark patterns may win short metrics and destroy brand trust. Localization length tests prevent clipped CTAs in verbose languages.

Background execution policies change with OS updates—revalidate after major iOS and Android releases. Misused background modes invite rejection. Persist user work frequently; the OS can kill you anytime after backgrounding. Uploads and timers should tolerate pause and resume without corrupting state.

Security, privacy, and data handling (13)

Shipping React Native features is less about any single API and more about the system around it: typed boundaries, predictable navigation, and telemetry that tells you what broke in production. Prefer boring, explicit modules over clever metaprogramming that the next hire cannot grep. When platform vendors change behavior in point releases, your defense is automated smoke tests on real devices and a short internal changelog of native assumptions you rely on.

Performance work should start with measurement, not instinct. Watch JS thread versus UI thread separately; they bottleneck differently. Lists, images, and animations dominate most regressions—optimize those before micro-optimizing pure functions. Hermes, JSC, and bridge internals evolve; re-profile after every major upgrade instead of trusting last year’s numbers. Battery and thermal throttling on mid devices reveal issues flagship phones hide.

Performance and measurement discipline (14)

Push notifications walk a line between helpful and intrusive. Prime users with context, respect notification channels on Android, and measure opt-outs after campaigns—spikes mean copy or frequency problems. Payload design affects background behavior; test killed and locked-device states. Tokens belong server-side with rotation strategies; never treat the client as authoritative for subscription state.

Images and maps look simple in mocks and expensive in production. Decode sizes should match display sizes; static map thumbnails are not interchangeable with interactive MapView gestures. Quotas, API keys, and offline behavior need explicit fallbacks—addresses as text, retry buttons, and calm error copy. Monitor vendor dashboards for spikes that indicate bugs or abuse.

Patrocinado

Promoción breve