Skip to content

adit9852/android-emulator-platform

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

18 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

πŸ“± Android Emulator Platform

Real Android devices, streamed live to your browser β€” no install, no signup.

A self-hosted, open-source alternative to Appetize.io. Launch a real Android emulator in one click, touch and type on it in real time, drag-and-drop an APK to install it, and simulate GPS, battery, and network β€” all from a single browser tab.

Live Demo

License: MIT React Node.js Docker Android TLS

Live Android session in the browser

✨ Highlights

  • πŸš€ One-click live device β€” pick a phone, hit Start, and a pre-warmed emulator is streaming in seconds (no per-session boot wait).
  • πŸ‘† Real-time touch & keyboard β€” native, low-latency input over scrcpy. Your laptop keyboard maps straight to the device.
  • πŸ“¦ Install any APK β€” drag-and-drop a file or paste a download URL; install + auto-launch on the live device.
  • πŸŽ›οΈ Hardware controls β€” Home, Back, Recents, Power, Volume, rotate, and screenshot from a dock beside the phone.
  • 🌐 Developer tools β€” throttle the network (Wi-Fi β†’ 4G β†’ 3G β†’ EDGE β†’ offline), set the battery level, spoof GPS (city presets), and open any URL on the device.
  • πŸ“Š Live dashboard β€” Apps library, session history, and a real-time capacity/utilization report.
  • πŸ”’ Production-ready edge β€” nginx reverse proxy, automatic Let's Encrypt HTTPS, and all streams tunnelled through one secure origin (zero mixed-content).
  • 🎨 Polished SaaS UI β€” React + Tailwind, glassmorphism, teal/cyan theme, meaningful motion, fully responsive.

πŸ–ΌοΈ Screenshots

Apps manager
Apps β€” upload, install & manage APKs
Reports dashboard
Reports β€” live capacity & device pool
Settings
Settings β€” session defaults, interface toggles & platform info

πŸ—οΈ How it works

The hard part of streaming a phone to a browser is doing it securely and with real input. Here's the full path of a tap:

flowchart LR
    U["🌐 Browser<br/>(React app)"] -->|HTTPS / WSS| N["nginx<br/>TLS · reverse proxy"]
    N -->|/api| B["Backend<br/>Express"]
    N -->|/stream/N| S["scrcpy-display<br/>noVNC + websockify"]
    B <-->|slot pool Β· sessions| R[("Redis")]
    B <-->|session records| P[("PostgreSQL")]
    B -->|ADB control| E["Android Emulator<br/>QEMU + KVM Β· Android 11"]
    S -->|scrcpy β†’ Xvfb β†’ x11vnc| E
