A single HTML file becomes an Android app by being bundled, unchanged, into a WebView shell. Because everything the page needs — markup, styles, scripts, images — is inside the one document, there are no relative paths to break, no folder to zip and nothing that can be missing on the phone. Upload the file, name the app, pick an icon, build, and the APK installs and runs with no connection. For any page that fits in one file, this is the route to take.
Which apps suit a single file
Anything self-contained and modest in size: a calculator or converter, a quiz or flashcard deck, a checklist, a timer, a form that saves locally, a landing page or portfolio, a small HTML5 game built on canvas, a reference card, a menu, a course lesson. The practical ceiling is a few megabytes; above that, images are better kept as files in a folder. The free tier accepts up to 5 MB of source, Pro up to 18 MB.
What the file needs
The head
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<meta name="theme-color" content="#c96a4a">
<title>My App</title>
The viewport line is not optional. Without it the WebView lays the page out at 980 px wide and shrinks it to fit — the "everything is tiny" complaint. viewport-fit=cover lets the page extend under the system bars on new phones so you can pad it with env(safe-area-inset-*). theme-color is read by the builder for the status bar.
Styles and scripts: inline
Move the contents of style.css into a <style> block in the head and the contents of app.js into a <script> block at the end of the body. If your code contains a literal </script> inside a string, escape it as <\/script>. The merger does all of this — including the escaping — automatically.
Images and fonts: embedded
Images go in as data URIs — base64 text in the src attribute or a CSS url(). Small icons and logos cost a few kilobytes each; photographs should be resized to phone width first. Fonts: use the system stack (system-ui, Roboto, sans-serif) rather than a Google Fonts link, which needs a connection. A .woff2 can be embedded as a data URI inside @font-face if a specific face matters.
No external anything
Every https:// in a src or href is a request the app will make on the phone. A CDN copy of jQuery, Bootstrap or Tailwind's play script, a Font Awesome kit, an analytics tag — each is a dependency on the network. Download the library and inline it, or remove it. The Offline Readiness Checker lists every one.
Storage without a server
The one thing a single-file app cannot do is write to itself. State — scores, settings, entries — goes in localStorage (simple, string values, ~5 MB) or IndexedDB (structured, larger). Both survive app restarts and are cleared only when the app's data is cleared or it is uninstalled. The storage guide covers the options and their limits.
Build it
- Open the file from your disk in Chrome. Press F12, toggle device mode, pick a phone. If it looks right here, it will look right in the app.
- Go to the builder, drop the file.
- Set the name, the icon and the colour. Leave the package name the builder suggests unless you have a reason to change it — it cannot change later.
- Build. Download the APK on your phone (or send it to yourself), open it, allow the install.
The first launch shows the splash screen for a moment and then your page, full-screen, with your colour in the status bar. Turn on airplane mode and open it again: it still works, because there was never a server.
Updating it later
Change the file, rebuild with the same package name and a higher version code, install over the top. Android treats it as an update and keeps localStorage intact. The versioning guide has the rules.