import UIKit @main final class AppDelegate: UIResponder, UIApplicationDelegate { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool { Badge.registerBackgroundRefresh() Offline.shared.resume() Outbox.watch() return true } /// A download kept going while the app was closed has finished (#425): the system launched us /// to hand it over, and waits on this handler. func application(_ application: UIApplication, handleEventsForBackgroundURLSession identifier: String, completionHandler: @escaping () -> Void) { Offline.shared.backgroundCompletion = completionHandler Offline.shared.resume() } /// Apple's address for this phone's copy of the app (#433), handed to the page to register. func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) { Push.token = deviceToken.map { String(format: "%02x", $0) }.joined() } /// ipx's count, arriving with the app closed (#433): `content-available` wakes the app for a /// moment, which the badge alone does not, so the widget's count follows the icon's (#428). func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) { guard let n = (userInfo["aps"] as? [String: Any])?["badge"] as? Int else { completionHandler(.noData) return } WidgetFeed.update { $0.unread = n } completionHandler(.newData) } func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) { NSLog("ipx: push registration: %@", error.localizedDescription) } } /// The one window. iOS will not run an app that has not adopted scenes, and a CarPlay app would /// be a second scene beside this one. final class SceneDelegate: UIResponder, UIWindowSceneDelegate { var window: UIWindow? func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options: UIScene.ConnectionOptions) { guard let scene = scene as? UIWindowScene else { return } let window = UIWindow(windowScene: scene) window.rootViewController = WebViewController() window.makeKeyAndVisible() self.window = window } /// iOS wants the request made as the app leaves, with the user's last look at the list; the /// one made on coming forward stays for a run that was cut short. func sceneDidEnterBackground(_ scene: UIScene) { Badge.scheduleBackgroundRefresh() } func sceneDidBecomeActive(_ scene: UIScene) { Badge.requestPermission() Badge.scheduleBackgroundRefresh() Task { await Outbox.flush() await Badge.refresh() } } }