Loading
  1. The backend keeps a pre-warmed pool of emulator slots in Redis. Starting a session just hands one out β€” no boot wait.
  2. Each emulator has a paired scrcpy-display container that renders only the phone screen (scrcpy β†’ Xvfb β†’ x11vnc β†’ websockify β†’ noVNC).
  3. nginx serves the React app, proxies the API, and tunnels each stream at /stream/<slot>/ over TLS β€” so the live video + WebSocket input share one secure origin (no http://ip:port, no mixed-content blocks).
  4. Touches and keystrokes ride scrcpy's native input straight into Android's InputManager β€” real, low-latency, and keyboard-mapped.

πŸ’‘ Why scrcpy + noVNC instead of a custom WebRTC bridge? It gives native keyboard/gesture mapping and rock-solid latency with far less moving machinery. Earlier MSE/ffmpeg and ws-scrcpy approaches were prototyped and dropped β€” see the inline notes in scrcpy-display/ and backend/src/routes/emulator.js.


🧰 Tech stack

Layer Technologies
Frontend React 18, Vite 5, Tailwind CSS 3, lucide-react
Backend Node.js, Express 4, Redis (slot pool + cache), PostgreSQL 15, Multer, Winston, dockerode, ws, Helmet, rate-limiting
Emulation budtmo/docker-android Β· Android 11 Β· QEMU + KVM Β· GPU passthrough (-gpu host, /dev/dri)
Streaming scrcpy β†’ Xvfb β†’ x11vnc β†’ websockify β†’ noVNC
Infra / Edge Docker Compose, nginx, Let's Encrypt (certbot, auto-renew)
Observability Prometheus + Grafana

Default device pool: Samsung Galaxy S10 Β· Nexus 5 Β· Samsung Galaxy S6 (Android 11) β€” 3 pre-warmed concurrent slots.


πŸš€ Quick start (self-host)

Prerequisites

  • A Linux host with Docker + Docker Compose
  • KVM enabled (/dev/kvm) β€” required for usable emulator performance (a bare-metal or nested-virt VPS, e.g. Hetzner)
  • ~8 GB RAM for the 3-device pool

Run it

# 1. Clone
git clone https://github.com/adit9852/android-emulator-platform
cd android-emulator-platform

# 2. Configure environment (DB creds, JWT secret, etc.)
cp .env.example .env   # then edit values

# 3. Build & launch the whole stack
docker compose up -d --build

# 4. Open the app
#    http://<your-server-ip>

The emulator pool boots once at startup and stays warm. First boot pulls images and provisions Android β€” give it a few minutes.

Make it a public HTTPS link

Point a domain (or use a free sslip.io host) at the server, then issue a cert with certbot's webroot challenge and enable the 443 server block in nginx/nginx.conf. The live demo runs exactly this setup with auto-renewal. See DEPLOYMENT_GUIDE.md.


πŸ”Œ API reference

All routes are under /api. Highlights:

Method Endpoint Description
GET /emulator/devices List devices and availability
GET /emulator/pool Slot pool status
POST /emulator/session Start a session (claims a slot)
GET /emulator/session/:id Session details + stream URL
DELETE /emulator/session/:id End a session (releases the slot)
GET /emulator/sessions List active sessions
POST /emulator/key Press a hardware key (Home/Back/…)
POST /emulator/tap Β· /swipe Β· /text Inject touch / text
POST /emulator/rotate/:id Toggle portrait ↔ landscape
GET /emulator/screenshot/:id Capture the screen
POST /emulator/gps Β· /battery Β· /network Β· /url Simulate sensors / open a URL
POST /upload/apk Β· /upload/apk-url Upload an APK (file or URL)
POST /upload/install Install an APK on a live device
GET / DELETE /upload/apks Β· /upload/apk/:id List / delete library APKs
GET /health Health check

πŸ“ Project structure

android-emulator-platform/
β”œβ”€β”€ frontend/         # React + Vite + Tailwind SPA (the dashboard & phone view)
β”œβ”€β”€ backend/          # Express API β€” slot pool, sessions, input, APKs (Redis + Postgres)
β”œβ”€β”€ emulator/         # Android emulator image (budtmo-based, Android 11)
β”œβ”€β”€ scrcpy-display/   # Per-emulator screen-streaming container (scrcpy β†’ noVNC)
β”œβ”€β”€ nginx/            # Reverse proxy + TLS termination + /stream routing
β”œβ”€β”€ monitoring/       # Prometheus + Grafana config
β”œβ”€β”€ docs/             # Screenshots
└── docker-compose.yml

πŸ—ΊοΈ Roadmap

  • User accounts & API keys (auth scaffolding already present)
  • Horizontal scaling of the emulator pool across hosts
  • Session recording & shareable replays
  • More devices / Android versions
  • Per-session resource quotas & idle reaping UI

⚠️ Notes & limitations

  • The default deployment runs 3 concurrent device slots β€” capacity scales with host CPU/RAM.
  • The Android launcher is portrait-locked (standard Android); rotation takes effect inside apps that support landscape.
  • KVM is effectively mandatory β€” without hardware virtualization the emulators are too slow to be usable.

πŸ™ Acknowledgements

Built on the shoulders of scrcpy, noVNC, budtmo/docker-android, and the wider Android emulator community. Design benchmarked against (not copied from) Appetize.io.

πŸ“„ License

MIT β€” free to use, modify, and self-host.

Made with β˜• and a lot of docker compose up.

About

Browser-based Android emulator streaming platform - React + Node.js + Docker + scrcpy + noVNC, with TLS, slot pooling & APK install.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors