diff --git a/.gitignore b/.gitignore
index 13fc2fc..d05c3cd 100644
--- a/.gitignore
+++ b/.gitignore
@@ -33,6 +33,9 @@ migrate_working_dir/
/build/
/coverage/
+# Firebase CLI deploy cache
+.firebase/
+
# Symbolication related
app.*.symbols
diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
index db77bb4..946d961 100644
Binary files a/android/app/src/main/res/mipmap-hdpi/ic_launcher.png and b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
index 17987b7..0cc71cd 100644
Binary files a/android/app/src/main/res/mipmap-mdpi/ic_launcher.png and b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
index 09d4391..95c8579 100644
Binary files a/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png and b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
index d5f1c8d..e2afc39 100644
Binary files a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png and b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
index 4d6372e..da9b2e6 100644
Binary files a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png and b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/assets/icon/icon.png b/assets/icon/icon.png
new file mode 100644
index 0000000..c2dc0b8
Binary files /dev/null and b/assets/icon/icon.png differ
diff --git a/docs/firebase-einrichtung.md b/docs/firebase-einrichtung.md
index fa62de1..8f6dcac 100644
--- a/docs/firebase-einrichtung.md
+++ b/docs/firebase-einrichtung.md
@@ -196,22 +196,30 @@ Zwei getrennte Schritte, **nacheinander**, nicht gleichzeitig (sonst sperrt man
- **Metriken abwarten:** In der Console unter *App Check → APIs* prüfen, dass für die genutzten Functions „Verified requests" ankommen (kann nach einem frischen Build ein paar Minuten dauern).
2. **Erst wenn Schritt 1 bestätigt ist:** In `functions/src/index.ts` und `functions/src/household.ts` bei den `onCall(...)`-Funktionen (`identifyPlant`, `diagnosePlant`, `analyzeLocation`, `assessPlantFit`, `joinHousehold`, `leaveHousehold`, `removeMember`) die Option `enforceAppCheck: true` ergänzen und neu deployen. Danach lehnen die Functions Aufrufe ohne gültiges App-Check-Token ab.
-Für einen echten Release-Build sollte `main.dart` auf die Produktiv-Provider umgestellt werden (`AndroidProvider.playIntegrity` / `AppleProvider.appAttest` statt der Debug-Provider) — bis dahin reicht der Debug-Provider für eigene Testgeräte.
+**Erledigt (2026-09-08):** `main.dart` schaltet die App-Check-Provider jetzt per `kReleaseMode` um — Release-Builds (TestFlight/Play) nutzen `AndroidPlayIntegrityProvider` / `AppleAppAttestProvider`, Debug-Builds weiter die Debug-Provider mit den hinterlegten Debug-Tokens. Wichtig, weil die Functions App Check **erzwingen**: Ein Release-Build mit Debug-Provider würde auf fremden Geräten bei jedem Function-Aufruf (Pflanze anlegen, Diagnose, Haushalt beitreten) scheitern. Auf dem ersten TestFlight-Build bestätigt.
-## Schritt 10: TestFlight einrichten (iOS)
+## Schritt 10: TestFlight einrichten (iOS) — abgeschlossen 2026-09-08
-Ziel: die App auf eigenen/Familien-Geräten installierbar machen, **ohne** öffentlichen Store-Eintrag oder Apple-Review (interne Tester werden nicht geprüft).
+Ziel: die App auf eigenen/Familien-Geräten installierbar machen, **ohne** öffentlichen Store-Eintrag oder Apple-Review (interne Tester werden nicht geprüft). Erster Build (1.0.0 (1)) am 2026-09-08 hochgeladen, in TestFlight „Bereit zum Testen", auf dem iPhone installiert und nutzbar.
-1. **App Store Connect** (, mit dem aktiven Apple-Developer-Konto) → *Meine Apps* → „+" → **Neue App**:
- - Plattform iOS, Name „LeafItToMe" (falls der Name schon vergeben ist, z. B. „LeafItToMe – Pflanzenpflege" versuchen), Bundle-ID `dev.leafittome.app` auswählen (aus der Liste, die Xcode/das Developer-Portal bereits kennt), SKU frei wählbar (z. B. `leafittome-001`).
-2. **App-Informationen → Datenschutzerklärung-URL:** die gehostete Datenschutzerklärung eintragen (Entwurf liegt in `docs/legal/datenschutz.html`, Hosting-Vorschlag s. u.).
-3. **App-Datenschutz (Privacy-Fragebogen):** Apple fragt nach Datentypen. Antworten passend zu `docs/legal/datenschutz.html`:
- - *Kontaktdaten* → E-Mail-Adresse: ja, verknüpft mit Nutzer, für App-Funktionalität (Konto).
- - *Fotos oder Videos* → ja, verknüpft mit Nutzer, für App-Funktionalität (Pflanzen-/Standort-Erkennung).
- - *Nutzerinhalte* (sonstige, z. B. Pflanzendaten) → ja, verknüpft mit Nutzer, für App-Funktionalität.
- - Kein Tracking, keine Daten zu Werbezwecken, keine Analyse-/Diagnosedaten (kein Analytics/Crashlytics im Projekt).
-4. **Build hochladen:** `flutter build ipa` (Release-Signing über Xcode „Automatically manage signing"), dann per Xcode Organizer oder Transporter-App hochladen.
-5. **TestFlight → Interne Tests:** neue Testgruppe anlegen (z. B. „Haushalt"), Tester per Apple-ID-E-Mail hinzufügen — die genannten Personen müssen als *Nutzer* im App-Store-Connect-Team stehen (bis zu 100 interne Tester, kein Review nötig, Build ist nach ein paar Minuten Verarbeitungszeit verfügbar).
+1. **App Store Connect** (, mit dem aktiven Apple-Developer-Konto) → *Apps* → „+" → **Neue App**:
+ - Plattform iOS, Name „LeafItToMe" (falls vergeben: „LeafItToMe – Pflanzenpflege"), primäre Sprache Deutsch, Bundle-ID `dev.leafittome.app` aus der Liste wählen, SKU frei (z. B. `leafittome-001`), voller Zugriff.
+ - Screenshots, Beschreibung, Preis, Altersfreigabe sind für **interne** TestFlight-Tests nicht nötig — nur die Datenschutz-Angaben unten.
+2. **App-Informationen → Datenschutzrichtlinie-URL:** `https://leaf-it-to-me-app.web.app/datenschutz` (Hosting via Firebase Hosting, s. u.).
+3. **App-Datenschutz (Privacy-Fragebogen):** Apple fragt Datentyp für Datentyp ab. Antworten passend zu `docs/legal/datenschutz.html` — jeweils *erhoben: ja*, *mit Nutzer verknüpft: ja*, *Tracking: nein*, Zweck *App-Funktionalität*:
+ - *Kontaktdaten → E-Mail-Adresse* (Konto).
+ - *Benutzerinhalte → Fotos oder Videos* (Pflanzen-/Standort-Erkennung).
+ - *Benutzerinhalte → Andere Benutzerinhalte* (Pflanzen-/Haushaltsdaten).
+ - *Kennungen → Nutzer-ID* (Apple/Google-Login-Konto-ID).
+ - Alles andere: nicht erhoben. Kein Tracking, keine Werbedaten, keine Analyse-/Diagnosedaten (kein Analytics/Crashlytics im Projekt).
+4. **Distribution-Zertifikat anlegen (einmalig, sonst scheitert der Upload!):** Xcode → *Settings → Accounts* → Apple-ID + Team markieren → **„Manage Certificates…"** → „+" → **„Apple Distribution"**. Ohne dieses Zertifikat gibt es im Schlüsselbund nur „Apple Development", und der Upload wird mit *„Invalid Signature … not signed with a distribution certificate"* (Code 90035) für jede Framework-Datei abgelehnt. Kontrolle: `security find-identity -v -p codesigning` muss eine Zeile „Apple Distribution: …" zeigen.
+5. **Build als Archiv aus Xcode bauen** (nicht `flutter build ipa` über die CLI — die konnte das Distribution-Zertifikat headless nicht ziehen und fiel auf Development-Signing zurück):
+ - `flutter build ios --config-only --release`
+ - `ios/Runner.xcworkspace` in Xcode öffnen → Geräte-Dropdown **„Any iOS Device (arm64)"** → Menü **Product → Archive**.
+ - Der Organizer öffnet sich → **„Distribute App" → App Store Connect → Upload** → Optionen auf Standard.
+ - **Harmlose Meldungen beim Upload:** „Upload Symbols Failed … did not include a dSYM for FirebaseFirestoreInternal / grpc / absl / RecaptchaEnterpriseSDK …". Firebase/gRPC liefern ihre Frameworks vorkompiliert ohne Debug-Symbole; das betrifft nur die Crash-Symbolisierung (ohne Crashlytics irrelevant). Der Build gilt trotzdem als angenommen.
+6. **TestFlight → Interne Tests:** neue Testgruppe (z. B. „Haushalt"), Tester per Apple-ID-E-Mail — die Personen müssen unter *Benutzer und Zugriff* im Team stehen (Rolle „Entwickler"/„Kundenservice" reicht). Bis zu 100 interne Tester, kein Review, Build nach wenigen Minuten Verarbeitung verfügbar.
+7. **Export-Compliance:** taucht dank `ITSAppUsesNonExemptEncryption = false` in `Info.plist` nicht als Nachfrage auf.
## Schritt 11: Play Internal Testing einrichten (Android)
@@ -234,7 +242,29 @@ Ziel: dieselbe „ohne öffentlichen Store-Eintrag"-Stufe für Android.
## Hosting: Datenschutzerklärung öffentlich erreichbar machen
-`docs/legal/datenschutz.html` ist bewusst eine einzelne, eigenständige HTML-Datei ohne Build-Schritt — sie kann 1:1 ausgeliefert werden. Chris nutzt bereits Cloudflare vor einer eigenen Domain, daher läuft das Hosting so:
+`docs/legal/datenschutz.html` ist bewusst eine einzelne, eigenständige HTML-Datei ohne Build-Schritt — sie kann 1:1 ausgeliefert werden.
+
+### Genutzte Lösung: Firebase Hosting (2026-09-08)
+
+Kein Zusatz-Setup, kostenlos (die ~4-KB-Seite bleibt weit im Gratis-Kontingent: 10 GB Speicher + 10 GB Transfer/Monat). In `firebase.json` steht ein `hosting`-Block:
+
+```json
+"hosting": {
+ "public": "docs/legal",
+ "cleanUrls": true,
+ "ignore": ["firebase.json", "**/.*"],
+ "redirects": [{ "source": "/", "destination": "/datenschutz", "type": 302 }]
+}
+```
+
+- `public: "docs/legal"` deployt die Seite direkt aus dem Repo — keine Kopie zum Synchronhalten. (Vorsicht: alles, was künftig in `docs/legal/` landet, wäre damit öffentlich.)
+- Deploy: `firebase deploy --only hosting --project leaf-it-to-me-app`
+- URL für App Store Connect / Play Console: **`https://leaf-it-to-me-app.web.app/datenschutz`** (die nackte Domain leitet per Redirect dorthin).
+- Nach jeder Änderung an `docs/legal/datenschutz.html` erneut `firebase deploy --only hosting`.
+
+### Alternative: eigene Domain über Cloudflare + Hetzner-VPS
+
+Falls die Datenschutzerklärung später unter eigener Domain laufen soll — Chris nutzt bereits Cloudflare vor einer eigenen Domain:
1. **Cloudflare-DNS:** Subdomain anlegen, z. B. `datenschutz..tld` → A-Record auf die IP des Hetzner-VPS. Proxy (orange Wolke) aktiviert lassen.
2. **SSL/TLS-Modus auf „Full (strict)"** stellen (Cloudflare → SSL/TLS → Übersicht) — **nicht** „Flexible", sonst ist die Strecke Cloudflare↔Server unverschlüsselt. Dafür ein **Origin Certificate** erzeugen (Cloudflare → SSL/TLS → Origin Server → Zertifikat erstellen; 15 Jahre gültig, kein Renewal wie bei Let's Encrypt nötig) und auf dem Server ablegen.
diff --git a/docs/handoff.md b/docs/handoff.md
index 526bbcb..4681dbe 100644
--- a/docs/handoff.md
+++ b/docs/handoff.md
@@ -1,6 +1,6 @@
# Handoff: LeafItToMe (Pflanzenpflege-App)
-Stand: 2026-08-20 (Session-Ende). Sprache mit dem Nutzer (Chris): **Deutsch**.
+Stand: 2026-09-08 (Session-Ende). Sprache mit dem Nutzer (Chris): **Deutsch**.
## Projekt in einem Satz
@@ -30,10 +30,20 @@ Private Flutter-App (iOS+Android) zur Pflanzenpflege für Haushalt + Pflanzen-Si
## Offen / Nächstes
-### 1. App-Store-Vorbereitung (läuft, 2026-08-20 begonnen)
+### 1. App-Store-Vorbereitung (iOS/TestFlight abgeschlossen 2026-09-08; Android offen)
Ziel fürs Erste: **nur TestFlight + Play-Internal-Testing**, kein öffentlicher Store-Eintrag (mit Chris abgestimmt — spart Screenshots/Store-Texte/Altersfreigabe für später). Bundle-ID bleibt bewusst `dev.leafittome.app` (eigene Domain steht noch aus, ist aber kein Blocker für TestFlight/Internal-Testing).
+**iOS / TestFlight: fertig (2026-09-08).** Erster Build `1.0.0 (1)` hochgeladen, in TestFlight „Bereit zum Testen", auf dem iPhone installiert und nutzbar. Dabei erledigt:
+- `lib/main.dart`: App-Check-Provider per `kReleaseMode` umgeschaltet — Release nutzt `AndroidPlayIntegrityProvider` / `AppleAppAttestProvider`, Debug weiter Debug-Provider. Nötig, weil die Functions App Check erzwingen.
+- App-Icon: `assets/icon/icon.png` (1024×1024, ohne Alpha) + `dart run flutter_launcher_icons` → iOS-/Android-Icon-Sätze generiert. (Tool-Macke v0.14.4: verhunzt `ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS` in `project.pbxproj` von `YES` auf `AppIcon` — danach zurücksetzen.)
+- Datenschutzerklärung: Platzhalter in `docs/legal/datenschutz.html` ausgefüllt (Christopher Schläfke / cschlaefke@live.com / 8. September 2026), interner Hinweiskasten raus. Gehostet via **Firebase Hosting** (`hosting`-Block in `firebase.json`, `public: "docs/legal"`), URL **`https://leaf-it-to-me-app.web.app/datenschutz`** — in App Store Connect eingetragen. Deploy: `firebase deploy --only hosting`.
+- App Store Connect: App-Eintrag + App-Datenschutz-Fragebogen ausgefüllt (E-Mail, Fotos, Nutzerinhalte, Nutzer-ID — alle verknüpft, kein Tracking).
+- **Stolperfalle (teuer erkauft):** `flutter build ipa` über die CLI signiert headless nur mit „Apple Development" → App-Store-Upload lehnt mit „Invalid Signature / Code 90035" jede Framework-Datei ab. Fix: in Xcode → Settings → Accounts → Manage Certificates → „+" → **Apple Distribution** anlegen, dann **aus Xcode archivieren** (Product → Archive) statt CLI. Details in `firebase-einrichtung.md` Schritt 10.
+- Die „Upload Symbols Failed / dSYM"-Meldungen für Firebase/gRPC/absl/Recaptcha beim Upload sind **harmlos** (vorkompilierte Frameworks ohne Debug-Symbole, nur Crash-Symbolik).
+
+**Offene Kleinigkeit iOS:** Launch-Screen ist noch der weiße Flutter-Platzhalter (Warnung beim Build, kein Blocker) → Backlog.
+
**App Check: vollständig abgeschlossen** (2026-08-20). Play Integrity (Android) + App Attest (iOS) in der Firebase-Console registriert, Debug-Token hinterlegt, „Verified requests" für Cloud Functions auf beiden Plattformen bestätigt, `enforceAppCheck: true` auf allen 7 `onCall`-Functions deployt (Commit `49b7f44`) und per Gerätetest bestätigt (Pflanze anlegen/Diagnose funktionieren normal). **Hinweis für später:** Unverified Requests bei Firestore/Storage in der Console sind erwartet/harmlos — dafür wurde nie Enforcement eingerichtet, nur für die Functions. Ebenso die einmalige iOS-Kaltstart-Meldung „App not registered … exchangeDeviceCheckToken" — bekannte, folgenlose Plugin-Race, siehe `firebase-einrichtung.md` Schritt 9.
**Weiteres Code-seitig erledigt:**
@@ -44,12 +54,12 @@ Ziel fürs Erste: **nur TestFlight + Play-Internal-Testing**, kein öffentlicher
- Nebenbei behoben: SPM-Versionskonflikt durch `firebase_app_check`-Einführung (inkonsistente Firebase-Paket-Minor-Versionen verhinderten den iOS-Build) — Commit `248f3be`.
- Neue Doku-Schritte in `firebase-einrichtung.md`: **Schritt 9** (App Check, jetzt komplett abgeschlossen), **Schritt 10** (TestFlight einrichten), **Schritt 11** (Play Internal Testing einrichten) — inkl. Textvorlagen für Apples App-Privacy-Fragebogen und Googles Data-Safety-Formular.
-**Noch offen (Chris' nächste Schritte, alle in `firebase-einrichtung.md` Schritt 10–11 dokumentiert):**
-- App-Icon: 1024×1024-Design liefern → unter `assets/icon/icon.png` ablegen → `dart run flutter_launcher_icons`.
-- Datenschutzerklärung: Platzhalter ausfüllen + über Cloudflare/Hetzner hosten (Anleitung s. o.).
-- Android-Upload-Key erzeugen (`keytool`, Schritt 11) und sichern.
-- App Store Connect: App-Eintrag anlegen, Privacy-URL + App-Privacy-Fragebogen ausfüllen, Build hochladen, interne TestFlight-Gruppe + Tester.
-- Play Console: App anlegen, Datenschutz-URL + Data-Safety-Formular + Content-Rating ausfüllen, internen Test-Track + Tester.
+**Noch offen — nur noch Android (Play Internal Testing), dokumentiert in `firebase-einrichtung.md` Schritt 11:**
+- Android-Upload-Key erzeugen (`keytool`, Schritt 11) und sofort sichern (Passwort-Manager + Backup außerhalb des Repos).
+- `android/key.properties` lokal anlegen (Vorlage `android/key.properties.example`).
+- Release-Fingerabdruck (SHA-1/SHA-256 des Upload-Keys) in Firebase hinterlegen (`firebase apps:android:sha:create`) — für App Check / Play Integrity im Release.
+- `flutter build appbundle --release` → Play Console: App anlegen, Datenschutz-URL (`https://leaf-it-to-me-app.web.app/datenschutz`) + Data-Safety-Formular + Content-Rating, internen Test-Track + Tester.
+- App-Icon ist bereits generiert (auch Android-Mipmaps), Datenschutzerklärung ist bereits gehostet — beides gilt für Android mit.
### 2. Backlog
@@ -69,6 +79,8 @@ Button „KI-Zweitmeinung" bei unbefriedigendem PlantNet-Ergebnis; Push-Anzeige
- iOS-Fehler „requires minimum platform version 15.0 … but this target supports 13.0": nach `flutter clean` oder beim Bauen direkt aus Xcode einmal `flutter build ios --config-only` ausführen (SwiftPM-Paket wird bei `pub get` mit iOS 13 erzeugt).
- In `.arb`-Dateien UND in deutschen Texten innerhalb von TS-Strings (Function-Prompts!) **typografische Anführungszeichen „…“** verwenden — gerade `"` brechen das JSON bzw. den TS-String.
- Die Bash-Session wechselt das Arbeitsverzeichnis **nicht zurück**: nach `cd functions && npm run build` vor Flutter-Kommandos wieder explizit ins Projekt-Root.
+- **iOS-App-Store-Upload braucht ein „Apple Distribution"-Zertifikat.** `flutter build ipa` über die CLI zieht es headless nicht und signiert nur mit „Apple Development" → Upload scheitert mit „Invalid Signature / Code 90035". Zuerst in Xcode → Settings → Accounts → Manage Certificates → „+" → Apple Distribution anlegen (`security find-identity -v -p codesigning` muss die Zeile zeigen), dann **aus Xcode archivieren** (Product → Archive), nicht per CLI.
+- `flutter_launcher_icons` v0.14.4 schreibt beim Generieren `ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = AppIcon` (statt `YES`) in `ios/Runner.xcodeproj/project.pbxproj` — danach `git checkout` auf die Datei, die generierten Icons bleiben.
- Nutzer wünscht zu jedem Backend-Baustein **begleitende deutsche Doku** in `docs/` (keine Firebase-Vorerfahrung).
## Arbeitsabläufe
diff --git a/docs/legal/datenschutz.html b/docs/legal/datenschutz.html
index 69528cd..2b1b9f3 100644
--- a/docs/legal/datenschutz.html
+++ b/docs/legal/datenschutz.html
@@ -27,20 +27,12 @@
Datenschutzerklärung – LeafItToMe
-Stand: [Datum einsetzen]
-
-
- Hinweis für Chris (vor Veröffentlichung entfernen):
- Platzhalter [Name], [E-Mail-Adresse] und [Datum]
- ausfüllen. Diese Seite ist als öffentlich erreichbare, eigenständige HTML-Datei gedacht
- (Hosting-Vorschlag in docs/firebase-einrichtung.md), auf die im Apple/Google-
- Account bei „Datenschutzerklärung" verlinkt wird.
-
+Stand: 8. September 2026
Verantwortlicher
- [Name]
- E-Mail: [E-Mail-Adresse]
+ Christopher Schläfke
+ E-Mail: cschlaefke@live.com
LeafItToMe ist eine private, nicht kommerzielle App zur Pflanzenpflege für einen
@@ -105,7 +97,7 @@
Daten werden gespeichert, solange dein Konto bzw. der Haushalt besteht.
Zur Löschung deines Kontos oder einzelner Daten wende dich an
- [E-Mail-Adresse].
+ cschlaefke@live.com.
Deine Rechte
@@ -113,7 +105,7 @@
Du hast das Recht auf Auskunft, Berichtigung, Löschung, Einschränkung der
Verarbeitung, Datenübertragbarkeit und Widerspruch gemäß Art. 15–21 DSGVO
sowie ein Beschwerderecht bei einer Datenschutzaufsichtsbehörde. Wende dich
- dazu an [E-Mail-Adresse].
+ dazu an cschlaefke@live.com.
diff --git a/firebase.json b/firebase.json
index 2b02355..ec0e72c 100644
--- a/firebase.json
+++ b/firebase.json
@@ -10,6 +10,18 @@
"source": "functions",
"predeploy": ["npm --prefix functions run build"]
},
+ "hosting": {
+ "public": "docs/legal",
+ "cleanUrls": true,
+ "ignore": ["firebase.json", "**/.*"],
+ "redirects": [
+ {
+ "source": "/",
+ "destination": "/datenschutz",
+ "type": 302
+ }
+ ]
+ },
"flutter": {
"platforms": {
"android": {
diff --git a/ios/Runner.xcworkspace/xcshareddata/swiftpm/Package.resolved b/ios/Runner.xcworkspace/xcshareddata/swiftpm/Package.resolved
index 5c3953c..e337d1b 100644
--- a/ios/Runner.xcworkspace/xcshareddata/swiftpm/Package.resolved
+++ b/ios/Runner.xcworkspace/xcshareddata/swiftpm/Package.resolved
@@ -50,8 +50,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/google/GoogleDataTransport.git",
"state" : {
- "revision" : "617af071af9aa1d6a091d59a202910ac482128f9",
- "version" : "10.1.0"
+ "revision" : "ba3358d3c3dbae8ef230b58a46b97ad65e84e974",
+ "version" : "10.1.1"
}
},
{
@@ -59,8 +59,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/google/GoogleUtilities.git",
"state" : {
- "revision" : "9f183ae842be978784f2963a343682e0c46d8fb3",
- "version" : "8.1.2"
+ "revision" : "92c8f6dc3ac375d6febdfcb3db68bc3d10633db3",
+ "version" : "8.1.3"
}
},
{
@@ -77,8 +77,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/google/gtm-session-fetcher.git",
"state" : {
- "revision" : "c0ac7575d70050c2973ba2318bd5af47f8e8153a",
- "version" : "5.3.0"
+ "revision" : "724a52eea6329b7e12d3ad8300d76ca9f3895fcc",
+ "version" : "5.3.1"
}
},
{
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json
index d36b1fa..d0d98aa 100644
--- a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json
+++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json
@@ -1,122 +1 @@
-{
- "images" : [
- {
- "size" : "20x20",
- "idiom" : "iphone",
- "filename" : "Icon-App-20x20@2x.png",
- "scale" : "2x"
- },
- {
- "size" : "20x20",
- "idiom" : "iphone",
- "filename" : "Icon-App-20x20@3x.png",
- "scale" : "3x"
- },
- {
- "size" : "29x29",
- "idiom" : "iphone",
- "filename" : "Icon-App-29x29@1x.png",
- "scale" : "1x"
- },
- {
- "size" : "29x29",
- "idiom" : "iphone",
- "filename" : "Icon-App-29x29@2x.png",
- "scale" : "2x"
- },
- {
- "size" : "29x29",
- "idiom" : "iphone",
- "filename" : "Icon-App-29x29@3x.png",
- "scale" : "3x"
- },
- {
- "size" : "40x40",
- "idiom" : "iphone",
- "filename" : "Icon-App-40x40@2x.png",
- "scale" : "2x"
- },
- {
- "size" : "40x40",
- "idiom" : "iphone",
- "filename" : "Icon-App-40x40@3x.png",
- "scale" : "3x"
- },
- {
- "size" : "60x60",
- "idiom" : "iphone",
- "filename" : "Icon-App-60x60@2x.png",
- "scale" : "2x"
- },
- {
- "size" : "60x60",
- "idiom" : "iphone",
- "filename" : "Icon-App-60x60@3x.png",
- "scale" : "3x"
- },
- {
- "size" : "20x20",
- "idiom" : "ipad",
- "filename" : "Icon-App-20x20@1x.png",
- "scale" : "1x"
- },
- {
- "size" : "20x20",
- "idiom" : "ipad",
- "filename" : "Icon-App-20x20@2x.png",
- "scale" : "2x"
- },
- {
- "size" : "29x29",
- "idiom" : "ipad",
- "filename" : "Icon-App-29x29@1x.png",
- "scale" : "1x"
- },
- {
- "size" : "29x29",
- "idiom" : "ipad",
- "filename" : "Icon-App-29x29@2x.png",
- "scale" : "2x"
- },
- {
- "size" : "40x40",
- "idiom" : "ipad",
- "filename" : "Icon-App-40x40@1x.png",
- "scale" : "1x"
- },
- {
- "size" : "40x40",
- "idiom" : "ipad",
- "filename" : "Icon-App-40x40@2x.png",
- "scale" : "2x"
- },
- {
- "size" : "76x76",
- "idiom" : "ipad",
- "filename" : "Icon-App-76x76@1x.png",
- "scale" : "1x"
- },
- {
- "size" : "76x76",
- "idiom" : "ipad",
- "filename" : "Icon-App-76x76@2x.png",
- "scale" : "2x"
- },
- {
- "size" : "83.5x83.5",
- "idiom" : "ipad",
- "filename" : "Icon-App-83.5x83.5@2x.png",
- "scale" : "2x"
- },
- {
- "size" : "1024x1024",
- "idiom" : "ios-marketing",
- "filename" : "Icon-App-1024x1024@1x.png",
- "scale" : "1x"
- }
- ],
- "info" : {
- "version" : 1,
- "author" : "xcode"
- }
-}
+{"images":[{"size":"20x20","idiom":"iphone","filename":"Icon-App-20x20@2x.png","scale":"2x"},{"size":"20x20","idiom":"iphone","filename":"Icon-App-20x20@3x.png","scale":"3x"},{"size":"29x29","idiom":"iphone","filename":"Icon-App-29x29@1x.png","scale":"1x"},{"size":"29x29","idiom":"iphone","filename":"Icon-App-29x29@2x.png","scale":"2x"},{"size":"29x29","idiom":"iphone","filename":"Icon-App-29x29@3x.png","scale":"3x"},{"size":"40x40","idiom":"iphone","filename":"Icon-App-40x40@2x.png","scale":"2x"},{"size":"40x40","idiom":"iphone","filename":"Icon-App-40x40@3x.png","scale":"3x"},{"size":"57x57","idiom":"iphone","filename":"Icon-App-57x57@1x.png","scale":"1x"},{"size":"57x57","idiom":"iphone","filename":"Icon-App-57x57@2x.png","scale":"2x"},{"size":"60x60","idiom":"iphone","filename":"Icon-App-60x60@2x.png","scale":"2x"},{"size":"60x60","idiom":"iphone","filename":"Icon-App-60x60@3x.png","scale":"3x"},{"size":"20x20","idiom":"ipad","filename":"Icon-App-20x20@1x.png","scale":"1x"},{"size":"20x20","idiom":"ipad","filename":"Icon-App-20x20@2x.png","scale":"2x"},{"size":"29x29","idiom":"ipad","filename":"Icon-App-29x29@1x.png","scale":"1x"},{"size":"29x29","idiom":"ipad","filename":"Icon-App-29x29@2x.png","scale":"2x"},{"size":"40x40","idiom":"ipad","filename":"Icon-App-40x40@1x.png","scale":"1x"},{"size":"40x40","idiom":"ipad","filename":"Icon-App-40x40@2x.png","scale":"2x"},{"size":"50x50","idiom":"ipad","filename":"Icon-App-50x50@1x.png","scale":"1x"},{"size":"50x50","idiom":"ipad","filename":"Icon-App-50x50@2x.png","scale":"2x"},{"size":"72x72","idiom":"ipad","filename":"Icon-App-72x72@1x.png","scale":"1x"},{"size":"72x72","idiom":"ipad","filename":"Icon-App-72x72@2x.png","scale":"2x"},{"size":"76x76","idiom":"ipad","filename":"Icon-App-76x76@1x.png","scale":"1x"},{"size":"76x76","idiom":"ipad","filename":"Icon-App-76x76@2x.png","scale":"2x"},{"size":"83.5x83.5","idiom":"ipad","filename":"Icon-App-83.5x83.5@2x.png","scale":"2x"},{"size":"1024x1024","idiom":"ios-marketing","filename":"Icon-App-1024x1024@1x.png","scale":"1x"}],"info":{"version":1,"author":"xcode"}}
\ No newline at end of file
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png
index dc9ada4..abf4072 100644
Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png
index 7353c41..1ac6168 100644
Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png
index 797d452..451266f 100644
Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png
index 6ed2d93..fab8d92 100644
Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png
index 4cd7b00..e8a1207 100644
Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png
index fe73094..4dbfba8 100644
Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png
index 321773c..8a1817b 100644
Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png
index 797d452..451266f 100644
Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png
index 502f463..c153a4a 100644
Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png
index 0ec3034..2e3f51a 100644
Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@1x.png
new file mode 100644
index 0000000..a072cf2
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@1x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@2x.png
new file mode 100644
index 0000000..c68adc6
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@2x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png
new file mode 100644
index 0000000..adf8467
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png
new file mode 100644
index 0000000..5403b29
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png
index 0ec3034..2e3f51a 100644
Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png
index e9f5fea..d327b3f 100644
Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png
new file mode 100644
index 0000000..946d961
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png
new file mode 100644
index 0000000..e2afc39
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png
index 84ac32a..d6a9112 100644
Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png
index 8953cba..b9dce4e 100644
Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png
index 0467bf1..604db33 100644
Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png differ
diff --git a/lib/main.dart b/lib/main.dart
index 20fc056..128c37c 100644
--- a/lib/main.dart
+++ b/lib/main.dart
@@ -1,5 +1,6 @@
import 'package:firebase_app_check/firebase_app_check.dart';
import 'package:firebase_core/firebase_core.dart';
+import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:shared_preferences/shared_preferences.dart';
@@ -13,12 +14,19 @@ Future main() async {
await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform,
);
- // Debug-Provider, bis Play Integrity (Android) / App Attest (iOS) in der
- // Firebase-Console registriert sind (docs/firebase-einrichtung.md Schritt 9).
- // Die Functions erzwingen App Check noch nicht — reines Vorbereiten.
+ // Release-Builds (TestFlight/Play): echte Attestierung über Play Integrity
+ // (Android) bzw. App Attest (iOS). Debug-Builds nutzen weiter den
+ // Debug-Provider mit den in der Firebase-Console hinterlegten Debug-Tokens.
+ // Die onCall-Functions erzwingen App Check (enforceAppCheck: true), deshalb
+ // muss ein Release-Build zwingend einen echten Provider verwenden.
+ // Siehe docs/firebase-einrichtung.md Schritt 9.
await FirebaseAppCheck.instance.activate(
- providerAndroid: AndroidDebugProvider(),
- providerApple: AppleDebugProvider(),
+ providerAndroid: kReleaseMode
+ ? const AndroidPlayIntegrityProvider()
+ : AndroidDebugProvider(),
+ providerApple: kReleaseMode
+ ? const AppleAppAttestProvider()
+ : AppleDebugProvider(),
);
final prefs = await SharedPreferences.getInstance();
runApp(