e250b6c5e1
Erster Lauf des Einrichtungsskripts auf einem Mac. Xcode brach ab mit "error: Unexpected duplicate tasks", zweimal ValidateEmbeddedBinary auf dieselbe DataMetric360Share.appex. Ursache: addTarget() legt fuer den Typ app_extension selbst schon eine Copy-Phase nach PlugIns am ersten Ziel an. Das Skript fuegte danach eine zweite mit demselben Ziel und derselben Datei hinzu. Die explizite Phase entfaellt jetzt; belegt am erzeugten Projekt: genau eine Phase mit dstSubfolderSpec 13 statt zwei. Alles Uebrige des Skripts lief auf Anhieb: Ziel, Entitlements, URL-Schema, Idempotenz.
128 lines
5.9 KiB
Markdown
128 lines
5.9 KiB
Markdown
# Tankbeleg aus dem Teilen-Blatt
|
|
|
|
Ein PDF aus Mail (oder einer anderen App) über **Teilen → DataMetric360** direkt
|
|
als Tankbeleg übernehmen.
|
|
|
|
## Wie es zusammenhängt
|
|
|
|
```
|
|
Mail ──Teilen──► DataMetric360Share (eigener Prozess)
|
|
│
|
|
│ PDF → Base64 → UserDefaults der App-Gruppe
|
|
│ group.app.datametric360
|
|
▼
|
|
datametric360://beleg (öffnet die App)
|
|
│
|
|
▼
|
|
App.tsx ──holt ab──► Tanken-Seite ──► belegLesen()
|
|
```
|
|
|
|
Eine Erweiterung ist ein eigener Prozess mit eigenem Dateibereich; der einzige
|
|
gemeinsame Boden mit der App ist die **App-Gruppe**. Der Beleg reist deshalb
|
|
Base64-kodiert durch die geteilten `UserDefaults` — die liest
|
|
`@capacitor/preferences` ohnehin schon, sobald man ihm die Gruppe nennt. Eine
|
|
Datei im Gruppen-Container wäre der sauberere Ort, bräuchte auf der App-Seite
|
|
aber eigenen nativen Code, also ein zusätzliches Plugin für einen Weg, den es
|
|
sonst nicht gäbe.
|
|
|
|
Der Preis ist eine Größengrenze von 4 MB (`grenzeBytes` im
|
|
`ShareViewController`). Ein Tankbeleg liegt bei einigen Dutzend Kilobyte; ein
|
|
gescanntes Mehrseiten-PDF kann darüber liegen — dann sagt die Erweiterung das,
|
|
und der Weg über **Beleg hochladen → Datei auswählen** in der App bleibt.
|
|
|
|
## Wo was liegt
|
|
|
|
| Datei | Rolle |
|
|
|---|---|
|
|
| `native/teilen/ShareViewController.swift` | nimmt das PDF entgegen, legt es ab, öffnet die App |
|
|
| `native/teilen/Info.plist` | wann DataMetric360 im Teilen-Blatt erscheint (genau ein PDF) |
|
|
| `native/teilen/DataMetric360Share.entitlements` | App-Gruppe für die Erweiterung |
|
|
| `native/App.entitlements` | dieselbe App-Gruppe für die App |
|
|
| `scripts/ios-teilen-einrichten.mjs` | hängt das alles ins erzeugte Xcode-Projekt |
|
|
| `src/daten/geteilterBeleg.ts` | holt den Beleg ab, räumt ihn weg |
|
|
| `src/App.tsx` | prüft beim Start und bei jeder Rückkehr, springt auf Tanken |
|
|
| `src/screens/Tanken.tsx` | nimmt ihn auf und lädt ihn hoch |
|
|
|
|
**`companion-app/ios/` ist gitignored** und wird von `npx cap add ios` neu
|
|
gebaut. Alles Native muss deshalb unter `native/` liegen und bei jedem Bau
|
|
eingespielt werden — dieselbe Regel, die schon die Team-Kennung und den
|
|
Standort-Schlüssel in `ios-signieren.sh` getrieben hat.
|
|
|
|
## Einmalig im Apple-Entwicklerportal
|
|
|
|
Ohne diese drei Schritte schlägt das Signieren fehl (die App-Gruppe muss
|
|
existieren, bevor ein Profil sie enthalten kann):
|
|
|
|
1. **Identifiers → App Groups**: `group.app.datametric360` anlegen.
|
|
2. **Identifiers → App IDs**: `app.datametric360.teilen` anlegen, Capability
|
|
*App Groups* aktivieren, die Gruppe zuordnen.
|
|
3. Bei der bestehenden App-ID `app.datametric360` ebenfalls *App Groups*
|
|
aktivieren und dieselbe Gruppe zuordnen.
|
|
|
|
Danach in Xcode einmal die Profile neu ziehen lassen — oder schlicht
|
|
`ios-signieren.sh` laufen lassen, das macht `-allowProvisioningUpdates`
|
|
selbst. **Merkposten aus Abschnitt AI:** ein zwischengespeichertes altes
|
|
Profil wird stillschweigend weiterverwendet. Ändert sich etwas an den
|
|
Berechtigungen, das passende `.mobileprovision` unter
|
|
`~/Library/Developer/Xcode/UserData/Provisioning Profiles` löschen und neu
|
|
exportieren.
|
|
|
|
## Bauen
|
|
|
|
```bash
|
|
bash scripts/ios-signieren.sh
|
|
```
|
|
|
|
Der Schritt „Share-Erweiterung einrichten" läuft dort automatisch, vor dem
|
|
Archivieren.
|
|
|
|
## Wenn das Skript abbricht
|
|
|
|
`ios-teilen-einrichten.mjs` bearbeitet die `project.pbxproj` über das
|
|
npm-Paket `xcode`. **Erstmals auf einem Mac gelaufen am 2026-09-02**; dabei kam
|
|
genau ein Fehler heraus, seither behoben: die Erweiterung wurde **zweimal**
|
|
eingebettet, weil `addTarget()` für den Typ `app_extension` von sich aus schon
|
|
eine Copy-Phase nach `PlugIns` anlegt und das Skript eine zweite hinzufügte.
|
|
Xcode quittierte das mit `error: Unexpected duplicate tasks`. Das Anlegen des
|
|
Ziels selbst, die Entitlements, das URL-Schema und die Idempotenz funktionierten
|
|
auf Anhieb.
|
|
|
|
Bricht es ab, ist nichts halb eingerichtet (es bricht vor dem Schreiben ab), und
|
|
dasselbe lässt sich in Xcode von Hand erledigen:
|
|
|
|
1. **File → New → Target… → Share Extension**, Name `DataMetric360Share`,
|
|
Sprache Swift, „Activate scheme" verneinen.
|
|
2. Die von Xcode erzeugten `ShareViewController.swift`, `Info.plist` und das
|
|
`MainInterface.storyboard` **löschen** und stattdessen die Dateien aus
|
|
`native/teilen/` in das Ziel legen (Storyboard wird nicht gebraucht, die
|
|
Erweiterung hat keine eigene Oberfläche).
|
|
3. Bundle-ID des Ziels auf `app.datametric360.teilen` setzen.
|
|
4. Beide Ziele → **Signing & Capabilities → + Capability → App Groups**,
|
|
`group.app.datametric360` anhaken.
|
|
5. Ziel `DataMetric360Share` → Build Settings → *Code Signing Entitlements* auf
|
|
`DataMetric360Share/DataMetric360Share.entitlements`; Ziel `App` auf
|
|
`App/App.entitlements`.
|
|
6. Ziel `App` → Build Phases → **Embed App Extensions** muss
|
|
`DataMetric360Share.appex` enthalten.
|
|
7. `ios/App/App/Info.plist`: URL-Schema `datametric360` unter
|
|
`CFBundleURLTypes` eintragen.
|
|
|
|
Schritt 7 ist der leiseste: fehlt er, wird der Beleg abgelegt, die App aber
|
|
nicht geöffnet — er taucht dann erst auf, wenn man die App das nächste Mal von
|
|
Hand startet.
|
|
|
|
## Prüfen, ob es wirkt
|
|
|
|
1. In Mail ein PDF antippen → **Teilen** → DataMetric360 muss in der Liste
|
|
stehen (nur bei genau einem PDF, sonst absichtlich nicht).
|
|
2. Antippen → die App kommt nach vorn, springt auf **Tanken**, das Formular ist
|
|
offen und liest den Beleg („Beleg wird gelesen …").
|
|
3. Danach ist der Eintrag weg: dieselbe Datei ein zweites Mal zu teilen muss
|
|
wieder funktionieren, ein bloßes Wechseln in die App darf den Beleg **nicht**
|
|
erneut verarbeiten.
|
|
|
|
## Was hier nicht steht
|
|
|
|
Android. Der Ablauf ist dort ein anderer (`intent-filter` statt App-Gruppe),
|
|
und die Android-Hülle dieses Projekts ist ohnehin nicht in Gebrauch.
|