Files
audi-app/companion-app/docs/SHARE_EXTENSION.md
T
Paul Nothaft e250b6c5e1 Share-Erweiterung wurde doppelt eingebettet - eine Copy-Phase zu viel
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.
2026-09-02 14:25:28 +02:00

5.9 KiB

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 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.