464fbb2bad
App de watchOS de solo consulta: resumen de cartera (total, cambio del mes y mayores posiciones), objetivos con su progreso y estado del check-in con la racha. Toda la edición sigue en el iPhone. Complicaciones (accessoryCircular / Rectangular / Inline / Corner): valor total de la cartera, progreso del objetivo más cercano a cumplirse y racha + estado del check-in. Datos: los App Groups no se comparten entre iOS y watchOS, así que el reloj no puede leer el store de CoreData que lee el widget de iOS. En su lugar, WatchSyncService construye un WatchPortfolioSnapshot ligero y lo envía como application context de WatchConnectivity, enganchado a CoreDataStack.refreshWidgetData() — el mismo punto que refresca el widget de iOS, así que cualquier repositorio que toque datos refresca el reloj. WatchDataStore lo cachea en el App Group del watch (WatchSnapshotCache) y recarga las timelines; la extensión de complicaciones solo lee ese caché. Proyecto: dos targets nuevos (watchOS app + widget extension) con grupos sincronizados de Xcode 16; Shared/ pertenece a la app de watch y se comparte con la app de iOS y el widget mediante exception sets, el mismo mecanismo que ya usaba el widget de iOS para el modelo de CoreData. Scheme compartido PortfolioJournalWatch. Localización propia por target en los 7 idiomas. Verificado: compilan los tres targets, la app de watch queda embebida en Watch/ con la extensión en PlugIns/, y en el par de simuladores iPhone 17 Pro Max + Apple Watch Series 11 el reloj recibe y muestra el snapshot enviado por el iPhone. 10 tests nuevos del payload. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YcDn5ccuRFV83q7xWWokBT
60 lines
1.9 KiB
Swift
60 lines
1.9 KiB
Swift
import UIKit
|
|
import UserNotifications
|
|
import FirebaseCore
|
|
import FirebaseAnalytics
|
|
import FirebaseCrashlytics
|
|
import GoogleMobileAds
|
|
|
|
class AppDelegate: NSObject, UIApplicationDelegate {
|
|
func application(
|
|
_ application: UIApplication,
|
|
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil
|
|
) -> Bool {
|
|
// Initialize Firebase (only if GoogleService-Info.plist exists)
|
|
if Bundle.main.path(forResource: "GoogleService-Info", ofType: "plist") != nil {
|
|
FirebaseApp.configure()
|
|
} else {
|
|
print("Warning: GoogleService-Info.plist not found. Firebase disabled.")
|
|
}
|
|
|
|
// Initialize Google Mobile Ads
|
|
MobileAds.shared.start()
|
|
|
|
// Request notification permissions
|
|
requestNotificationPermissions()
|
|
|
|
// Apple Watch bridge: activating early means the first application
|
|
// context lands before the user raises their wrist.
|
|
Task { @MainActor in
|
|
WatchSyncService.shared.activate()
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
private func requestNotificationPermissions() {
|
|
let center = UNUserNotificationCenter.current()
|
|
center.requestAuthorization(options: [.alert, .badge, .sound]) { granted, error in
|
|
if let error = error {
|
|
print("Notification permission error: \(error)")
|
|
}
|
|
print("Notification permission granted: \(granted)")
|
|
}
|
|
}
|
|
|
|
func application(
|
|
_ application: UIApplication,
|
|
didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data
|
|
) {
|
|
let token = deviceToken.map { String(format: "%02.2hhx", $0) }.joined()
|
|
print("Device token: \(token)")
|
|
}
|
|
|
|
func application(
|
|
_ application: UIApplication,
|
|
didFailToRegisterForRemoteNotificationsWithError error: Error
|
|
) {
|
|
print("Failed to register for remote notifications: \(error)")
|
|
}
|
|
}
|