commit ad51890cb20892cfd202f0f053d93771f858d8a9 Author: Jarian Date: Wed May 13 04:01:37 2026 +0000 first commit diff --git a/README.md b/README.md new file mode 100644 index 0000000..d461974 --- /dev/null +++ b/README.md @@ -0,0 +1,223 @@ +# Local App Store + +A private Android app store for your local network. Serve APKs from your own repository and install them on your devices via the Android app or browse/download from any browser. + +## Architecture + +- **Server**: FastAPI application that serves APKs and metadata over HTTP +- **Android Client**: Kotlin app with Material Design 3 UI, Room database, and PackageInstaller integration +- **Web Frontend**: Single-page HTML/JS app served by the server, accessible from any browser +- **Signing**: Self-signed keystore for both the store app and distributed apps + +## Quick Start + +### 1. Server Setup + +```bash +cd server + +# Activate virtual environment +source venv/bin/activate + +# Install dependencies (if not already done) +pip install -r requirements.txt + +# Drop your APKs into the repos/ directory +cp /path/to/your/app.apk repos/ + +# Start the server (runs on all interfaces, port 8080) +python main.py +``` + +The server auto-scans `repos/` on startup. To rescan after adding new APKs: + +```bash +curl -X POST http://localhost:8080/api/scan +``` + +You can also add app metadata (name, description, icon, screenshots) by creating a JSON file alongside each APK: + +``` +repos/ +myapp.apk +myapp.json # Optional metadata override +myapp_screenshots/ # Optional screenshots (*.png) +``` + +Example `myapp.json`: + +```json +{ + "name": "My App", + "description": "A great app for doing things", + "icon": "res/mipmap-hdpi/ic_launcher.png", + "screenshots": ["screenshot1.png", "screenshot2.png"] +} +``` + +### 2. Web Frontend + +Once the server is running, open any browser and navigate to: + +``` +http://:8080 +``` + +The web frontend provides: +- Browse all apps in a responsive grid +- Search apps by name or description +- View app details (description, permissions, screenshots) +- Download APK files directly +- Scan repository for new apps + +### 3. Signing APKs + +```bash +cd signing + +# Generate keystore (already done - localstore.keystore exists) +# To regenerate: ./generate-key.sh + +# Sign an APK before adding it to repos/ +./sign-apk.sh /path/to/your/app.apk +``` + +All APKs should be signed with the same keystore for consistency. + +### 4. Building the Android Client + +Prerequisites: Java 17, Android SDK (platform-tools, build-tools 34.0.0, platforms android-34). + +```bash +cd android + +# Configure SDK path (adjust to your SDK location) +echo "sdk.dir=/path/to/android-sdk" > local.properties + +# Build debug APK +./gradlew :app:assembleDebug + +# Build release APK (signed with localstore.keystore) +./gradlew :app:assembleRelease +``` + +APKs are output to `app/build/outputs/apk/`. + +### 5. Installing on Android Device + +```bash +# Connect device via USB or use wireless ADB + +# Install debug build +/home/jarian/android-sdk/platform-tools/adb install app/build/outputs/apk/debug/app-debug.apk + +# Install release build +/home/jarian/android-sdk/platform-tools/adb install app/build/outputs/apk/release/app-release.apk +``` + +First time setup in the app: +1. Open the app -> go to Settings +2. Enter your server IP address (e.g., `192.168.8.128`) +3. Click "Test Connection" to verify +4. Click "Save" +5. Grant "Install unknown apps" permission when prompted + +## API Endpoints + +| Method | Endpoint | Description | +|--------|----------|-------------| +| GET | `/` | Web frontend | +| GET | `/api/apps` | List all apps (supports `?search=`, `?offset=`, `?limit=`) | +| GET | `/api/apps/{id}` | Get app details | +| GET | `/api/apps/{id}/download` | Download APK file | +| GET | `/api/apps/{id}/icon` | Get app icon (128x128 PNG) | +| GET | `/api/apps/{id}/screenshots` | List screenshots | +| GET | `/api/apps/{id}/screenshots/{file}` | Get screenshot image | +| POST | `/api/apps/update-check` | Check for updates | +| POST | `/api/scan` | Trigger repository rescan | +| GET | `/api/status` | Server status info | + +## Configuration + +Server config is in `server/config.yaml`: + +```yaml +server: + host: "0.0.0.0" # Bind to all interfaces + port: 8080 # HTTP port + +repository: + path: "./repos" # APK storage directory +``` + +## Project Structure + +``` +app-store/ +server/ + main.py # FastAPI application + web frontend + app.py # Pydantic models + scanner.py # APK metadata scanner + config.yaml # Server configuration + requirements.txt # Python dependencies + venv/ # Python virtual environment + repos/ # Drop APKs here + web/ + index.html # Web frontend (HTML/CSS/JS) +android/ # Gradle project (CLI build) + build.gradle # Root build config + settings.gradle # Project settings + local.properties # SDK path + app/ + build.gradle # App build config (KSP, Room, etc.) + src/main/ + AndroidManifest.xml + kotlin/com/localstore/ + LocalStoreApp.kt + data/ # API, models, database, repository, settings + ui/ # Fragments, ViewModels, adapters + installer/ # PackageInstaller wrapper + res/ # Layouts, strings, themes, navigation, colors + gradle/ # Gradle wrapper +signing/ + generate-key.sh # Create keystore + sign-apk.sh # Sign APKs + localstore.keystore # Self-signed keystore +app-debug.apk # Debug build +app-release.apk # Release build (signed) +README.md +``` + +## Android Permissions + +The app requires: +- `INTERNET` - connect to the server +- `REQUEST_INSTALL_PACKAGES` - install APKs (user grants in Settings) +- `ACCESS_NETWORK_STATE` - check connectivity + +## Security Notes + +- The keystore is self-signed. For production use, consider a proper CA-signed certificate. +- The server serves over HTTP. For HTTPS, configure a reverse proxy (nginx/Caddy) with Let's Encrypt. +- All APKs should be signed with the same keystore to ensure trust chain. + +## Troubleshooting + +**Apps not appearing after adding to repos/** +- Run `POST /api/scan` or restart the server + +**Icon not loading** +- The server extracts icons from APK resources. If extraction fails, specify icon path in the `.json` metadata file. + +**Installation fails** +- Ensure "Install unknown apps" permission is granted for the app store app in Android Settings + +**Connection fails** +- Check server IP in Settings matches your server's actual IP +- Ensure both devices are on the same network +- Check firewall allows port 8080 + +**Gradle build fails** +- Ensure Java 17 is installed and JAVA_HOME is set +- Ensure Android SDK is installed and `local.properties` points to it +- Run `./gradlew :app:clean` before rebuilding \ No newline at end of file