Quick answer: export your game for the web (Phaser: the
dist/build; Construct 3: Export → Web (HTML5); GDevelop: Export → Web), make sureindex.htmlis at the root of the folder and that scripts are classic rather than modules, zip the folder's contents, and upload the ZIP to the ZIP to APK builder with the orientation set to match the game. Handle touch, resize and the audio-unlock gesture in the game itself.
Exporting from each engine
| Engine | Export | Watch for |
|---|---|---|
| Phaser 3 (Vite/webpack template) | npm run build → dist/ | Relative base path; classic script output (see the framework guide) |
| Construct 3 | Export → Web (HTML5), uncheck "Minify" only if debugging | Untick the offline/service-worker option; it is unnecessary in an app and its registration fails on file:// |
| GDevelop | Export → Web (browser game) → local folder | Already relative and classic; zip the folder contents |
| PixiJS / Three.js / plain canvas | Whatever your bundler outputs | Same as Phaser: relative paths, no type="module" |
| Godot 4 (web export) | Export → Web | Requires SharedArrayBuffer and cross-origin isolation, which a file:// page cannot provide — Godot web exports do not run in a bundled APK. Use Godot's own Android export instead. |
| Unity WebGL | — | Same problem as Godot; use Unity's Android build. |
Zip the exported folder's contents so index.html is at the root, and run it through the checker:
Orientation and full screen
The builder locks the orientation for you — choose landscape for most games, portrait for puzzle and endless-runner formats. The app is already full screen with no address bar. Inside the game, listen for resize and scale the canvas to window.innerWidth × innerHeight; phones have every aspect ratio from 16:9 to 21:9 and a fixed 1280 × 720 canvas will be letter-boxed or cropped. Phaser's Scale.FIT with autoCenter, Construct's "Letterbox scale" and GDevelop's "Adapt game resolution" all do this.
Touch input
Pointer events work as in Chrome. Two things bite: the 300 ms tap delay is gone on modern WebViews but only if the viewport meta tag is present (<meta name="viewport" content="width=device-width, initial-scale=1">), and the browser's own gestures — pull-to-refresh, pinch-zoom, long-press context menu — can interfere. Add touch-action: none to the canvas and user-select: none to the body, and call preventDefault() on touchstart if your engine does not already.
Audio
Chrome — and therefore the WebView — refuses to play sound until the user has interacted with the page. Every engine handles this by resuming the audio context on the first tap; make sure your game has a "Tap to start" screen or a first-tap handler that calls AudioContext.resume(). Background music that starts on load will be silent until then. Audio files bundle fine: prefer OGG or M4A; MP3 works but is larger.
Saving progress
localStorage is the simplest and works offline; it persists across updates as long as the package name and signing key stay the same. Construct's and GDevelop's built-in storage actions use it. For big saves (level editors, replays), IndexedDB. Do not rely on cookies — they do not work on bundled pages.
Keeping under the size limit
Games are asset-heavy and the limits are 5 MB free, 18 MB Pro. In order of payoff: convert sprite sheets and backgrounds to WebP; use OGG at 96 kbps for music; strip unused frames and languages; and if the total is still too high, load large optional packs from a URL when online. The size estimator shows the breakdown per type from your ZIP.
Performance notes
- Canvas 2D and WebGL are hardware-accelerated in the WebView; expect the same frame rate as Chrome on the same phone.
- Use
requestAnimationFrame, notsetInterval, for the loop. - Avoid layout thrash: keep the game in a single canvas, not hundreds of DOM elements.
- Test on a mid-range phone, not only a flagship.
Checklist
- Web export, index.html at the root, classic scripts
- Orientation set in the builder; canvas scales on resize
- Viewport meta;
touch-action: noneon the canvas - Tap-to-start screen unlocks audio
- Progress in localStorage/IndexedDB
- Assets as WebP/OGG; under the size limit