feat(apple): add direct-download macOS channel (notarized DMG + Sparkle + Homebrew)

Add a second macOS shipping channel alongside the App Store build:

- New VniDropDirect target (Release-Direct config) sharing VniDrop's sources via
  an AppBase target template; links Sparkle behind the DIRECT_DISTRIBUTION flag so
  the App Store binary never bundles a self-updater. arm64-only (core is arm64).
- Sparkle updater (SparkleUpdater.swift) + "Check for Updates" menu, compiled only
  under DIRECT_DISTRIBUTION; Info.plist SUFeedURL points at the GitHub Release
  /latest/download/appcast.xml, non-sandboxed entitlements for Developer ID.
- build-dmg.sh (archive → Developer ID export → DMG → sign → notarize → staple),
  generate-appcast.sh, and ExportOptions-DeveloperID.plist.
- apple-release.yml: on tag v*.*.*, build/notarize the DMG, publish the GitHub
  Release with appcast, and push the Homebrew cask to sudosylabs/homebrew-vnidrop.
  apple.yml gains a PR compile-check of the direct target.
- CFBundleVersion is stamped at build time as a UTC YYMMDD.HHMM timestamp for both
  channels, replacing the hand-maintained build number.
- Docs (RELEASE-MACOS.md, README), cask template + tap README, localized
  updates_check string, Makefile targets, gitignore for dist/ artifacts.
This commit is contained in:
2026-07-27 14:31:36 +02:00
parent 8de190a36e
commit cc194f6a7b
17 changed files with 950 additions and 9 deletions

View File

@@ -4629,6 +4629,23 @@
"ru": "Поделиться"
}
},
"updates_check": {
"context": "macOS app menu item that checks for a new version via Sparkle. Direct-download (.dmg) build only; never shown in the App Store build.",
"targets": [
"apple"
],
"translations": {
"en": "Check for Updates…",
"fr": "Rechercher les mises à jour…",
"es": "Buscar actualizaciones…",
"it": "Cerca aggiornamenti…",
"de": "Nach Updates suchen…",
"pt": "Procurar atualizações…",
"pl": "Sprawdź aktualizacje…",
"nl": "Zoeken naar updates…",
"ru": "Проверить наличие обновлений…"
}
},
"value_unavailable": {
"context": "Placeholder shown when a device-info or metadata value can't be read.",
"translations": {