iOS-Push aktiviert: APNs/Entitlements + Doku
- Push Notifications & Background Mode (remote-notification) als iOS-Capability ergänzt (Runner.entitlements, Info.plist, project.pbxproj) - Apple Developer Account freigeschaltet, APNs-Schlüssel in Firebase hinterlegt - Doku: firebase-einrichtung.md Schritt 6 auf "erledigt" + Stolperfalle "Personal Team versteckt Push-Capability" festgehalten - Handoff: V1 nun auch iOS vollständig, iOS-Push aus Offen-Liste entfernt Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
1986a920fa
commit
da12e3e5ab
5 changed files with 30 additions and 12 deletions
|
|
@ -133,7 +133,7 @@ Die Keys liegen damit im **Google Secret Manager** — verschlüsselt, nur die C
|
||||||
|
|
||||||
**Android:** funktioniert sofort — beim ersten App-Start nach diesem Update fragt die App die Benachrichtigungs-Berechtigung ab, fertig.
|
**Android:** funktioniert sofort — beim ersten App-Start nach diesem Update fragt die App die Benachrichtigungs-Berechtigung ab, fertig.
|
||||||
|
|
||||||
**iOS braucht den Apple Developer Account** (Push ist auf iOS ohne bezahlten Account nicht möglich). Sobald er freigeschaltet ist:
|
**iOS braucht den Apple Developer Account** (Push ist auf iOS ohne bezahlten Account nicht möglich). ✅ **Erledigt am 2026-07-20** — iOS-Push ist eingerichtet und läuft auf dem echten Gerät. So wurde es gemacht:
|
||||||
|
|
||||||
1. **APNs-Schlüssel erzeugen:** <https://developer.apple.com> → *Certificates, Identifiers & Profiles* → **Keys** → „+" → Namen vergeben, **Apple Push Notifications service (APNs)** ankreuzen → Continue → Register → **.p8-Datei herunterladen** (nur einmal möglich!) und die **Key ID** notieren; die **Team ID** steht oben rechts im Account.
|
1. **APNs-Schlüssel erzeugen:** <https://developer.apple.com> → *Certificates, Identifiers & Profiles* → **Keys** → „+" → Namen vergeben, **Apple Push Notifications service (APNs)** ankreuzen → Continue → Register → **.p8-Datei herunterladen** (nur einmal möglich!) und die **Key ID** notieren; die **Team ID** steht oben rechts im Account.
|
||||||
2. **In Firebase hinterlegen:** Firebase Console → Projekteinstellungen (Zahnrad) → **Cloud Messaging** → Abschnitt „Apple-App-Konfiguration" → APNs-Authentifizierungsschlüssel **hochladen** (.p8 + Key ID + Team ID).
|
2. **In Firebase hinterlegen:** Firebase Console → Projekteinstellungen (Zahnrad) → **Cloud Messaging** → Abschnitt „Apple-App-Konfiguration" → APNs-Authentifizierungsschlüssel **hochladen** (.p8 + Key ID + Team ID).
|
||||||
|
|
@ -141,6 +141,8 @@ Die Keys liegen damit im **Google Secret Manager** — verschlüsselt, nur die C
|
||||||
|
|
||||||
Danach einmal neu bauen (`flutter run`) — die Erinnerungen landen dann auch auf dem iPhone-Sperrbildschirm.
|
Danach einmal neu bauen (`flutter run`) — die Erinnerungen landen dann auch auf dem iPhone-Sperrbildschirm.
|
||||||
|
|
||||||
|
> **Stolperfalle (teuer erkauft):** „Push Notifications" fehlte in Xcode unter „+ Capability", obwohl „Background Modes" da war. Ursache: Es war noch das alte **kostenlose „Personal Team"** als Signing-Team gewählt — Gratis-Teams dürfen kein Push, deshalb blendet Xcode den Eintrag komplett aus. Fix: In *Xcode → Settings → Accounts* die Apple-ID mit der bezahlten Mitgliedschaft hinzufügen und in *Signing & Capabilities* das Team **ohne** den Zusatz `(Personal Team)` wählen. Danach erscheint „Push Notifications" in der Liste.
|
||||||
|
|
||||||
## Schritt 7 und folgende (kommen mit den nächsten Blöcken)
|
## Schritt 7 und folgende (kommen mit den nächsten Blöcken)
|
||||||
|
|
||||||
- **Google-/Apple-Login** — zusätzlich zu E-Mail/Passwort (Apple-Login braucht ebenfalls den Developer Account).
|
- **Google-/Apple-Login** — zusätzlich zu E-Mail/Passwort (Apple-Login braucht ebenfalls den Developer Account).
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ Private Flutter-App (iOS+Android) zur Pflanzenpflege für Haushalt + Pflanzen-Si
|
||||||
|
|
||||||
## Verifizierter Stand
|
## Verifizierter Stand
|
||||||
|
|
||||||
- **V1 komplett** und auf Android Ende-zu-Ende getestet: Foto → Erkennung → vorbefülltes Profil; Tages-Checkliste; Sammel-Push kam im regulären Scheduler-Lauf auf dem Sperrbildschirm an. iOS-App läuft ebenfalls (Login, Pflanzen, Fotos) — **nur iOS-Push fehlt** (braucht Apple Developer Account, Beantragung scheiterte bisher an Apples Webseite; Schritte stehen in `docs/firebase-einrichtung.md` Schritt 6).
|
- **V1 komplett** und auf Android + iOS Ende-zu-Ende getestet: Foto → Erkennung → vorbefülltes Profil; Tages-Checkliste; Sammel-Push kam im regulären Scheduler-Lauf auf dem Sperrbildschirm an. **iOS-Push seit 2026-07-20 eingerichtet und laufend** (Apple Developer Account freigeschaltet, APNs-Schlüssel in Firebase, Push-/Background-Capability in Xcode — Details + Stolperfalle „Personal Team" in `docs/firebase-einrichtung.md` Schritt 6).
|
||||||
- **V2 implementiert, deployt und vom Nutzer erfolgreich getestet** (Einladungscodes member/sitter, `joinHousehold`-Function, Rules-Enforcement für Sitter, „bestätigt von"-Anzeige).
|
- **V2 implementiert, deployt und vom Nutzer erfolgreich getestet** (Einladungscodes member/sitter, `joinHousehold`-Function, Rules-Enforcement für Sitter, „bestätigt von"-Anzeige).
|
||||||
- **V2.1 Multi-Haushalt implementiert und getestet**: Nutzer bleiben Mitglied aller Haushalte (`memberUids` ist Quelle der Wahrheit, `users.householdId` nur noch aktiver Zeiger), `sendDailyReminders` sammelt Aufgaben aus allen Haushalten.
|
- **V2.1 Multi-Haushalt implementiert und getestet**: Nutzer bleiben Mitglied aller Haushalte (`memberUids` ist Quelle der Wahrheit, `users.householdId` nur noch aktiver Zeiger), `sendDailyReminders` sammelt Aufgaben aus allen Haushalten.
|
||||||
- **V2.2 implementiert, deployt und vom Nutzer vollständig getestet und bestätigt**: Besitzer-Konzept (`ownerUid`, Alt-Haushalte: memberUids[0]), Besitzer-Anzeige, Haushalt umbenennen (Rules: Clients dürfen nur noch `name` ändern), Haushalts-Wechsler im Drawer, Tages-Checkliste gruppiert Aufgaben aus allen Haushalten, Functions `leaveHousehold`/`removeMember` (biegen den aktiven Zeiger des Betroffenen um, legen notfalls frischen Haushalt an). Zwei Nachbesserungen aus dem Live-Test, beide behoben und bestätigt:
|
- **V2.2 implementiert, deployt und vom Nutzer vollständig getestet und bestätigt**: Besitzer-Konzept (`ownerUid`, Alt-Haushalte: memberUids[0]), Besitzer-Anzeige, Haushalt umbenennen (Rules: Clients dürfen nur noch `name` ändern), Haushalts-Wechsler im Drawer, Tages-Checkliste gruppiert Aufgaben aus allen Haushalten, Functions `leaveHousehold`/`removeMember` (biegen den aktiven Zeiger des Betroffenen um, legen notfalls frischen Haushalt an). Zwei Nachbesserungen aus dem Live-Test, beide behoben und bestätigt:
|
||||||
|
|
@ -26,11 +26,11 @@ Private Flutter-App (iOS+Android) zur Pflanzenpflege für Haushalt + Pflanzen-Si
|
||||||
|
|
||||||
## Offen / Nächstes
|
## Offen / Nächstes
|
||||||
|
|
||||||
**Offener Faden aus der letzten Session:** Der Nutzer wollte nach der V2.2-Bestätigung weitermachen, hat auf Rückfrage nach dem nächsten Punkt aber bewusst „Etwas anderes" gewählt statt einer der unten stehenden Optionen — die Session endete, bevor er sagen konnte, worum es geht. **Nächster Schritt: direkt fragen, was das Anliegen ist, nicht von einem der Kandidaten unten ausgehen.**
|
**Zuletzt erledigt (2026-07-20):** iOS-Push eingerichtet — Apple Developer Account war frisch freigeschaltet, APNs-Schlüssel/Firebase/Xcode-Capability durchgezogen, Nutzer bestätigt „läuft jetzt". Damit ist V1 auch auf iOS vollständig.
|
||||||
|
|
||||||
Bekannte Kandidaten, falls der Nutzer nach Optionen fragt:
|
Bekannte Kandidaten für den nächsten Schritt:
|
||||||
|
|
||||||
1. iOS-Push, sobald Apple Developer Account existiert.
|
1. **Apple-Login** — braucht denselben (jetzt vorhandenen) Developer Account, wäre logischer Anschluss an iOS-Push (siehe `docs/firebase-einrichtung.md` Schritt 7).
|
||||||
2. **V3:** Krankheits-Diagnose per Foto, Stellplatz-Bewertung (Standort-Analyse pro Stellplatz + Eignungs-Sterne pro Pflanze — Zwei-Ebenen-Konzept siehe Memory), Umtopf-Erinnerungen.
|
2. **V3:** Krankheits-Diagnose per Foto, Stellplatz-Bewertung (Standort-Analyse pro Stellplatz + Eignungs-Sterne pro Pflanze — Zwei-Ebenen-Konzept siehe Memory), Umtopf-Erinnerungen.
|
||||||
3. **Backlog:** Button „KI-Zweitmeinung" bei unbefriedigendem PlantNet-Ergebnis; Push-Anzeige auch bei App im Vordergrund; App Check vor App-Store-Release; Englisch (`app_en.arb`).
|
3. **Backlog:** Button „KI-Zweitmeinung" bei unbefriedigendem PlantNet-Ergebnis; Push-Anzeige auch bei App im Vordergrund; App Check vor App-Store-Release; Englisch (`app_en.arb`).
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -69,6 +69,7 @@
|
||||||
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
|
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
|
||||||
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||||
B91F40C029091C1C3E88A3C3 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
B91F40C029091C1C3E88A3C3 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
D85240B0300E69D300945466 /* Runner.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Runner.entitlements; sourceTree = "<group>"; };
|
||||||
/* End PBXFileReference section */
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
/* Begin PBXFrameworksBuildPhase section */
|
/* Begin PBXFrameworksBuildPhase section */
|
||||||
|
|
@ -102,7 +103,6 @@
|
||||||
041675BB1A44D5A4222F7755 /* Pods-RunnerTests.release.xcconfig */,
|
041675BB1A44D5A4222F7755 /* Pods-RunnerTests.release.xcconfig */,
|
||||||
27AD176722468C79F044AE02 /* Pods-RunnerTests.profile.xcconfig */,
|
27AD176722468C79F044AE02 /* Pods-RunnerTests.profile.xcconfig */,
|
||||||
);
|
);
|
||||||
name = Pods;
|
|
||||||
path = Pods;
|
path = Pods;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
|
@ -151,6 +151,7 @@
|
||||||
97C146F01CF9000F007C117D /* Runner */ = {
|
97C146F01CF9000F007C117D /* Runner */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
D85240B0300E69D300945466 /* Runner.entitlements */,
|
||||||
97C146FA1CF9000F007C117D /* Main.storyboard */,
|
97C146FA1CF9000F007C117D /* Main.storyboard */,
|
||||||
97C146FD1CF9000F007C117D /* Assets.xcassets */,
|
97C146FD1CF9000F007C117D /* Assets.xcassets */,
|
||||||
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
|
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
|
||||||
|
|
@ -248,7 +249,7 @@
|
||||||
);
|
);
|
||||||
mainGroup = 97C146E51CF9000F007C117D;
|
mainGroup = 97C146E51CF9000F007C117D;
|
||||||
packageReferences = (
|
packageReferences = (
|
||||||
781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "FlutterGeneratedPluginSwiftPackage" */,
|
781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage" */,
|
||||||
);
|
);
|
||||||
productRefGroup = 97C146EF1CF9000F007C117D /* Products */;
|
productRefGroup = 97C146EF1CF9000F007C117D /* Products */;
|
||||||
projectDirPath = "";
|
projectDirPath = "";
|
||||||
|
|
@ -466,6 +467,7 @@
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
CLANG_ENABLE_MODULES = YES;
|
CLANG_ENABLE_MODULES = YES;
|
||||||
|
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||||
DEVELOPMENT_TEAM = KSX6GJY9C5;
|
DEVELOPMENT_TEAM = KSX6GJY9C5;
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
|
|
@ -649,6 +651,7 @@
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
CLANG_ENABLE_MODULES = YES;
|
CLANG_ENABLE_MODULES = YES;
|
||||||
|
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||||
DEVELOPMENT_TEAM = KSX6GJY9C5;
|
DEVELOPMENT_TEAM = KSX6GJY9C5;
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
|
|
@ -672,6 +675,7 @@
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
CLANG_ENABLE_MODULES = YES;
|
CLANG_ENABLE_MODULES = YES;
|
||||||
|
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||||
DEVELOPMENT_TEAM = KSX6GJY9C5;
|
DEVELOPMENT_TEAM = KSX6GJY9C5;
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
|
|
@ -724,7 +728,7 @@
|
||||||
/* End XCConfigurationList section */
|
/* End XCConfigurationList section */
|
||||||
|
|
||||||
/* Begin XCLocalSwiftPackageReference section */
|
/* Begin XCLocalSwiftPackageReference section */
|
||||||
781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "FlutterGeneratedPluginSwiftPackage" */ = {
|
781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage" */ = {
|
||||||
isa = XCLocalSwiftPackageReference;
|
isa = XCLocalSwiftPackageReference;
|
||||||
relativePath = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage;
|
relativePath = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,6 @@
|
||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
<plist version="1.0">
|
<plist version="1.0">
|
||||||
<dict>
|
<dict>
|
||||||
<key>NSCameraUsageDescription</key>
|
|
||||||
<string>LeafItToMe nutzt die Kamera, um Pflanzen zu fotografieren und automatisch zu erkennen.</string>
|
|
||||||
<key>NSPhotoLibraryUsageDescription</key>
|
|
||||||
<string>LeafItToMe greift auf deine Fotos zu, um vorhandene Pflanzenbilder auszuwählen.</string>
|
|
||||||
<key>CADisableMinimumFrameDurationOnPhone</key>
|
<key>CADisableMinimumFrameDurationOnPhone</key>
|
||||||
<true/>
|
<true/>
|
||||||
<key>CFBundleDevelopmentRegion</key>
|
<key>CFBundleDevelopmentRegion</key>
|
||||||
|
|
@ -30,6 +26,10 @@
|
||||||
<string>$(FLUTTER_BUILD_NUMBER)</string>
|
<string>$(FLUTTER_BUILD_NUMBER)</string>
|
||||||
<key>LSRequiresIPhoneOS</key>
|
<key>LSRequiresIPhoneOS</key>
|
||||||
<true/>
|
<true/>
|
||||||
|
<key>NSCameraUsageDescription</key>
|
||||||
|
<string>LeafItToMe nutzt die Kamera, um Pflanzen zu fotografieren und automatisch zu erkennen.</string>
|
||||||
|
<key>NSPhotoLibraryUsageDescription</key>
|
||||||
|
<string>LeafItToMe greift auf deine Fotos zu, um vorhandene Pflanzenbilder auszuwählen.</string>
|
||||||
<key>UIApplicationSceneManifest</key>
|
<key>UIApplicationSceneManifest</key>
|
||||||
<dict>
|
<dict>
|
||||||
<key>UIApplicationSupportsMultipleScenes</key>
|
<key>UIApplicationSupportsMultipleScenes</key>
|
||||||
|
|
@ -53,6 +53,10 @@
|
||||||
</dict>
|
</dict>
|
||||||
<key>UIApplicationSupportsIndirectInputEvents</key>
|
<key>UIApplicationSupportsIndirectInputEvents</key>
|
||||||
<true/>
|
<true/>
|
||||||
|
<key>UIBackgroundModes</key>
|
||||||
|
<array>
|
||||||
|
<string>remote-notification</string>
|
||||||
|
</array>
|
||||||
<key>UILaunchStoryboardName</key>
|
<key>UILaunchStoryboardName</key>
|
||||||
<string>LaunchScreen</string>
|
<string>LaunchScreen</string>
|
||||||
<key>UIMainStoryboardFile</key>
|
<key>UIMainStoryboardFile</key>
|
||||||
|
|
|
||||||
8
ios/Runner/Runner.entitlements
Normal file
8
ios/Runner/Runner.entitlements
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>aps-environment</key>
|
||||||
|
<string>development</string>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
Loading…
Reference in a new issue