2.0: sync CloudKit en tiempo real vía push silencioso
NSPersistentCloudKitContainer solo sincronizaba de forma oportunista (sin push), por lo que un plato nuevo tardaba mucho o no aparecía en el otro dispositivo. Se activa el push de CloudKit: - aps-environment en MealMood.entitlements vía variable APS_ENVIRONMENT (development en Debug, production en Release) para no romper TestFlight. - AppDelegate con registerForRemoteNotifications() + manejo del push silencioso; el mirror de SwiftData importa al ser despertado. - (Capability Push Notifications habilitada en el App ID por API.) Pendiente: regenerar el provisioning profile AppStore con Push antes de la build 63, y validar el sync push en iPhone+iPad vía TestFlight. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A3HaWmmtTQ1vdTERtSYU6p
This commit is contained in:
@@ -923,6 +923,7 @@
|
|||||||
buildSettings = {
|
buildSettings = {
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
CODE_SIGN_ENTITLEMENTS = MealMood/Resources/MealMood.entitlements;
|
CODE_SIGN_ENTITLEMENTS = MealMood/Resources/MealMood.entitlements;
|
||||||
|
APS_ENVIRONMENT = production;
|
||||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||||
CURRENT_PROJECT_VERSION = 62;
|
CURRENT_PROJECT_VERSION = 62;
|
||||||
DEVELOPMENT_TEAM = 2825Q76T7H;
|
DEVELOPMENT_TEAM = 2825Q76T7H;
|
||||||
@@ -1028,6 +1029,7 @@
|
|||||||
buildSettings = {
|
buildSettings = {
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
CODE_SIGN_ENTITLEMENTS = MealMood/Resources/MealMood.entitlements;
|
CODE_SIGN_ENTITLEMENTS = MealMood/Resources/MealMood.entitlements;
|
||||||
|
APS_ENVIRONMENT = development;
|
||||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||||
CURRENT_PROJECT_VERSION = 62;
|
CURRENT_PROJECT_VERSION = 62;
|
||||||
DEVELOPMENT_TEAM = 2825Q76T7H;
|
DEVELOPMENT_TEAM = 2825Q76T7H;
|
||||||
|
|||||||
@@ -1,11 +1,32 @@
|
|||||||
import SwiftUI
|
import SwiftUI
|
||||||
import SwiftData
|
import SwiftData
|
||||||
|
import UIKit
|
||||||
import FirebaseCore
|
import FirebaseCore
|
||||||
import FirebaseCrashlytics
|
import FirebaseCrashlytics
|
||||||
#if canImport(GoogleMobileAds)
|
#if canImport(GoogleMobileAds)
|
||||||
import GoogleMobileAds
|
import GoogleMobileAds
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/// Registers for remote notifications so CloudKit (the NSPersistentCloudKitContainer
|
||||||
|
/// behind SwiftData) receives its silent-push subscriptions and imports changes
|
||||||
|
/// in near-real-time across devices. Silent pushes are coalesced by the system,
|
||||||
|
/// so battery cost is negligible — no polling.
|
||||||
|
final class AppDelegate: NSObject, UIApplicationDelegate {
|
||||||
|
func application(_ application: UIApplication,
|
||||||
|
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool {
|
||||||
|
application.registerForRemoteNotifications()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func application(_ application: UIApplication,
|
||||||
|
didReceiveRemoteNotification userInfo: [AnyHashable: Any],
|
||||||
|
fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
|
||||||
|
// CloudKit silent push: SwiftData's mirror imports on its own once woken;
|
||||||
|
// report new data so the system keeps delivering sync pushes.
|
||||||
|
completionHandler(.newData)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Whether the store is syncing through CloudKit this launch. When true, the
|
/// Whether the store is syncing through CloudKit this launch. When true, the
|
||||||
/// legacy iCloud KV snapshot sync must stay inert (both would fight).
|
/// legacy iCloud KV snapshot sync must stay inert (both would fight).
|
||||||
enum CloudSyncRuntime {
|
enum CloudSyncRuntime {
|
||||||
@@ -16,6 +37,8 @@ enum CloudSyncRuntime {
|
|||||||
|
|
||||||
@main
|
@main
|
||||||
struct MealMoodApp: App {
|
struct MealMoodApp: App {
|
||||||
|
@UIApplicationDelegateAdaptor(AppDelegate.self) private var appDelegate
|
||||||
|
|
||||||
private let modelContainer: ModelContainer = {
|
private let modelContainer: ModelContainer = {
|
||||||
let schema = Schema([
|
let schema = Schema([
|
||||||
AppSettings.self,
|
AppSettings.self,
|
||||||
|
|||||||
@@ -2,6 +2,8 @@
|
|||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "https://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "https://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
<plist version="1.0">
|
<plist version="1.0">
|
||||||
<dict>
|
<dict>
|
||||||
|
<key>aps-environment</key>
|
||||||
|
<string>$(APS_ENVIRONMENT)</string>
|
||||||
<key>com.apple.developer.icloud-container-identifiers</key>
|
<key>com.apple.developer.icloud-container-identifiers</key>
|
||||||
<array>
|
<array>
|
||||||
<string>iCloud.com.alexandrev.mealmood</string>
|
<string>iCloud.com.alexandrev.mealmood</string>
|
||||||
|
|||||||
Reference in New Issue
Block a user