Unity is the most widely used game engine for cross-platform development, but cross-platform does not mean build once, ship everywhere without work. A game running at 60fps on PC will crawl on an older Android device. A UI perfect on a 16:9 monitor will overflow on an iPhone SE. Building for multiple platforms means understanding each platform's constraints and designing systems that adapt to them.
This article covers the practical architecture, workflow, and platform-specific considerations for shipping Unity games on mobile (Android and iOS), web (WebGL), PC (Windows/Mac), and XR (Meta Quest), based on our experience developing and shipping over 50 commercial games and interactive experiences.
Project Architecture: Scriptable Object Profiles
The most impactful architectural decision for cross-platform Unity development is using Scriptable Objects for all platform-specific configuration. Platform behaviour — render quality, physics simulation rate, audio compression, UI scale — should be driven by Scriptable Object profiles swapped at runtime based on platform detection, not hardcoded in scripts.
We create a PlatformProfile ScriptableObject with fields for target framerate, physics timestep, shadow quality, draw distance, texture quality, and audio settings. Separate profiles exist for Mobile Low, Mobile High, WebGL, Standalone, and XR. At startup, the GameManager detects the platform and applies the appropriate profile, making it trivial to tune each platform independently without touching gameplay code.
Addressables for Asset Management
Unity Addressables is essential for any serious cross-platform project. It decouples asset loading from prefab references, enables asynchronous on-demand loading, and supports remote content delivery for post-launch updates. On mobile, Addressables allow shipping a small core APK and downloading additional content post-install. For WebGL, we structure projects with a core bundle under 20MB and Addressable bundles for each content section loaded on demand.
Mobile: Android and iOS
Performance and Thermal Management
Target 30fps on mobile, not 60fps. Targeting 60fps either requires cutting visual quality dramatically or causes thermal throttling within 5-10 minutes on mid-range devices, which drops the frame rate dynamically anyway. Use URP with mobile-optimised settings: single shadow cascade, disabled SSAO, disabled HDR on low-end devices. Profile with Xcode Instruments on iOS and Android GPU Inspector on Android.
Android Device Tier System
Android fragmentation means thousands of distinct devices with different GPU vendors, Android versions and performance characteristics. Our approach: define three device tiers (Low, Mid, High) based on a benchmark scene run at startup that renders a fixed scene for 30 frames and measures average frame time. Based on the result, the game applies the corresponding PlatformProfile, supplemented by a remote device-specific override config for known devices with unusual characteristics.
WebGL Specifics
WebGL has no direct filesystem access, no native threads, strict memory limits, and poor mobile browser support. Use the IL2CPP scripting backend and enable Brotli compression. Disable unused Unity features — the WebGL build includes everything enabled in the project, so unused physics engines and audio decoders add build size unnecessarily. WebGL Unity builds allocate a fixed memory heap at startup — if it overflows, the game crashes with an out-of-memory error. Set the heap conservatively (512MB) and use Addressables to load and unload assets as the player progresses.
XR: Meta Quest
Enable Fixed Foveated Rendering (FFR) level 2 for most Quest games — it renders the periphery at lower resolution and significantly reduces GPU load. Enable Application SpaceWarp on Quest Pro and Quest 3 — it synthetically generates in-between frames, allowing the engine to render at 36fps while achieving 72fps perceived frame rate. Target 72fps, not 90fps, for most experience applications where action is relatively slow-paced.
Input and UI Systems
Use Unity's new Input System, not the legacy Input.GetKey API. The new system abstracts input bindings from game code — the same Jump action binds to Spacebar on PC, A button on controller, a Quest trigger, or a mobile touch gesture. Use Canvas Scaler with Scale with Screen Size at 1920x1080 reference resolution and test UI on at least: 16:9 landscape, 9:16 portrait, 21:9 ultrawide, and the Meta Quest aspect ratio.
Automated Build Pipeline
A cross-platform project with 5 target platforms benefits enormously from an automated build pipeline. We use GitHub Actions with GameCI Docker containers to build all platforms on push to the main branch. Automated builds catch platform-specific compilation errors early — a script compiling fine on PC may fail on WebGL due to unsupported .NET APIs, or an iOS build may fail due to a missing native plugin.
Key Takeaways
- Use Scriptable Object profiles for platform configuration — never hardcode platform-specific values in scripts.
- Target 30fps on mobile — thermal management is more important than frame rate on mid-range Android devices.
- Implement a runtime device tier benchmark on Android for more reliable device classification than static databases.
- WebGL memory is a fixed heap — use Addressables to avoid loading everything at once.
- Use the new Input System — decoupling input bindings from game logic makes cross-platform input trivial.
- Automate builds for all platforms in CI — platform-specific compilation failures are much cheaper to catch early.


