ios-shell — Capacitor-Hülle für Silverscale
Native iOS-App, die https://silverscale.dennisfisch.de live in einer WKWebView
lädt (Remote-Modus). Zweck: dauerhafte Kamera-Permission für den Barcode-Scan
(Spec: docs/superpowers/specs/2026-06-07-capacitor-sidestore-mvp-design.md).
App-Updates kommen weiter per npm run build auf dem VPS — die IPA muss
praktisch nie neu gebaut werden.
Phase 0 „Jaqueline-Gate" (07.06.2026, Frontend-Audit)
Dieser Stand bündelt alles IPA-Pflichtige in EINEN Rebuild:
- Gebrandetes Icon + Splash (aus
frontend/public/icon.svggeneriert; vorher Default-Capacitor-Logo, Audit F1). - Portrait-Lock in
Info.plist(Landscape war ungetestet, Audit F3). - Swipe-Back-Geste via
allowsBackForwardNavigationGestures(AppDelegate, Audit F7). ⚠️ Auf dem Gerät testen: Wischt man auf der ersten App-Seite zurück, könnte die Geräte-Code-Login-Seite aus der WebView-History auftauchen — falls ja, melden, wird serverseitig gelöst. - Plugins vorinstalliert (Nutzung kommt per Frontend-Deploy, ohne neuen IPA-Build): Browser (externe Links als Safari-Sheet, Audit F16), Haptics, StatusBar, SplashScreen, App.
- Dunkler WebView-Hintergrund (
backgroundColorin capacitor.config.json): kein weißer Blitz mehr zwischen Splash und geladener App. - Offline-Kaltstart-Fallback (Phase 1, fährt im selben Rebuild mit):
www/offline.html+server.errorPath— statt weißer Wand erscheint eine gebrandete „Keine Verbindung"-Seite mit Retry (auto beionline).
IPA v2 (Gerätetest-Feedback 07.06.)
Zweiter Rebuild, behebt die Geste-Probleme aus dem ersten Gerätetest:
- Native Zurück-Geste wieder AUS (AppDelegate): WKWebView arbeitete mit veralteten Snapshots — Bounce/Flackern beim Wischen (#1) und ein Race mit dem Sheet-Dirty-Check, das die App sekundenlang einfror (#9).
- UA jetzt
SilverscaleApp/2: daran erkennt das Frontend die neue Hülle und aktiviert seinen eigenen JS-Edge-Swipe (gleiche Geste, sauberer popstate-Pfad). Mit alter IPA (v1) bleibt alles beim native Verhalten — nichts doppelt sich. - @capacitor/app-launcher: Garmin-Links öffnen die Garmin-Connect-App (Universal Link), falls installiert — sonst Browser (#14).
- Offline-Seite: Fisch schwimmt sichtbarer, Retry-Button mit Tap-Feedback (#10).
Build wie gehabt: npm i && npx cap sync ios → xcodebuild → IPA → SideStore
drüberinstallieren (Session bleibt erhalten).
IPA v3 (Welle 5): Nativer VisionKit-Scanner
App/NativeScanner.swift (DataScannerViewController, EAN-8/13/UPC-E,
Abbrechen-Button, Erfolgs-Haptik) — registriert per Code in
App/MyViewController.swift (CAPBridgeViewController-Subclass,
Main.storyboard zeigt darauf) über registerPluginInstance —
registerPluginType ist bei aktivem autoRegisterPlugins (Default) ein
stilles No-Op! ⚠️ NICHT über packageClassList in
capacitor.config.json versuchen: cap sync ÜBERSCHREIBT die Liste bei
jedem Lauf mit den npm-Plugins — lokale Plugin-Klassen fliegen raus
(so geschehen beim ersten v3-Build, „Scanner: web"). Das Frontend erkennt das
Plugin über die Bridge: mit v3-IPA übernimmt der native Scanner ALLE
Scan-Stellen (Essen loggen, Artikel, Bons), ältere IPAs fallen automatisch
auf den Web-Scanner zurück. Build: ./build-ipa.sh (Swift-Fehler landen
im Log — bei Problemen Log an Claude).
Voraussetzungen (Mac)
Xcode + Command-Line-Tools, Node (brew), CocoaPods: brew install cocoapods
(falls noch nicht da).
Erstmaliges Bauen
cd app/ios-shell
npm i
npx cap add ios # erzeugt ios/ – DANACH committen (git add ios/)
In ios/App/App/Info.plist vor dem schließenden </dict> einfügen,
dann erneut committen:
<key>NSCameraUsageDescription</key>
<string>Barcode-Scan für Artikel</string>
Unsignierte IPA bauen (SideStore signiert selbst um)
cd app/ios-shell
./build-ipa.sh
Das Skript macht npm i → cap sync → xcodebuild → IPA packen, zeigt pro
Schritt nur 1–2 Zeilen und schreibt das volle Protokoll (inkl. Versions-
Diagnose) nach logs/build-<zeitstempel>.log — bei Fehlern die letzten
Zeilen direkt im Terminal, das Log-File an Claude geben.
Installation (je iPhone, einmalig — Stand 06/2026, iloader-Weg)
- LocalDevVPN (App Store) auf dem iPhone installieren.
- iloader auf dem Mac installieren: https://github.com/nab138/iloader/releases/latest (darwin-universal.dmg)
- iPhone per Kabel an den Mac, „Vertrauen" + Code bestätigen.
- iloader öffnen → mit der Sideload-Apple-ID anmelden (case-sensitive!) → Gerät wählen → „Install SideStore (Stable)".
- iPhone (iOS 26): Einstellungen → Allgemein → VPN & Geräteverwaltung → Entwickler-App-Profil → „Allow & Restart" + Passcode. Entwicklermodus (Datenschutz & Sicherheit) aktivieren, falls noch nicht an (Neustart).
- LocalDevVPN verbinden → SideStore öffnen → mit derselben Apple-ID anmelden → den „7 DAYS"-Counter antippen (erster manueller Refresh schließt das Setup ab).
Silverscale.ipaper AirDrop aufs iPhone → SideStore „+" → IPA aus „Dateien" wählen → installieren.- App öffnen → Geräte-Code-Seite erscheint → Code aus den PWA-Einstellungen (📱 Geräte-Login) eingeben → fertig. Kamera-Frage kommt EINMAL nativ.
Login-Architektur
WKWebView kann kein WebAuthn/Passkey → GET /api/auth/login erkennt den
User-Agent SilverscaleApp (appendUserAgent in capacitor.config.json) und
zeigt eine Code-Eingabeseite; POST /api/auth/device-login setzt die normale
180-Tage-Session (ADR-40, backend/auth.py).
Refresh-Betrieb (SideStore)
Freie Apple-ID = Signatur läuft nach 7 Tagen ab. SideStore refresht selbst (LocalDevVPN an, Hintergrundaktualisierung an, App gelegentlich öffnen). Verpasster Refresh: App startet nicht mehr — kein Datenverlust, einmal in SideStore manuell refreshen. Limits: max. 3 aktive Apps inkl. SideStore.