Cross-Platform Parity (Android ↔ iOS)
Generated 2026-05-07 · Costco Android
Executive summary
Both apps share the same backend, brand, and feature surface — and largely the same patterns of risk. Where Android and iOS converge, fixing once unlocks both platforms. Where they diverge, ask whether the divergence is intentional.
Shared risk patterns
The same anti-patterns surface on both platforms. Each row below is a single architectural decision that can be made jointly.
| Pattern | Android | iOS | Joint recommendation |
|---|---|---|---|
| Force-unwrap of optionals | !! force-unwraps pervasive · 39 critical sites | ! / try! / as! pervasive · 16 critical (incl. 13 try! regex) | Lint-rule both repos: ban force operators in non-test code; sweep over 1 quarter. |
| Memory leaks via lifecycle | 14 Handler.postDelayed without cleanup; 21 NotificationCenter-equivalent observers | 6 Timer.scheduledTimer not invalidated; 21 NotificationCenter observers without removal | Adopt the same teardown checklist; pair test that runs leak detection per release. |
| Hardcoded design literals | Color(0xFF…) + inline .dp across feature modules |
Color(hex:) + inline UIFont.systemFont sizes |
Custom lint rule per platform banning literals outside design system; sweep tokens. |
| WCAG 2.2 conformance | Near-zero contentDescription / Compose semantics |
Hardcoded UIFont sizes (no Dynamic Type); missing accessibility traits | Cross-platform a11y audit; shared 'a11y baseline' definition; UI tests that assert. |
| Heavy startup | 20+ deps eagerly in CostcoApplication | Heavy work in viewDidLoad across 5+ controllers | Defer non-critical init to async; baseline profile (Android) + signposts (iOS). |
| print/Log in production | 231+ Log.d/e/i calls; should use Timber | 30+ print() calls; should use os.Logger | One PR per platform; lint rule blocking new occurrences. |
| Test coverage threshold | JaCoCo at 40.81% | Coverage gate not surfaced | Stair-step both to 60-70% over two quarters; PR-diff blocking on changed files. |
| Ignored / commented-out tests | 12 @Ignore'd tests; commented test methods | Same pattern; @Ignore'd / @Skip / commented blocks | Treat @Ignore without reason+expiry as a build break. |
| Documentation / onboarding | Stale README; no per-module README; no ADRs | Stale README; no per-package README; no ADRs | Adopt MADR; quarterly doc audit; require module README on creation. |
| Background-location justification | ACCESS_BACKGROUND_LOCATION for warehouses | NSLocationAlwaysAndWhenInUseUsageDescription | Single user-facing justification per Play Store + App Store; same flow. |
Convergence opportunities
Same SDKs across platforms — keep versions synchronized; renew contracts together.
Adobe Marketing Cloud
Android: 11 modules from BOM 3.17.0. iOS: Adobe Target + Optimize via CostcoContentstack.
Action: Audit which modules each platform uses; remove unused.
Contentstack CMS
Android: Java/Kotlin SDK in shared/contentstack. iOS: contentstack-swift 1.5+ in CostcoContentstack.
Action: Same content schema + analytics events.
NokNok / Passkey
Android: NokNok FIDO2. iOS: PasskeyManagerKit (NokNok wrapper).
Action: Share the OIDC nonce strategy; keep contract in sync.
ThreatMetrix
Both platforms ship ThreatMetrix.
Action: Unified profiling rules and risk thresholds.
Firebase Crashlytics
Android: integrated. iOS: presence to verify.
Action: Shared dashboard; same Slack/email rules; closed-loop with issue tracker.
OneTrust consent
Both reference cookielaw.org.
Action: Same consent state must gate the same SDKs across platforms.
Notable divergences
| Area | Android | iOS | Worth aligning? |
|---|---|---|---|
| Architecture | Hilt DI; MVVM; Compose + Views | Init-based DI; MVVM; SwiftUI + UIKit | No — platform-idiomatic |
| Image loading | Coil + Glide (both!) | SDWebImage (custom fork) | Internal: each platform should pick one |
| Networking | Retrofit + OkHttp + Volley (legacy) | URLSession + RZVinyl (legacy) | Internal: retire legacy on each platform |
| Persistence | Room + DBFlow + DataStore | Storage SPM (Keychain + UserDefaults + CoreData) | No — platform-idiomatic |
| Test infrastructure | JUnit + MockK + Karumi Shot | XCTest + Mockey + iOSSnapshotTestCase | Yes — share test data fixtures + scenario coverage |
| Locale coverage | en, en-rCA, fr, fr-rCA | en, en-CA, fr-CA, fr | Yes — strict parity, same string keys |
| Deep-link surface | 11+ intent filters incl. costco:// + 11+ http/https | Custom URL schemes + Universal Links | Yes — every link should resolve identically per OS |
Recommended joint actions
Cross-platform stability strike-team (now)
4 weeks. 1 lead per platform + 1 platform engineer each. Target: top-20 crashes on each side, fix the shared patterns once.
Shared a11y baseline (next)
1 cross-functional engineer + design system DRI. Define WCAG 2.2 baseline; apply to design tokens; fix top traffic screens.
Joint privacy & SDK audit (later)
1 mobile + 1 legal. Generate iOS Privacy Manifest; align Android/iOS App Store privacy labels; vendor renewal calendar.
Quarterly cross-platform sync
30-minute review of shared findings; track convergence over time; protect what's working (Hilt, SPM modularization, snapshot tests).