# Upload Android App to Local App Store Follow these steps to add a new Android app to the Local App Store. ## Prerequisites - Java 17: `export JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64` - Android SDK: `export ANDROID_HOME=/home/jarian/android-sdk` - Gradle wrapper in your app project (run `gradle wrapper` if missing) - Signing keystore: `/home/jarian/playground/app-store/signing/localstore.keystore` (alias `localstore`, password `localstore123`) - Server running on port 9800 ## Step 1: Build the APK ```bash export JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64 export ANDROID_HOME=/home/jarian/android-sdk cd /path/to/your/app/project ./gradlew :app:assembleRelease ``` The signed release APK will be at `app/build/outputs/apk/release/app-release.apk`. ## Step 2: Copy APK to repos ```bash cp app/build/outputs/apk/release/app-release.apk /home/jarian/playground/app-store/server/repos/.apk ``` Use a lowercase, hyphen-separated ID (e.g., `myapp`, `hello-world`). ## Step 3: Create metadata JSON Create `.json` in the repos directory alongside the APK: ```json { "name": "App Display Name", "description": "One or two sentences describing the app.", "icon": null, "screenshots": [], "package_name": "com.your.package", "version_name": "1.0", "version_code": "1", "min_sdk": "26", "target_sdk": "34", "permissions": ["android.permission.INTERNET"] } ``` **Field notes:** - `name`: Human-readable display name - `description`: Short description shown in the store - `icon`: `null` if no PNG icon in the APK, otherwise the resource path (e.g., `res/drawable-mdpi/ic_launcher.png`) - `screenshots`: Array of screenshot filenames, or `[]` if none - `package_name`: From `AndroidManifest.xml` or `build.gradle` - `version_name` / `version_code`: From `build.gradle` `defaultConfig` - `min_sdk` / `target_sdk`: From `build.gradle` `defaultConfig` - `permissions`: Array of `` entries from `AndroidManifest.xml` ## Step 4: Trigger server scan ```bash curl -X POST http://localhost:9800/api/scan ``` Or restart the server if preferred: ```bash screen -S appstore -X quit 2>/dev/null sleep 1 screen -dmS appstore bash -c "cd /home/jarian/playground/app-store/server && source venv/bin/activate && python -c 'import uvicorn, sys; sys.path.insert(0, \".\"); from main import app; uvicorn.run(app, host=\"0.0.0.0\", port=9800)'" ``` ## Step 5: Verify ```bash curl -s http://localhost:9800/api/apps | python3 -c " import json, sys data = json.load(sys.stdin) print(f'Total: {data[\"total\"]} apps') for app in data['apps']: print(f' - {app[\"name\"]} (v{app[\"version_name\"]}, pkg={app[\"package_name\"]})') " ``` ## Optional: Add to downloads directory For easy browser download via `/dl/` endpoint: ```bash cp app/build/outputs/apk/release/app-release.apk /home/jarian/playground/app-store/server/downloads/.apk ``` ## Common Issues - **Binary XML manifest parsing**: The scanner reads APKs directly without `aapt`. Fields like `version_name` may show `unknown` if the string parser misses them — always set them in the JSON override. - **No PNG icon**: If the APK only has XML vector drawables, set `"icon": null` in the JSON. - **KSP plugin**: Required for Room. Keep only in `app/build.gradle`, not root `build.gradle`. - **Navigation**: Use `` tag (not `FrameLayout`) with `android:name="androidx.navigation.fragment.NavHostFragment"`, or add NavHostFragment programmatically in MainActivity. - **Data binding**: Cannot create typed properties for `` tags. Use programmatic NavHostFragment instead. - **Lint**: Set `checkReleaseBuilds false` to avoid blocking builds.