# SkateSpots — Zapstore Publishing Guide Get SkateSpots on [Zapstore](https://zapstore.dev) as a native Android APK. --- ## 🚀 Releasing a new version (the recurring flow) > This is the process to follow **every time** you ship an update. For a > brand-new machine setup (keystore, `android:init`, etc.) see > **First-time setup** further down. ### Prerequisites - `zsp` installed at `~/go/bin/zsp` - `SIGN_WITH` env var with your nsec - Android SDK + Gradle installed ### Step 1 — Bump versions (BOTH files) Bump the web version in `package.json`: ``` "version": "1.0.XX" → "1.0." ``` Bump the Android version in `android/app/build.gradle`: ```bash # Check current version first grep -n "versionCode\|versionName" android/app/build.gradle # Bump it (replace OLD/NEW with actual numbers) sed -i 's/versionCode OLD/versionCode NEW/' android/app/build.gradle sed -i 's/versionName "1.0.OLD"/versionName "1.0.NEW"/' android/app/build.gradle # Verify grep -n "versionCode\|versionName" android/app/build.gradle ``` > ⚠️ **Both numbers must be bumped** — `package.json` for the web app, > `build.gradle` for the APK. **Zapstore reads the version from the APK > (`build.gradle`)**, so if you forget that one you'll get `Asset already exists`. ### Step 2 — Pull latest from git ```bash git pull ``` ### Step 3 — Build the APK ```bash npm run android:build ``` This runs: (1) Vite build → (2) Capacitor sync → (3) Gradle `assembleRelease`. ✅ Look for **BUILD SUCCESSFUL** at the end. ### Step 4 — Publish to Zapstore ```bash SIGN_WITH=nsec1... ~/go/bin/zsp publish zapstore.yaml ``` The wizard will: parse & verify the APK → fetch Play Store metadata → sign with your nsec → publish to `wss://relay.zapstore.dev` → upload the APK to `cdn.zapstore.dev`. - When prompted **"Preview release in browser?"** → select **No, skip** - When prompted **"Choose an option"** → select **Publish now** ### Full one-liner (once versions are bumped) ```bash git pull && npm run android:build && SIGN_WITH=nsec1... ~/go/bin/zsp publish zapstore.yaml ``` ### Verify it's live https://zapstore.dev/apps/org.skatespots.app ### Troubleshooting | Problem | Fix | |---|---| | `zapstore: command not found` | Use `~/go/bin/zsp` instead | | `zsp: command not found` | Run `go install github.com/zapstore/zsp@latest` | | `Asset already exists` | Version not bumped — check `build.gradle` | | Vite build fails | Run `git pull` first to get latest fixes | | Merge conflict on `package-lock.json` | `git checkout --theirs package-lock.json && git add package-lock.json && git commit` | --- ## First-time setup The sections below are only needed the **first time** you set up a machine (installing tooling, creating the signing keystore, initializing the Android project). For normal releases, use the flow above. ## Prerequisites (install on your machine) 1. **Node.js 18+** — https://nodejs.org 2. **Java 17** — https://adoptium.net 3. **Android Studio** — https://developer.android.com/studio - After install: open Android Studio → SDK Manager → install Android SDK 34 4. **Go** (for `zsp` CLI) — https://go.dev/dl/ --- ## Step 1 — Clone & install ```bash git clone nostr://npub1yrnuj56rnen08zp2h9h7p74ghgjx6ma39spmpj6w9hzxywutevsst7k5cx/git.shakespeare.diy/SkateSpots cd SkateSpots npm install ``` --- ## Step 2 — Install Capacitor ```bash npm install @capacitor/core @capacitor/cli @capacitor/android npm install @capacitor/splash-screen @capacitor/status-bar @capacitor/keyboard ``` --- ## Step 3 — Initialize Android project ```bash npm run android:init ``` This: - Builds the web app into `dist/` - Creates the `android/` folder with a full Android project - Copies your web build into the Android WebView --- ## Step 4 — Add app icons Copy your icon files into the Android resources: ```bash # The app already has icons in public/images/ # After android:init, copy them: cp public/images/icon-1024.png android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png ``` Or use Android Studio: right-click `app` → New → Image Asset → import `public/images/icon-1024.png` --- ## Step 5 — Generate a signing keystore (one-time) ```bash keytool -genkey -v \ -keystore skatespots-release.jks \ -alias skatespots \ -keyalg RSA \ -keysize 2048 \ -validity 10000 \ -dname "CN=SkateSpots, OU=SkateSpots, O=SkateSpots, L=Bangkok, S=Bangkok, C=TH" ``` **Save the keystore file and passwords somewhere safe — you need them for every future release.** --- ## Step 6 — Build the release APK ```bash npm run android:build ``` Or manually with signing: ```bash npm run build npx cap sync android cd android ./gradlew assembleRelease \ -Pandroid.injected.signing.store.file=../skatespots-release.jks \ -Pandroid.injected.signing.store.password=YOUR_STORE_PASSWORD \ -Pandroid.injected.signing.key.alias=skatespots \ -Pandroid.injected.signing.key.password=YOUR_KEY_PASSWORD ``` APK output: `android/app/build/outputs/apk/release/app-release.apk` --- ## Step 7 — Install zsp (Zapstore CLI) ```bash go install github.com/zapstore/zsp@latest export PATH=$PATH:$(go env GOPATH)/bin ``` --- ## Step 8 — Publish to Zapstore ```bash SIGN_WITH=nsec1... zsp publish --wizard ``` > ⚠️ **Never commit your nsec.** Always pass it inline at runtime via the > `SIGN_WITH` env var, and never paste it into any tracked file. The wizard will: 1. Ask for your APK path → point to `android/app/build/outputs/apk/release/app-release.apk` 2. Link your APK signing certificate to your Nostr identity (one-time NIP-C1 proof) 3. Publish the app event to Zapstore's relay **Note:** `zapstore.yaml` is already committed to the repo — Zapstore will use it to verify your identity automatically. --- ## Step 9 — Verify on Zapstore Visit: https://zapstore.dev/app/org.skatespots.app Or search "SkateSpots" in the Zapstore app. --- ## Updating the app For future releases: ```bash # 1. Build new APK npm run android:build # 2. Publish new version SIGN_WITH=nsec1... zsp publish -r git.shakespeare.diy/skatespots/SkateSpots ``` --- ## Android project structure ``` android/ ├── app/ │ ├── src/main/ │ │ ├── assets/public/ ← your web app lives here (auto-synced) │ │ ├── res/ ← icons, splash screens │ │ └── AndroidManifest.xml │ └── build/outputs/apk/release/app-release.apk ← built APK ├── capacitor.settings.gradle └── build.gradle ``` ## Troubleshooting **`ANDROID_HOME` not set:** ```bash export ANDROID_HOME=$HOME/Library/Android/sdk # macOS export ANDROID_HOME=$HOME/Android/Sdk # Linux export PATH=$PATH:$ANDROID_HOME/platform-tools ``` **Gradle build fails:** - Make sure Java 17 is active: `java -version` - Switch with: `export JAVA_HOME=$(/usr/libexec/java_home -v 17)` **WebSocket connections blocked:** - Already handled — `capacitor.config.ts` sets `allowMixedContent: true`