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>
272 lines
6.9 KiB
Markdown
272 lines
6.9 KiB
Markdown
# 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.<XX+1>"
|
|
```
|
|
|
|
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`
|