Die .ipa war nicht installierbar, plus QR-Scanner (2026.9.4.8)
Der Erweiterung fehlte CFBundleVersion - eine Pflichtangabe, ohne die iOS
die Installation der ganzen App verweigert ("kann nicht installiert werden").
Verursacht von der Versionsangleichung vom Vortag: das Skript reichte den
Platzhalter $(CURRENT_PROJECT_VERSION) statt einer Zahl weiter, und das per
Skript angelegte Ziel der Erweiterung kennt diese Build-Einstellung nicht.
An den entpackten .ipa nachgemessen, 2026.9.3.3 gegen 2026.9.4.5.
ios-signieren.sh reicht nur noch echte Zahlen weiter, das Gegenlesen der
fertigen .ipa bricht ab statt zu warnen, und abgelegt wird erst danach -
eine Datei, die die Pruefung nicht besteht, darf nicht in auslieferung/
landen.
Dazu:
- Kopfmarke statt Firmierung des Betreibers in der Tankstellen-Zeile
- dritter Suchbegriff: der Name ohne fuehrende Marke. Gemessen: Nominatim
findet "Shell, Pascalstr. 8, Ingolstadt" nicht, "Pascalstr. 8, Ingolstadt"
schon - daran blieb die Belegkarte der realen Instanz leer
- der Tankstellen-Verweis zeigt die Tankstelle, statt eine Route zu rechnen
- Cache-Brecher auf .ipa, Symbolen und manifest.plist
- QR-Scanner fuer den Zugangs-Token bei der Ersteinrichtung (jsQR statt
GoogleMLKit, damit der Xcode-Lauf kein pod install riskiert)
214/214 Tests, Panel als Modul geparst, live gegen audi_ha_test geprueft.
This commit is contained in:
@@ -2,8 +2,12 @@
|
||||
|
||||
**Last updated: 2026-09-04** (Tankstelle zweizeilig und antippbar, die Belegkarte sagt bei
|
||||
fehlender Position die Wahrheit statt einen toten Knopf zu zeigen, der Regler bekommt einen
|
||||
Speichern-Knopf, und die Share-Erweiterung trug eine andere Versionsnummer als die App - `2026.9.4.5`,
|
||||
Abschnitt CC. Davor: Geraetezeit statt Ankunftszeit - die Wurzel hinter der 3-km-Fahrt:
|
||||
Speichern-Knopf, und die Share-Erweiterung trug eine andere Versionsnummer als die App;
|
||||
dazu die Kopfmarke statt der Firmierung des Betreibers und ein
|
||||
Cache-Brecher auf der .ipa-Adresse; die .ipa liess sich zuletzt nicht mehr
|
||||
installieren - der Erweiterung fehlte die CFBundleVersion; dazu der QR-Scanner
|
||||
fuer den Zugangs-Token, `2026.9.4.8`,
|
||||
Abschnitte CC bis CE. Davor: Geraetezeit statt Ankunftszeit - die Wurzel hinter der 3-km-Fahrt:
|
||||
das Fahrtfenster stand in Geraetezeit, der Verlauf war nach Ankunftszeit sortiert. Dazu die neun
|
||||
Paritaetsbefunde und die verunreinigte Batteriehistorie, `2026.9.4.1`, Abschnitt CB. Davor: Der Regler stellt den Schlaf-Timeout des Dongles, flespi lesend und
|
||||
schreibend, die eigene Warteschlange wieder entfallen, `2026.9.3.10`, Abschnitt BZ. Davor: Zugaenge: die Dienste-Token aus App und Panel bedienbar, der Wert kommt nie
|
||||
@@ -475,7 +479,8 @@ wraps the web app for iPhone; a PWA home-screen install is the accepted intermed
|
||||
- [x] Authenticated smoke tests of the data layer (reads, service calls, queue round-trip)
|
||||
against `audi_ha_test` with a real token
|
||||
- [x] Offline UX per design brief (offline marker, visible pending queue)
|
||||
- [ ] **QR-Code-Scanner fürs Token-Onboarding (angefragt 2026-08-28, noch nicht geplant/gebaut)** —
|
||||
- [x] **QR-Code-Scanner fürs Token-Onboarding — gebaut am 2026-09-04, siehe Abschnitt CE.**
|
||||
Historie der Anforderung:
|
||||
2026-08-11 bewusst weggelassen ("nur wenn es einfach bleibt"), der Owner will das jetzt doch als
|
||||
Alternative zum manuellen Einfügen.
|
||||
|
||||
@@ -9629,3 +9634,213 @@ selbst stehen.
|
||||
zur Testinstanz. Das ist der Weg, die App live zu pruefen, ohne an CORS zu
|
||||
scheitern: `cors_allowed_origins` in der `configuration.yaml` blieb wirkungslos
|
||||
(Preflight weiterhin 403), der eingetragene Block ist deshalb wieder entfernt.
|
||||
|
||||
### Nachtrag (2026.9.4.6): die Kopfmarke, nicht die Firmierung
|
||||
|
||||
Praezisierung des Eigentuemers zur Zeile oben: dort gehoert die **Marke** hin
|
||||
("Shell, Aral, OMV ..."), nicht der Betreiber. `A. Zrenner GmbH` ist die
|
||||
Firmierung dessen, der die Tankstelle betreibt - nach aussen sichtbar ist die
|
||||
Kopfmarke, und nur die sagt dem Leser etwas.
|
||||
|
||||
Neu `markeErkennen()` in beiden Codebasen: sucht die Kopfmarke im gespeicherten
|
||||
`station_name` gegen eine Liste, die **wortgleich** mit `_MARKEN` im
|
||||
`shell_beleg_parser.py` ist. Der Parser erkennt die Marke beim Einlesen eines
|
||||
Belegs, diese Liste erkennt sie nachtraeglich in dem, was gespeichert ist -
|
||||
laufen die beiden auseinander, zeigt die Oberflaeche eine andere Marke als der
|
||||
Beleg. Gesucht wird mit Wortgrenzen, damit "Star" nicht in "Starnberg" trifft.
|
||||
|
||||
Damit steht oben `<Marke>, <Strasse>` und unten `<PLZ> <Ort>`; ohne erkennbare
|
||||
Marke nur die Strasse - der Betreibername tritt **nicht** an ihre Stelle. Traegt
|
||||
der Beleg gar keine Anschrift, bleibt der gespeicherte Name unveraendert stehen
|
||||
("Shell, SÖLDEN"), sonst hiesse eine bekannte Tankstelle ploetzlich "unbekannt".
|
||||
|
||||
Gegen die 16 echten Datensaetze der Testinstanz nachgerechnet, mit den Funktionen
|
||||
des Panels selbst (aus dem Buendel geschnitten und in Node ausgefuehrt, nicht
|
||||
nachgebaut): drei Betreibernamen fallen korrekt weg (`Hermann Mogler
|
||||
Mineraloelg. GmbH`, `TC Sengül GmbH`, `A. Zrenner GmbH`), `Shell, SÖLDEN` und
|
||||
`Testtankstelle` bleiben stehen, leer ergibt "unbekannt". Die App deckt dasselbe
|
||||
mit 24 Faellen in `src/daten/tankstelle.test.ts` ab.
|
||||
|
||||
### Nachtrag (2026.9.4.6): die .ipa-Adresse bekommt einen Cache-Brecher
|
||||
|
||||
Gemeldet: die alte App geloescht, neu installiert - "Wolke mit Pfeil" und "kann
|
||||
nicht installiert werden, versuche es spaeter erneut".
|
||||
|
||||
**Das ausgelieferte Artefakt ist in Ordnung**, geprueft statt vermutet: die von
|
||||
Gitea gelieferte `App.ipa` ist ein gueltiges Zip, App **und** Erweiterung tragen
|
||||
`2026.9.4.5` (die Versionsangleichung aus Abschnitt CC ist also drin), die
|
||||
`manifest.plist` passt dazu (`app.datametric360`, `bundle-version 2026.9.4.5`),
|
||||
beide eingebetteten Profile fuehren beide Geraete-UDIDs und laufen bis
|
||||
2027-08-29, beide Symbol-Adressen antworten mit HTTP 200 als `image/png`.
|
||||
|
||||
Was fehlte, ist die Vorsorge, die dieses Projekt an jeder anderen ausgelieferten
|
||||
Datei laengst trifft: `ios-luftweg.sh` schrieb `<string>$BASIS/App.ipa</string>`
|
||||
**ohne** Versionsanhang. Die Adresse ist damit ueber jeden Bau hinweg
|
||||
zeichengleich, und der Installations-Dienst von iOS haelt eine einmal geholte
|
||||
Datei fuer schon bekannt - eine bekannte Ursache genau dieser beiden Symptome.
|
||||
Jetzt tragen `.ipa`, beide Symbole und die `manifest.plist` selbst ein
|
||||
`?v=<Version>`; die bereits ausgelieferten Dateien unter `auslieferung/` sind
|
||||
von Hand nachgezogen (das Skript laeuft nur auf dem Mac, es braucht
|
||||
`PlistBuddy`).
|
||||
|
||||
**Ebenfalls geklaert, weil es zusammen gemeldet wurde:** das veraenderte
|
||||
App-Symbol kommt nicht von hier, sondern vom Commit `d819f2e` ("iOS-App auf
|
||||
2026.9.4.5"), der vom Mac gepusht wurde - er hat `auslieferung/` erneuert.
|
||||
|
||||
**Was bleibt, wenn der Cache-Brecher nicht reicht:** das stecken gebliebene
|
||||
Platzhalter-Symbol auf dem Startbildschirm loeschen (langes Tippen, "App
|
||||
entfernen"), Geraet neu starten, dann den `itms-services://`-Link erneut in
|
||||
Safari oeffnen. Und der `?v=` wirkt erst mit dem naechsten Aufruf des Links,
|
||||
nicht rueckwirkend auf einen laufenden Versuch.
|
||||
|
||||
### Was in dieser Runde NICHT live geprueft werden konnte
|
||||
|
||||
Die Testinstanz zeigte in dieser Sitzung die Anmeldemaske, und ein Passwort
|
||||
einzugeben ist in diesem Projekt ausgeschlossen - auch bei der Wegwerf-Instanz.
|
||||
Beide Oberflaechen sind deshalb ueber Modul-Parse, `tsc --noEmit`, 206/206 Tests
|
||||
und die oben beschriebene Rechnung gegen die echten Datensaetze belegt, **nicht**
|
||||
ueber einen Screenshot. Die Messungen zur Zeilenhoehe (82px) und zur
|
||||
SmartDeal-Zeile (26,4px) stammen aus dem Teil der Sitzung davor und sind von der
|
||||
Markenaenderung nicht beruehrt: sie macht die erste Zeile kuerzer, nicht laenger.
|
||||
|
||||
## CD. Die .ipa liess sich nicht mehr installieren - eine fehlende Pflichtangabe (2026.9.4.7)
|
||||
|
||||
Gemeldet: „bis zum letzten Xcode-Update hatte ich das richtige Logo, jetzt steht
|
||||
ein anderes auf dem iPhone und die App ist nicht mehr installierbar."
|
||||
|
||||
**Beides ist ein Befund, nicht zwei.** Die letzte funktionierende `.ipa`
|
||||
(`2026.9.3.3`) aus der Historie geholt und gegen die aktuelle gestellt - beide
|
||||
entpackt, die Info.plists mit `plistlib` gelesen (im Testcontainer, hier gibt es
|
||||
kein `PlistBuddy`):
|
||||
|
||||
| | `2026.9.3.3` (lief) | `2026.9.4.5` (lehnt ab) |
|
||||
|---|---|---|
|
||||
| App `CFBundleVersion` | `1` | `1` |
|
||||
| Erweiterung `CFBundleVersion` | `1` | **fehlt ganz** |
|
||||
|
||||
Alles andere ist in beiden gleich und in Ordnung: Bundle-IDs, Profile mit beiden
|
||||
Geraete-UDIDs bis 2027-08-29, `get-task-allow: false`, App-Gruppe auf beiden
|
||||
Zielen, `MinimumOSVersion`.
|
||||
|
||||
`CFBundleVersion` ist eine Pflichtangabe. Fehlt sie in **einem** der beiden
|
||||
Buendel, verweigert iOS die Installation der **ganzen** App - mit genau der
|
||||
nichtssagenden Meldung "kann nicht installiert werden, versuche es spaeter
|
||||
erneut".
|
||||
|
||||
**Verursacht hat es die Versionsangleichung aus Abschnitt CC**, also der Versuch,
|
||||
einen anderen Fehler zu beheben. Der Schritt liest die Build-Nummer aus der
|
||||
Info.plist der App - dort steht aber keine Zahl, sondern der Platzhalter einer
|
||||
Build-Einstellung (`$(CURRENT_PROJECT_VERSION)`, aus dem Capacitor-Geruest).
|
||||
Fuers App-Ziel loest Xcode ihn zu `1` auf; das per Skript angelegte Ziel der
|
||||
Erweiterung kennt die Einstellung nicht, dort wurde daraus **leer**, und ein
|
||||
leerer Wert faellt beim Schreiben der Plist ganz heraus.
|
||||
|
||||
Zwei Aenderungen in `ios-signieren.sh`: die Build-Nummer wird nur noch
|
||||
weitergereicht, wenn sie wirklich eine Zahl ist (sonst `1`), und das
|
||||
Gegenlesen der fertigen `.ipa` **bricht ab**, wenn einem der beiden Buendel eine
|
||||
brauchbare `CFBundleVersion` fehlt. Die bisherige Pruefung verglich nur
|
||||
`CFBundleShortVersionString` - genau daran ist es vorbeigelaufen.
|
||||
|
||||
**Das „andere Logo" ist der Platzhalter der haengenden Installation.** iOS zeigt
|
||||
waehrend des Ladens das `display-image` aus der `manifest.plist` auf dem
|
||||
Startbildschirm, und das ist `companion-app/public/symbol-192.png` vom 13.08. -
|
||||
die alte "DM"-Kachel, nicht das App-Symbol vom 31.08. (DataMetric / Auto / 360).
|
||||
Weil die Installation nie fertig wird, bleibt der Platzhalter stehen. Beide
|
||||
Dateien nebeneinander angesehen, sie sind nachweislich verschieden.
|
||||
**Offen und bewusst nicht angefasst:** die beiden Symbole anzugleichen, damit
|
||||
schon der Platzhalter richtig aussieht - dafuer muessten aus
|
||||
`native/logo/AppIcon-hell.svg` neue 192er- und 512er-PNG gerastert werden.
|
||||
|
||||
### Zusaetzlich: die Adressen der Auslieferung tragen jetzt die Version
|
||||
|
||||
`ios-luftweg.sh` schrieb `<string>$BASIS/App.ipa</string>` ohne Anhaengsel. Die
|
||||
Adresse ist damit ueber jeden Bau hinweg zeichengleich, und der
|
||||
Installations-Dienst von iOS haelt eine einmal geholte Datei fuer schon bekannt.
|
||||
Jetzt tragen `.ipa`, beide Symbole und die `manifest.plist` selbst ein
|
||||
`?v=<Version>`; die bereits ausgelieferten Dateien unter `auslieferung/` sind von
|
||||
Hand nachgezogen, weil das Skript nur auf dem Mac laeuft.
|
||||
|
||||
### Der dritte Suchbegriff: der Name ohne die fuehrende Marke
|
||||
|
||||
Gemeldet: dieselbe Tankstelle loest in Docker und auf der realen Instanz
|
||||
verschieden auf, und auf der realen Instanz bleibt die Belegkarte leer.
|
||||
|
||||
Die Ursache steht in den Daten, nicht im Code: seit dem 16.08.2026 setzt der
|
||||
Belegparser den Stationsnamen als „Marke, Strasse, Ort" zusammen - **ohne
|
||||
Postleitzahl**. Am 04.09.2026 gegen Nominatim gemessen:
|
||||
|
||||
| Suchtext | Antwort |
|
||||
|---|---|
|
||||
| `Shell, Pascalstr. 8, Ingolstadt` | leer |
|
||||
| `Pascalstr. 8, Ingolstadt` | 48.7869/11.3977 |
|
||||
| `Shell, Pascalstr. 8, 85057 Ingolstadt` | 48.7869/11.3977 |
|
||||
|
||||
Die Marke am Anfang kippt die Suche, sobald die Postleitzahl fehlt.
|
||||
`tankstelleKandidaten()` haengt deshalb einen dritten Versuch an: den Namen ohne
|
||||
die fuehrende Marke. Er laeuft nur, wenn die ersten beiden nichts gefunden
|
||||
haben.
|
||||
|
||||
**Live nachgewiesen** an genau diesem Beleg in der Testinstanz (deren Datensatz
|
||||
vom 29.07.2026 dieselbe Form hat): im Zwischenspeicher steht
|
||||
`"Shell, Pascalstr. 8, Ingolstadt" => null` neben
|
||||
`"Pascalstr. 8, Ingolstadt" => {lat: 48.7869101, lon: 11.39767}`, und die Karte
|
||||
zeigt eine Nadel.
|
||||
|
||||
### Der Verweis zeigt die Tankstelle, statt eine Route zu rechnen
|
||||
|
||||
Vorgabe des Eigentuemers. `kartendienstUrl()` hat dafuer einen Modus bekommen:
|
||||
`"route"` bleibt die Vorgabe (Standort-Blatt, Autohaus), der Tankstellen-Verweis
|
||||
im Einzelbeleg nimmt `"zeigen"` - Apple `?q=` bzw. `?ll=&q=`, Google
|
||||
`/maps/search/`. Live geprueft: der Verweis lautet jetzt
|
||||
`google.com/maps/search/?api=1&query=...` statt `/maps/dir/`.
|
||||
|
||||
Verifiziert: Panel als Modul geparst, `tsc --noEmit` sauber, **210/210** Tests
|
||||
(vier neue: der markenlose Kandidat, der Fall „Marke steht nicht vorn", und die
|
||||
beiden Kartendienste im Modus „zeigen"), `audi_ha_test` auf `2026.9.4.7` sauber
|
||||
gestartet, und beide Belege live im Panel nachgesehen (zweizeilig „Nuernberger
|
||||
Str.74" / „91522 Ansbach" ohne den Betreibernamen, Nadel auf der Karte).
|
||||
|
||||
## CE. QR-Scanner fuer den Zugangs-Token (2026.9.4.8)
|
||||
|
||||
Vorgabe des Eigentuemers: ein Knopf unter „Zugangs-Token", und **nur** bei der
|
||||
Ersteinrichtung - danach gibt es nichts mehr abzutippen. Damit ist der seit dem
|
||||
28.08.2026 offene Punkt aus Abschnitt A erledigt.
|
||||
|
||||
**Kein natives Scanner-Plugin, und das ist die eigentliche Entscheidung.**
|
||||
`@capacitor-mlkit/barcode-scanning` (8.1.1, passt zu Capacitor 8) waere der
|
||||
bequemere Weg, zieht aber GoogleMLKit ueber CocoaPods nach - mehrere Dutzend
|
||||
Megabyte und ein `pod install`, das auf dem Mac gelingen muss. Genau der
|
||||
Xcode-Lauf, der die App nach Abschnitt CD ueberhaupt erst wieder installierbar
|
||||
macht, darf daran nicht scheitern. Gewaehlt: **jsQR** (1.4.0, 30 KB, MIT), rein
|
||||
in JavaScript, dazu `getUserMedia` in der WebView. WKWebView liefert die Kamera
|
||||
seit iOS 14.3 aus, und die App laeuft unter `capacitor://localhost`, also in
|
||||
einem sicheren Kontext.
|
||||
|
||||
Nativ bleibt genau ein Punkt: **`NSCameraUsageDescription`** in der Info.plist,
|
||||
gesetzt von `ios-signieren.sh` wie schon der Standort- und die beiden
|
||||
Kalender-Schluessel (`ios/` ist gitignored, ein in Xcode geklickter Eintrag
|
||||
waere beim naechsten `cap add ios` wieder weg). Ohne den Schluessel beendet iOS
|
||||
die App wortlos in dem Moment, in dem sie die Kamera anfordert.
|
||||
|
||||
**Was der Code enthaelt, war die zweite offene Frage** (sie stand seit dem
|
||||
01.09.2026 in Abschnitt A): Home Assistants eigener QR traegt **nur den Token**,
|
||||
nicht die Adresse der Instanz. `qrFundDeuten()` entscheidet deshalb: eine
|
||||
http-Adresse wandert in das Adressfeld, ein langer zusammenhaengender Text in
|
||||
das Tokenfeld, alles andere wird **nicht** uebernommen (ein WLAN-Code oder eine
|
||||
Visitenkarte sollen kein Feld fuellen). Vier Faelle in
|
||||
`src/screens/QrScanner.test.ts`.
|
||||
|
||||
Der Knopf erscheint nur, wenn das Geraet der App ueberhaupt eine Kamera
|
||||
durchreicht - am Rechner waere er ein Knopf, der zwangslaeufig in eine
|
||||
Fehlermeldung laeuft; dieselbe Ueberlegung wie beim Zwischenablage-Knopf des
|
||||
Beleg-Dialogs (Abschnitt C, 2026-08-17). „Verbinden" ist jetzt `variant`
|
||||
`primary`, der Scanner-Knopf bleibt die zweite Rolle - die Rangfolge, die Apples
|
||||
Richtlinien fuer genau diese Paarung vorsehen.
|
||||
|
||||
Verifiziert: `tsc --noEmit` sauber, **214/214** Tests, `vite build` sauber,
|
||||
`audi_ha_test` auf `2026.9.4.8` sauber gestartet, und die Ersteinrichtung live
|
||||
unter `http://localhost:18123/local/dmapp/index.html` angesehen: der Knopf steht
|
||||
unter „Zugangs-Token", das Blatt oeffnet mit Videofeld und Zielrahmen, und ohne
|
||||
Kamerafreigabe steht dort die erklaerende Meldung statt einer leeren Flaeche.
|
||||
**Nicht geprueft, weil es in dieser Umgebung nicht geht:** ein echter Scan - die
|
||||
Browser-Vorschau gibt keine Kamera heraus. Das zeigt sich erst auf dem Geraet.
|
||||
|
||||
Reference in New Issue
Block a user