Mobile update channel
Mobile uses a first-class release channel, not ad-hoc APK links. Clients poll a versioned JSON manifest, compare integer build numbers, and prompt (or force) install. This is separate from imux macOS Sparkle updates.
Manifest
Canonical URL:
- version — semver string (display)
- versionCode — Android integer; primary upgrade key
- iosBuildNumber / downloads.ios.buildNumber — iOS CFBundleVersion
- downloads.android.apk — HTTPS APK URL
- downloads.ios.appStore / testFlight — when published
- downloads.ios.ipa — App Store signed archive URL (not sideload)
- forceUpdate / minVersionCode — block dismiss when required
- changelog[] — modal and download page copy
- packageId — com.clavue.xw
GET https://www.clavue.com/downloads/mobile/latest-mobile.json
# Cache-bust query: ?_=<timestamp> (app always appends)Client behavior
- Cold start: force network check
- App resume: throttled (default 6h, overridable via checkIntervalHours)
- Settings → Check for updates: force network, ignore dismiss
- Local notification channel app-updates (once per remote versionCode)
- Dismiss stores dismissedVersionCode until a higher remote code appears
Publish a build
versionCode must strictly increase for same package id. Changing package id (e.g. com.clavue.mobile → com.clavue.xw) is a new app — users reinstall.
cd clavue-mobile
./scripts/publish-android-release.sh --bump patch --deploy \
--notes "修复说明;第二条 changelog"
# Force users below a floor:
./scripts/publish-android-release.sh --bump patch --deploy --force-updateiOS releases
Archive + export App Store IPA (sync CFBundleShortVersionString / CFBundleVersion with app.json first). Upload with Transporter. Host a copy under /downloads/mobile/clavue-mobile-vX.Y.Z-ios.ipa and set downloads.ios.ipa + buildNumber + status ready_for_app_store. After the listing is live, set downloads.ios.appStore and status published. See clavue-mobile/IOS_RELEASE.md.