Tech Report
PWA Support in 2025
TL;DR
PWA support is good enough to ship on Android and usable but limited on iOS. The biggest practical gap is iOS install UX: there is no automatic install prompt — users must navigate a 4+ step Share menu flow. For a canvas game with WebSockets, both platforms work; fullscreen is the main iOS gap on iPhone.
Android (Chrome)
What Works Well
- Auto install prompt — Chrome shows a "mini infobar" on first visit when installability criteria are met. If the user dismisses it, it reappears after ~90 days. You can intercept the
beforeinstallpromptevent to suppress the infobar and show your own in-game "Install app" button at a better moment. - Fullscreen —
element.requestFullscreen()works correctly. - WebSockets — full support, no known issues.
- Icons — maskable icons (for adaptive icon shapes) are supported. Use
purpose: "maskable"for Android icons andpurpose: "any"for others; do not combine them as"any maskable"— Chrome warns that the result will look wrong on some platforms. - Manifest —
display: "standalone"hides browser chrome.orientationlocking via the manifest is respected.
Install Criteria Checklist
- HTTPS
- Web App Manifest with
name,short_name,start_url,display, at least one 192×192 icon and one 512×512 icon - A registered Service Worker (even a minimal one with no offline behaviour)
iOS (Safari)
What Works Well
- WebSockets — supported. A bug in Safari 15.6.1–16.6 caused
oncloseto not fire when connectivity dropped (connection appeared OPEN but was dead). This is fixed in current Safari. Still worth implementing a heartbeat/ping-pong to detect dead connections independently. - Standalone mode —
display: "standalone"in the manifest is respected. The browser chrome disappears after adding to Home Screen. - Safari 26 (shipping fall 2025) — every website added to the Home Screen will open as a web app by default, even without a manifest. This is a significant improvement.
- Fullscreen on iPad —
element.requestFullscreen()works on iPad. - Background execution — claims that iOS PWAs freeze when backgrounded have been tested and refuted as of current iOS versions.
Limitations
- No install prompt on iPhone — iOS Safari does not fire
beforeinstallpromptand shows no automatic install banner. Installation requires the user to tap Share → scroll to "Add to Home Screen" → tap Add. That's 4+ steps with no way for your app to trigger it. All iOS browsers are WebKit-based, so this affects Chrome/Firefox/Edge on iOS too. - No fullscreen on iPhone —
element.requestFullscreen()is completely unsupported on iPhone. Standalone mode (launched from Home Screen) is the only way to remove browser chrome. The status bar remains visible even in standalone. - Apple-specific meta tags required — iOS Safari does not fully use the Web App Manifest icon fields. You need separate HTML meta tags:
apple-touch-iconfor the home screen icon andapple-touch-startup-imagefor the splash screen. Without them, iOS will auto-generate a screenshot thumbnail as the icon, which looks bad.
Recommended Implementation
manifest.webmanifest
{
"name": "Shadows",
"short_name": "Shadows",
"start_url": "/",
"display": "standalone",
"background_color": "#0a0a0f",
"theme_color": "#0a0a0f",
"icons": [
{ "src": "/icons/icon-192.png", "sizes": "192x192", "type": "image/png", "purpose": "any" },
{ "src": "/icons/icon-512.png", "sizes": "512x512", "type": "image/png", "purpose": "any" },
{ "src": "/icons/icon-512-maskable.png", "sizes": "512x512", "type": "image/png", "purpose": "maskable" }
]
}
HTML head meta tags (iOS-specific)
<!-- Link the manifest -->
<link rel="manifest" href="/manifest.webmanifest">
<!-- iOS home screen icon (bypasses manifest, required for iOS) -->
<link rel="apple-touch-icon" sizes="180x180" href="/icons/apple-touch-icon.png">
<!-- iOS standalone mode -->
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<meta name="apple-mobile-web-app-title" content="Shadows">
<!-- iOS splash screens (one per device size) -->
<link rel="apple-touch-startup-image" href="/icons/splash-2048x2732.png"
media="(device-width: 1024px) and (device-height: 1366px) and (-webkit-device-pixel-ratio: 2)">
<!-- Theme colour for browser chrome (Android) -->
<meta name="theme-color" content="#0a0a0f">
<!-- Viewport — critical for mobile -->
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
viewport-fit=cover is important: it makes the canvas fill the notch/Dynamic Island area on iPhones. Without it there are black bars.
Service Worker (minimum viable)
A bare-minimum SW is required for Android installability. For a live game, offline mode isn't useful, but the SW still needs to exist:
// sw.js — registers the app as installable; no caching needed for an online game
self.addEventListener('fetch', () => {});
Register it in your entry point:
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/sw.js');
}
Android Custom Install Prompt
let installPrompt = null;
window.addEventListener('beforeinstallprompt', (e) => {
e.preventDefault();
installPrompt = e;
// show your own "Install App" button in the game UI
});
// when user clicks your button:
installPrompt?.prompt();
Icon Files to Create
| File | Size | Use |
|---|---|---|
| icon-192.png | 192×192 | Android manifest (any) |
| icon-512.png | 512×512 | Android manifest (any) |
| icon-512-maskable.png | 512×512 | Android adaptive icon (maskable — safe zone is centre 80%) |
| apple-touch-icon.png | 180×180 | iOS home screen |
| splash-*.png | Various | iOS launch screens (optional but polished) |
For the maskable icon: the subject (logo/artwork) must fit within the centre 80% circle. The outer 10% padding on each side will be cropped by Android adaptive icon shapes.
Verdict for a WebSocket Canvas Game
| Feature | Android | iOS iPhone | iOS iPad |
|---|---|---|---|
| Installable | ✓ Auto prompt | ⚠ Manual 4-tap flow | ⚠ Manual 4-tap flow |
| Fullscreen | ✓ | ⚠ Standalone only | ✓ requestFullscreen |
| WebSockets | ✓ | ✓ (use heartbeat) | ✓ (use heartbeat) |
| Canvas rendering | ✓ | ✓ | ✓ |
| Background persistence | ✓ | ✓ | ✓ |
| Icon quality | ✓ Adaptive | ✓ With apple-touch-icon | ✓ With apple-touch-icon |
Recommendation: implement the full metadata set — it's low-effort and makes Android excellent. iOS is worth doing for the standalone experience; just don't promise users an install prompt that will never appear.
Sources
webkit.org — News from WWDC25: Safari 26 Beta
bugs.webkit.org — WebSocket onclose not firing (Safari 15.6.1–16.6)
web.dev — Promote PWA install
firt.dev — PWA on iOS notes
gist.github.com — fozzedout PWA reference
vinova.sg — Navigating Safari iOS PWA limitations
dev.to — Why not "any maskable" for PWA icons