Skip to main content

Indie game storeFree gamesFun gamesHorror games
Game developmentAssetsComics
SalesBundles
Jobs
TagsGame Engines

Overcoming the Limitations of winit on Mobile Platforms

A topic by Eren created 70 days ago Views: 94
Viewing posts 1 to 1
(1 edit)

Rust’s window management library, winit, is advertised as cross-platform — but when it comes to mobile, the experience reveals some serious limitations and pitfalls.

(I had my fair share of issues with WASM too, but let's focus on mobile for this post.)


In this write-up, I’d like to share some of the challenges I faced while building a Rust-based mobile app and how I overcame them, step by step.

Rust on Mobile Isn’t Plug-and-Play

Unlike Unity or Unreal Engine, where you can just export your game and you're good to go, Rust apps on mobile must be built as native libraries (.a, .so files) and manually linked to the app’s entry point (e.g., MainActivity on Android).

This by itself is already a major hurdle if you're not familiar with mobile development.

Android – Dealing with GameActivity and More

Android provides a special GameActivity designed specifically for game engines:
📎 GameActivity official docs

To use Rust libraries with this, you either need to hook into GameActivity or fall back to NativeActivity. This changes how winit behaves compared to other platforms.

For example, when initializing the event loop, you need to explicitly pass an AndroidApp instance via with_android_app().

On top of that, you need extra setup to forward logs into Logcat, and other platform-specific adjustments.

WGPU + Android Emulator = Not Great

If you use WGPU as your rendering backend, you might be surprised to find that your app crashes only on the Android Emulator.

The reason? WGPU tries to initialize a Vulkan surface, which ends up blocking EGL surface creation, causing a panic at runtime.

Interestingly, this issue doesn't occur on real devices.

🔗 Related GitHub Issue:
https://github.com/gfx-rs/wgpu/issues/2384

Vulkan Isn't a Silver Bullet

Even if you try to force Vulkan as a backend to avoid EGL issues, you’ll run into different problems.

One major pain point is inconsistent Vulkan support across Android devices:

  • Many devices still use outdated Vulkan drivers, even on recent Android versions.

  • Vulkan 1.3+ support is rare; some don’t even fully support 1.1.

  • Indirect drawing and key extensions may be missing or buggy on lower-end hardware.

And since mobile screens rotate, you need to manually apply transform logic when using Vulkan. This is rarely a problem on desktop, but becomes a unique challenge on phones and tablets.

iOS – Simulator vs. Real Device, Plus One Nasty Bug

On iOS, you have to build separate libraries for the simulator (-sim.a) and for real devices, switching them out depending on your testing or release target. Otherwise, you’ll run into linker or compatibility errors.

Even worse, there's a long-standing bug in winit on iOS:

After the initial redraw event, no subsequent redraws are triggered, even if requested.

This essentially breaks the main rendering loop — quite a dealbreaker for anything real-time like a game or animation.

Fortunately, a developer has shared a workaround in the issue tracker:

🔗 Temporary fix on GitHub

It works for now, but it's clearly a patch and not a proper solution.

Sample Project / Demo

All this trial-and-error eventually resulted in a working setup, which I've published as an open-source reference:

📎 GitHub Repository:
https://github.com/erenengine/eren_mobile_test

Final Thoughts

After going through all of this, I can see why the Bevy team still recommends using engines like Godot for production mobile games.

Rust is powerful and flexible, and its ecosystem is improving fast — but mobile support still has a long way to go before it becomes truly seamless and "cross-platform."

Thanks for reading! I hope this post helps others navigate these same issues more smoothly. 😊