SwiftUI App Protocol and Remote Notifications

I am trying to bring CloudKit syncing to a new SwiftUI app using the new App protocol and have not found a way to listen for remote notifications. Is this possible with the new updates to SwiftUI this year or is this currently an AppDelegate thing only?

Accepted Reply

Hi CracchioloNick,

If your app needs to use traditional App Delegate methods for these types of lifecycle events, you can use the NSApplicationDelegateAdaptor or UIApplicationDelegateAdaptor property wrappers to supply a type that should handle those delegate methods.

You can use it like this:

Code Block swift
@main
struct MyApp: App {
@UIApplicationDelegateAdaptor private var appDelegate: AppDelegate
var body: some Scene {
WindowGroup {
RootView()
}
}
}
class AppDelegate: NSObject, UIApplicationDelegate {
}


With this declaration, a single instance of your App Delegate class will be created to handle any of the delegate methods that it implements, including push notification callbacks and/or CloudKit sharing invitations.
  • When attempting to build a Multiplatform App, for example, the WWDC21 Fruta App, and attempting to add the @UIApplicationDelegateAdapter, there is an error: "UIKit is not available when building for macOS. Consider using #if !os(macOS) to conditionally import this framework."

    However, this is required in order to add remote notifications, among other features. What do we do to add UI Kit and the necessary UIApplicationDelegateAdapter in a Multiplatform app?

  • @cyclic did you find a solution to catalyst?

Add a Comment

Replies

Hi CracchioloNick,

If your app needs to use traditional App Delegate methods for these types of lifecycle events, you can use the NSApplicationDelegateAdaptor or UIApplicationDelegateAdaptor property wrappers to supply a type that should handle those delegate methods.

You can use it like this:

Code Block swift
@main
struct MyApp: App {
@UIApplicationDelegateAdaptor private var appDelegate: AppDelegate
var body: some Scene {
WindowGroup {
RootView()
}
}
}
class AppDelegate: NSObject, UIApplicationDelegate {
}


With this declaration, a single instance of your App Delegate class will be created to handle any of the delegate methods that it implements, including push notification callbacks and/or CloudKit sharing invitations.
  • When attempting to build a Multiplatform App, for example, the WWDC21 Fruta App, and attempting to add the @UIApplicationDelegateAdapter, there is an error: "UIKit is not available when building for macOS. Consider using #if !os(macOS) to conditionally import this framework."

    However, this is required in order to add remote notifications, among other features. What do we do to add UI Kit and the necessary UIApplicationDelegateAdapter in a Multiplatform app?

  • @cyclic did you find a solution to catalyst?

Add a Comment
Awesome! I didn't see these. Thank you for your help!
I saw the reply from the Frameworks Engineer, however it doesn't appear that all delegate callbacks proper functionally. There's a related question with not much help - https://developer.apple.com/forums/thread/669962

The provided solutions absolutely do NOT work. The only delegate method that gets called this way is didFinishLaunchingWithOptions. That's fine and all, but what if you need to register for push notifications?? Any real app needs the token to send to a server so it can send out pushes to the user.

Seriously, this is very messed up.

  • What doesn't work? If you add the @UIApplicationDelegateAdaptor private var appDelegate: AppDelegate entry to your App, and then create an AppDelegate.swift file that implements NSObject and UIApplicationDelegate then the push notification delegate methods will get called.

    Inside the application(_:didFinishLaunchingWithOptions:) you still have to then register for notifications like normal.

Add a Comment

Neither didRegisterForRemoteNotificationsWithDeviceToken, nor didFailToRegisterForRemoteNotificationsWithError gets called. There is a message in logs "Registered for push notifications with token: <...>", which probably means registration itself succeeds. Push notifications capability is added, certificates are in place, I am testing on device, not sim, but AppDelegate's methods for pushes are just not called. didFinishLaunchingWithOptions is called normally btw, which means my UIApplicationDelegateAdaptor is ok. I am using xcode Version 13.2.1 and ios 15.2.

Here is how I subscribe to pushes:

UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge]) { (granted, _) in
      NSLog("PUSH NOTIFICATION PERMISSION GRANTED: \(granted)")
      guard granted else { return }
      DispatchQueue.main.async {
        UIApplication.shared.registerForRemoteNotifications()
      }
    }

Here are method signatures:

func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) { }
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) { }

I need to receive device token to send to server, please help

  • EDIT!!! My apologies, I found out the problem is AzureNotificationHubs-iOS pod being in project. I don't use it for now, but the very fact that it is there, breaks delegate method calls. Does anybody maybe know how to restore the delegate calls while still keeping the azure?

  • AzureNotificationHubs-iOS uses swizzling that is why standard delegate methods don't get called. Microsoft documentation says to "Add the NHAppDelegateForwarderEnabled key [to plist] and set the value to 0" and it works. With this key in place swizzling is not used and delegate methods work as expected.

Add a Comment