Tutorial 05

PWA and Google Play

Turn the chat app you built into something with a real icon on a real phone’s home screen — and get it onto the Google Play Store.

Time: 60–90 minutes Cost: Free (Google Play developer account is a one-time $25 fee) Level: Beginner

What Is a PWA?

A Progressive Web App, or PWA, is a website that can be installed like a regular app — with its own icon on the home screen, its own window with no browser bar, and the ability to work as a real Android app through the Google Play Store. The website you already built doesn’t need to be rebuilt for this. You're adding a small set of files that tell phones and app stores how to treat it.

💡 You need exactly three things: a manifest.json file describing your app, a service worker file that lets it work offline, and two icon images. That’s the entire technical requirement.


Step 1 — Create Your Icons

You need two square PNG images: icon-192.png (192×192 pixels) and icon-512.png (512×512 pixels). Ask an AI chatbot to design a simple logo for your app, or create one yourself in any image editor. Keep it simple — a single bold shape or letter reads better at small sizes than a detailed illustration.


Step 2 — Add the Manifest, Service Worker, and Icon Routes

Extend the Worker from Tutorial 4 with four new routes. Add these constants near the top of your file:

const MANIFEST = {
  name: "My App",
  short_name: "My App",
  start_url: "/",
  display: "standalone",
  background_color: "#0d1117",
  theme_color: "#0d1117",
  icons: [
    { src: "/icon-192.png", sizes: "192x192", type: "image/png", purpose: "any" },
    { src: "/icon-192.png", sizes: "192x192", type: "image/png", purpose: "maskable" },
    { src: "/icon-512.png", sizes: "512x512", type: "image/png", purpose: "any" },
    { src: "/icon-512.png", sizes: "512x512", type: "image/png", purpose: "maskable" }
  ]
};

⚠️ This exact detail caused a full day of debugging on a real PrivateAI site. Each icon size needs two separate entries — one with purpose "any" and one with purpose "maskable" — four entries total for two icon sizes. Combining them into one entry with "any maskable" looks like it should work, but Google’s packaging tool will reject it. Copy the structure above exactly.

For the icon images themselves, convert each PNG to a long line of text called base64, then add routes that decode and serve them:

if (url.pathname === "/manifest.json") {
  return new Response(JSON.stringify(MANIFEST), {
    headers: { "Content-Type": "application/manifest+json" }
  });
}

if (url.pathname === "/icon-192.png") {
  const bin = atob(ICON192_BASE64);
  const bytes = new Uint8Array(bin.length);
  for (let i = 0; i < bin.length; i++) bytes[i] = bin.charCodeAt(i);
  return new Response(bytes, { headers: { "Content-Type": "image/png" } });
}

Add a simple service worker too — this is what makes the app installable:

const SW = "self.addEventListener('install', e => self.skipWaiting());" +
  "self.addEventListener('fetch', e => e.respondWith(fetch(e.request)));";

if (url.pathname === "/sw.js") {
  return new Response(SW, { headers: { "Content-Type": "application/javascript" } });
}

Finally, add these two lines inside the <head> of your HTML so the browser knows the manifest exists:

<link rel="manifest" href="/manifest.json">
<meta name="theme-color" content="#0d1117">

Deploy, then check yourworker.workers.dev/manifest.json in your browser — you should see the JSON with four icon entries.


Step 3 — Package It With PWABuilder

1Go to PWABuilder

Visit pwabuilder.com and enter your site’s URL (your custom domain, or the .workers.dev address). It will analyze your manifest, icons, and service worker.

2Fix anything flagged

If it flags an issue with your icons or manifest, it’s almost always the four-entry icon structure from Step 2. Re-check that before anything else.

3Generate the Android package

Choose Google Play as the target, set a package name in reverse-domain format (like com.yourcompany.yourapp), and generate the package.

⚠️ PWABuilder’s servers are sometimes unreliable and will occasionally return a 500 error that has nothing to do with your site. If this happens, simply wait a few minutes and try again, or try a different browser. This is not a sign anything is wrong with your manifest.


Step 4 — Save Your Signing Key

When the package finishes, you’ll get a .zip file containing your .aab file (the Android app itself) and a signing keystore file.

⚠️ Save the keystore file somewhere safe immediately. This file is what proves you are the legitimate publisher of your app. Every future update to your app must be signed with this exact same keystore. If you lose it, you cannot update your app — ever. You would have to publish it as a brand new app instead.


Step 5 — Submit to Google Play

1Create a Google Play Developer account

Go to play.google.com/console and sign up. There is a one-time $25 registration fee.

2Create your app

Click Create app, give it a name, choose App and Free.

3Set up internal testing

Go to Testing → Internal testing → Create new release. Upload your .aab file, add release notes, and add at least one tester email — your own is fine to start.

4Complete the store listing

Fill in your app’s description, upload a feature graphic (1024×500 pixels) and at least two screenshots, complete the content rating questionnaire, and add a privacy policy URL.

🎉 Internal testing is instant. Once a tester accepts the invite, they can install your app from a private link — no waiting for Google’s review. Full public review is only required when you move to production.


What You Learned