The Problem
Developers and power‑users often need a quick way to package a web page (or a small web app) as a native Android APK without installing Android Studio or writing Java/Kotlin code. Existing solutions require a desktop build environment, manual signing, and custom wrapper code, which adds friction for rapid prototyping or distribution.
What This Does
web-to-app is an Android application that lets a user type a URL, selects optional AI‑generated assets, and produces a signed, encrypted APK directly on the device. The core conversion logic lives in the Kotlin package com.webtoapp.core.
app/src/main/java/com/webtoapp/ui/MainActivity.ktlaunches the UI, collects the target URL, and invokesApkBuilder(seeapp/src/main/java/com/webtoapp/core/apkbuilder/ApkBuilder.kt).ApkBuilderassembles a temporary Android project, copies the selected sample front‑end (e.g.,app/src/main/assets/sample_projects/react-demo/dist/) and runsFrontendProjectBuilder(app/src/main/java/com/webtoapp/core/frontend/FrontendProjectBuilder.kt) to inject the URL into the web assets.- The final binary is encrypted with the AES‑GCM engine (
app/src/main/cpp/crypto_engine.cpp+app/src/main/java/com/webtoapp/core/crypto/AesCryptoEngine.kt) and signed byJarSigner.kt.
All UI components (cards, dialogs, etc.) are pure Compose files under app/src/main/java/com/webtoapp/ui/components/, keeping presentation separate from the build pipeline.
How It Is Wired
- App launch – Android starts
MainActivity(MainActivity.kt). - User input – UI components call
AppExporter.exportApp(url)(implemented inAppExporter.kt). - Project preparation –
AppExportercreates aFrontendProjectConfigand passes it toFrontendProjectBuilder.build(config). This builder copies the selected sample project fromapp/src/main/assets/sample_projects/*/dist/into a temporary directory. - URL injection –
ProjectDetectorscans the copied assets and replaces placeholder strings with the user‑provided URL (logic inProjectDetector.kt). - APK assembly –
ApkBuilder.build(tempDir)creates the AndroidManifest, resources, and compiles the stub app using Gradle (app/build.gradle.kts). - Encryption – Before signing, the generated APK bytes are fed to
AesCryptoEngine.encrypt()which calls the nativecrypto_engine.cpp(via JNI declared inNativeCrypto.kt). - Signing –
JarSigner.sign(apkBytes)produces the final signed APK placed in the app’s private storage.
The widest blast radius lies in crypto_engine.cpp and AiApiClient.kt – they touch native code and external AI services, respectively, so changes there affect security and network behavior across the whole product.
How To Use It
# Clone the repository
git clone https://github.com/moses-y/web-to-app
cd web-to-app
# Build the Android app (requires Android SDK and Gradle)
./gradlew :app:assembleDebug # produces app/build/outputs/apk/debug/app-debug.apk
No additional configuration files are required for a basic build. To run the app on a device, install the debug APK (adb install app/build/outputs/apk/debug/app-debug.apk) and launch it. Inside the app, enter a URL and tap Build APK; the generated file appears in the app’s “Export” folder.
Real‑World Use
A marketing team can ship a branded web landing page as an installable APK for events where Google Play distribution is unavailable. The workflow:
val url = "https://example.com/promo"
AppExporter.exportApp(url) // invoked from a button in MainActivity
The resulting APK can be shared via QR code or NFC without any external build server.
Code Health & Issues
- High – No test suite – 226 source files, 0 test files (
[HIGH] Add a test suite). - High – Missing lockfile –
app/src/main/assets/sample_projects/react-demo/package.jsonhas no accompanying lockfile ([HIGH] Commit a lockfile). - High – No CI workflow – Repository contains no GitHub Actions or other CI config (
[HIGH] Add a workflow that builds and tests). - Medium – Dependabot disabled – No automatic dependency updates (
[MEDIUM] Enable Dependabot or Renovate). - Medium – Generated output committed – 27 build artifacts are tracked in
app/([MEDIUM] Remove generated build output). - Low – Missing convention files – No
.editorconfig,.gitattributes, or formatter config ([LOW] Add the repository convention files).
The static analysis also flagged deep nesting (up to 8 levels) in files such as crypto_engine.cpp and several AI‑related Kotlin classes, indicating a potential maintenance burden.
The Bottom Line
web-to-app delivers a functional on‑device pipeline for turning arbitrary URLs into signed Android APKs, with a clear separation between UI, build orchestration, and cryptographic handling. However, the lack of automated tests, CI, and reproducible JavaScript dependencies makes it risky for production use or downstream modification. It is best suited for internal prototyping or as a reference implementation for teams willing to invest in test and CI scaffolding.