@@ -6,7 +6,7 @@ import EventKit
66import UIKit
77import UserNotifications
88
9- @UIApplicationMain
9+ @main
1010class AppDelegate : UIResponder , UIApplicationDelegate {
1111 var window : UIWindow ?
1212 let notificationCenter = UNUserNotificationCenter . current ( )
@@ -32,7 +32,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
3232 }
3333
3434 let action = UNNotificationAction ( identifier: " OPEN_APP_ACTION " , title: " Open App " , options: . foreground)
35- let category = UNNotificationCategory ( identifier: " loopfollow.background.alert " , actions: [ action] , intentIdentifiers: [ ] , options: [ ] )
35+ let category = UNNotificationCategory ( identifier: BackgroundAlertIdentifier . categoryIdentifier , actions: [ action] , intentIdentifiers: [ ] , options: [ ] )
3636 UNUserNotificationCenter . current ( ) . setNotificationCategories ( [ category] )
3737
3838 UNUserNotificationCenter . current ( ) . delegate = self
@@ -45,50 +45,64 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
4545 DispatchQueue . main. async {
4646 UIApplication . shared. registerForRemoteNotifications ( )
4747 }
48+
49+ BackgroundRefreshManager . shared. register ( )
50+
51+ // Detect Before-First-Unlock launch. If protected data is unavailable here,
52+ // StorageValues were cached from encrypted UserDefaults and need a reload
53+ // on the first foreground after the user unlocks.
54+ let bfu = !UIApplication. shared. isProtectedDataAvailable
55+ Storage . shared. needsBFUReload = bfu
56+ LogManager . shared. log ( category: . general, message: " BFU check: isProtectedDataAvailable= \( !bfu) , needsBFUReload= \( bfu) " )
57+
4858 return true
4959 }
5060
51- func applicationWillTerminate( _: UIApplication ) { }
61+ func applicationWillTerminate( _: UIApplication ) {
62+ #if !targetEnvironment(macCatalyst)
63+ LiveActivityManager . shared. endOnTerminate ( )
64+ #endif
65+ }
5266
5367 // MARK: - Remote Notifications
5468
55- // Called when successfully registered for remote notifications
69+ /// Called when successfully registered for remote notifications
5670 func application( _: UIApplication , didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data ) {
5771 let tokenString = deviceToken. map { String ( format: " %02.2hhx " , $0) } . joined ( )
5872
5973 Observable . shared. loopFollowDeviceToken. value = tokenString
6074
61- LogManager . shared. log ( category: . general , message: " Successfully registered for remote notifications with token: \( tokenString) " )
75+ LogManager . shared. log ( category: . apns , message: " Successfully registered for remote notifications with token: \( tokenString) " )
6276 }
6377
64- // Called when failed to register for remote notifications
78+ /// Called when failed to register for remote notifications
6579 func application( _: UIApplication , didFailToRegisterForRemoteNotificationsWithError error: Error ) {
66- LogManager . shared. log ( category: . general , message: " Failed to register for remote notifications: \( error. localizedDescription) " )
80+ LogManager . shared. log ( category: . apns , message: " Failed to register for remote notifications: \( error. localizedDescription) " )
6781 }
6882
69- // Called when a remote notification is received
83+ /// Called when a remote notification is received
7084 func application( _: UIApplication , didReceiveRemoteNotification userInfo: [ AnyHashable : Any ] , fetchCompletionHandler completionHandler: @escaping ( UIBackgroundFetchResult ) -> Void ) {
71- LogManager . shared. log ( category: . general , message: " Received remote notification: \( userInfo) " )
85+ LogManager . shared. log ( category: . apns , message: " Received remote notification: \( userInfo) " )
7286
7387 // Check if this is a response notification from Loop or Trio
7488 if let aps = userInfo [ " aps " ] as? [ String : Any ] {
7589 // Handle visible notification (alert, sound, badge)
7690 if let alert = aps [ " alert " ] as? [ String : Any ] {
7791 let title = alert [ " title " ] as? String ?? " "
7892 let body = alert [ " body " ] as? String ?? " "
79- LogManager . shared. log ( category: . general , message: " Notification - Title: \( title) , Body: \( body) " )
93+ LogManager . shared. log ( category: . apns , message: " Notification - Title: \( title) , Body: \( body) " )
8094 }
8195
8296 // Handle silent notification (content-available)
8397 if let contentAvailable = aps [ " content-available " ] as? Int , contentAvailable == 1 {
8498 // This is a silent push, nothing implemented but logging for now
8599
86100 if let commandStatus = userInfo [ " command_status " ] as? String {
87- LogManager . shared. log ( category: . general , message: " Command status: \( commandStatus) " )
101+ LogManager . shared. log ( category: . apns , message: " Command status: \( commandStatus) " )
88102 }
89103
90104 if let commandType = userInfo [ " command_type " ] as? String {
91- LogManager . shared. log ( category: . general , message: " Command type: \( commandType) " )
105+ LogManager . shared. log ( category: . apns , message: " Command type: \( commandType) " )
92106 }
93107 }
94108 }
@@ -97,6 +111,12 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
97111 completionHandler ( . newData)
98112 }
99113
114+ // MARK: - URL handling
115+
116+ // Note: with scene-based lifecycle (iOS 13+), URLs are delivered to
117+ // SceneDelegate.scene(_:openURLContexts:) — not here. The scene delegate
118+ // handles <urlScheme>://la-tap for Live Activity tap navigation.
119+
100120 // MARK: UISceneSession Lifecycle
101121
102122 func application( _: UIApplication , willFinishLaunchingWithOptions _: [ UIApplication . LaunchOptionsKey : Any ] ? ) -> Bool {
@@ -110,7 +130,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
110130 func application( _: UIApplication , configurationForConnecting connectingSceneSession: UISceneSession , options _: UIScene . ConnectionOptions ) -> UISceneConfiguration {
111131 // Called when a new scene session is being created.
112132 // Use this method to select a configuration to create the new scene with.
113- return UISceneConfiguration ( name: " Default Configuration " , sessionRole: connectingSceneSession. role)
133+ UISceneConfiguration ( name: " Default Configuration " , sessionRole: connectingSceneSession. role)
114134 }
115135
116136 func application( _: UIApplication , didDiscardSceneSessions _: Set < UISceneSession > ) {
@@ -166,7 +186,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
166186
167187 func userNotificationCenter( _: UNUserNotificationCenter , didReceive response: UNNotificationResponse , withCompletionHandler completionHandler: @escaping ( ) -> Void ) {
168188 if response. actionIdentifier == " OPEN_APP_ACTION " {
169- if let window = window {
189+ if let window {
170190 window. rootViewController? . dismiss ( animated: true , completion: nil )
171191 window. rootViewController? . present ( MainViewController ( ) , animated: true , completion: nil )
172192 }
0 commit comments