10

Here is a simple AppDelegate that I have made:

import SwiftUI

class AppDelegate: UIResponder, UIApplicationDelegate {

    private func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: NSDictionary?) -> Bool {
        print("application")
        // first launch
        // this method is called only on first launch when app was closed / killed
        return true
    }

    private func applicationWillEnterForeground(application: UIApplication) -> Bool{
        print("applicationWillEnterForeground")
        // app will enter in foreground
        // this method is called on first launch when app was closed / killed and every time app is reopened or change status from background to foreground (ex. mobile call)
        return true
    }

    private func applicationDidBecomeActive(application: UIApplication) -> Bool {
        print("applicationDidBecomeActive")
        // app becomes active
        // this method is called on first launch when app was closed / killed and every time app is reopened or change status from background to foreground (ex. mobile call)
        return true
    }
}

@main
struct CouponDeckApp: App {
    @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
    @Environment(\.scenePhase) private var scenePhase
    var body: some Scene {
        WindowGroup {
            AppContentView()
                
        }
    }
}

The AppDelegate doesn't seem to be calling any of its functions, though. It should be running them at 3 places, but none are running. Why is this happening, and how do I fix it?

Kunal Katiyar
  • 304
  • 2
  • 15
  • 1
    In the SwiftUI lifecycle, the `applicationWillEnterForeground` and `applicationDidBecomeActive` don't seem to get called (however, you also don't have the correct method signatures for them -- use autocomplete to see what they actually should be). @swiftPunk already gave you an answer on one of your questions asking the same thing showing you how to do this in SwiftUI. I also linked to this information for you when you first asked here: https://stackoverflow.com/questions/68716601/swiftui-initialization-of-app-not-working – jnpdx Aug 22 '21 at 19:10
  • It seems you are missing some point! you are asking same question in deferent forms! – ios coder Aug 22 '21 at 19:19
  • @jnpdx in the Apple Documentation, I seem to be correct. The names match perfectly. – Kunal Katiyar Aug 22 '21 at 19:29
  • @swiftPunk that's because none of the answers anyone has given to me have worked. – Kunal Katiyar Aug 22 '21 at 19:30
  • @KunalKatiyar no, they don't. Check the return types. – jnpdx Aug 22 '21 at 19:39
  • @jnpdx even by removing the return types, it still doesn't work. – Kunal Katiyar Aug 22 '21 at 19:40
  • I already said that those methods don’t work in the SwiftUI lifecycle. @swiftPunk and I have both shown you how to do this in SwiftUI – jnpdx Aug 22 '21 at 19:49
  • I feel your pain jnpdx – workingdog support Ukraine Aug 23 '21 at 00:44

2 Answers2

23

You've marked your app with @main which makes it app entry point.

Not all methods of app delegate will work with UIApplicationDelegateAdaptor, like here applicationWillEnterForeground applicationDidBecomeActive won't be called.

Instead you're supposed to use publishers inside SwiftUI view, like this:

.onReceive(NotificationCenter.default.publisher(for: UIApplication.didBecomeActiveNotification)) { _ in
    print("applicationDidBecomeActive")
}
.onReceive(NotificationCenter.default.publisher(for: UIApplication.willEnterForegroundNotification)) { _ in
    print("applicationWillEnterForeground")
}

An other problem with your AppDelegate is that it doesn't have needed methods signature. When you're adding new method, don't paste it from somewhere, instead type a couple of letters from method name and let Xcode finish the rest. In your case if you have your signature correct, private would be an error reported by Xcode.

If you still wanna get them inside your delegate for some reason, you need to move @main to AppDelegate, and initialize your SwiftUI view with UIHostingController like it was back done in SwiftUI 1:

@main
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?
    
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        let window = UIWindow()
        self.window = window
        window.rootViewController = UIHostingController(rootView: ContentView())
        window.makeKeyAndVisible()
        return true
    }
    
    func applicationWillEnterForeground(_ application: UIApplication) {
        print("applicationWillEnterForeground")
    }
    
    func applicationDidBecomeActive(_ application: UIApplication) {
        print("applicationDidBecomeActive")
    }
}

Also you need to update Info.plist, set enable multiple windows to NO:

Phil Dukhov
  • 67,741
  • 15
  • 184
  • 220
  • How do you edit the Info.plist file like that? Also, on every example I've seen, people can use `AppDelegate` and `App` together using `UIApplicationDelegateAdaptor` . – Kunal Katiyar Aug 24 '21 at 21:03
  • @KunalKatiyar I was not particularly correct about `UIApplicationDelegateAdaptor`, check out updated answer – Phil Dukhov Aug 25 '21 at 09:40
  • It probably works, but the real problem (as pointed out in one of my other questions) is that `print` statements don't work the second time! When I ran another function that actually edits stuff, it worked perfectly! But I'll accept your answer because it technically works. – Kunal Katiyar Sep 06 '21 at 00:02
  • Had to upvote for the nice tips that were included. Thank-you. – Marcy Jan 16 '23 at 16:26
0

Use the SceneDelegate file instead.

Add it in this method:

func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { }
vimuth
  • 5,064
  • 33
  • 79
  • 116
Cristy
  • 24
  • 4