SkateSpots/ZAPSTORE.md
shakespeare.diy 90d300d5dd SECURITY: remove committed nsec from ZAPSTORE.md
Replace the hardcoded signing nsec with a `nsec1...` placeholder and add a
warning to always pass SIGN_WITH inline at runtime, never commit it.

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-07-25 13:31:09 +07:00

6.9 KiB

SkateSpots — Zapstore Publishing Guide

Get SkateSpots on Zapstore 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.<XX+1>"

Bump the Android version in android/app/build.gradle:

# 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

git pull

Step 3 — Build the APK

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

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)

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

git clone nostr://npub1yrnuj56rnen08zp2h9h7p74ghgjx6ma39spmpj6w9hzxywutevsst7k5cx/git.shakespeare.diy/SkateSpots
cd SkateSpots
npm install

Step 2 — Install Capacitor

npm install @capacitor/core @capacitor/cli @capacitor/android
npm install @capacitor/splash-screen @capacitor/status-bar @capacitor/keyboard

Step 3 — Initialize Android project

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:

# 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)

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

npm run android:build

Or manually with signing:

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)

go install github.com/zapstore/zsp@latest
export PATH=$PATH:$(go env GOPATH)/bin

Step 8 — Publish to Zapstore

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:

# 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:

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