AppDelegate and SceneDelegate when supporting iOS 12 and 13

Related searches

I need to support iOS 12 and iOS 13.

Should I be duplicating code between AppDelegate and SceneDelegate?

For example:

func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
    guard let windowScene = (scene as? UIWindowScene) else { return }
    let window = UIWindow(windowScene: windowScene)

    window.rootViewController = HomeViewController()
    window.makeKeyAndVisible()

    self.window = window
}

and

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    let window = UIWindow(frame: UIScreen.main.bounds)
    window.rootViewController = HomeViewController()
    window.makeKeyAndVisible()

    self.window = window

    return true
}

If I don't do this, in 1 version I end up with a black screen, but if I do and print in the viewDidLoad method of HomeViewController I can see it is called twice.

I update my didFinishLaunchingWithOptions and I can see in iOS13 it is still called twice.

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {

    guard #available(iOS 12, *) else { return true }

    let window = UIWindow(frame: UIScreen.main.bounds)
    window.rootViewController = HomeViewController()
    window.makeKeyAndVisible()

    self.window = window

    return true
}

You do need to duplicate the code but you need to make sure it runs only on the correct system. In iOS 13 you don’t want that application delegate didFinishLaunching body code to run, so use an availability check to prevent it. In the same way, use availability to hide the window scene stuff from iOS 12.

Here's the basic sketch of a solution that runs correctly on both iOS 12 and iOS 13:

AppDelegate.Swift
import UIKit
@UIApplicationMain
class AppDelegate : UIResponder, UIApplicationDelegate {
    var window : UIWindow?
    func application(_ application: UIApplication,
        didFinishLaunchingWithOptions 
        launchOptions: [UIApplication.LaunchOptionsKey : Any]?)
        -> Bool {
            if #available(iOS 13, *) {
                // do only pure app launch stuff, not interface stuff
            } else {
                self.window = UIWindow()
                let vc = ViewController()
                self.window!.rootViewController = vc
                self.window!.makeKeyAndVisible()
                self.window!.backgroundColor = .red
            }
            return true
    }
}
SceneDelegate.swift
import UIKit
@available(iOS 13.0, *)
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
    var window : UIWindow?
    func scene(_ scene: UIScene,
        willConnectTo session: UISceneSession,
        options connectionOptions: UIScene.ConnectionOptions) {
            if let windowScene = scene as? UIWindowScene {
                self.window = UIWindow(windowScene: windowScene) 
                let vc = ViewController()                      
                self.window!.rootViewController = vc             
                self.window!.makeKeyAndVisible()                 
                self.window!.backgroundColor = .red
            }
    }
}
ViewController.swift
import UIKit
class ViewController : UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        print("view did load")
        self.view.backgroundColor = .green
    }
}

Note that dealing with other duplicates, such as the application activating, is much simpler because if you support window scenes the application delegate method won't be called on iOS 12. So the problem is confined to this one situation, namely where you have window / root view controller manipulations to perform at launch (e.g. no storyboard).

Create a new iOS12 project in Xcode11, If you want to support iOS prior to iOS 13, there are a few steps you need to do. many things that are not compatible with iOS 12, e.g. SceneDelegate.swift . In AppDelegate.swift there are two new UIApplicationDelegate� The AppDelegate class of your app adopts the UIApplicationDelegate protocol, which is part of the UIKit framework. The app delegate’s role changes from iOS 12 to iOS 13, as we’ll soon discover. Here’s what you typically use the app delegate for on iOS 12: Set up the first view controller of your app, called the root view controller

Xcode 11.* and Swift 5.*

Follow the steps given below after that your code will work fine for both iOS 12 and iOS 13 -

  1. Remove the scene manifest from info.plist file
  2. Remove scene delegate
  3. Add window property inside the AppDelegate
  4. Remove all the methods(2 methods mostly) related to the scene from AppDelegate

Hope this will work for someone. Happy Coding 🤓

Allow app created in Xcode 11 to run on iOS 12 and lower, As the SceneDelegate class is only available on iOS 13 and above, we added in AppDelegate.swift, which only supports iOS 13 and above. In iOS 13 and later—A UISceneDelegate object. In iOS 12 and earlier—The UIApplicationDelegate object. You can support both types of delegate objects, but UIKit always uses scene delegate objects when they are available. UIKit notifies only the scene delegate associated with the specific scene that is entering the foreground.

This is work on me.

@available out the SceneDelegate.swift

As the SceneDelegate class is only available on iOS 13 and above, we have to tell the compiler to only include the class for iOS 13 and above. To do this, we will add this line "@available(iOS 13.0, *)" right above the SceneDelegate class declaration like this :

import UIKit

@available(iOS 13.0, *)
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
//...
}

@available out some methods in AppDelegate.swift

Next, there are two new methods added in AppDelegate.swift, which only supports iOS 13 and above. We will add the same @available(iOS 13.0, *) on top of them as well :

// AppDelegate.swift

@available(iOS 13.0, *)
func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
    // Called when a new scene session is being created.
    // Use this method to select a configuration to create the new scene with.
    return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
}

@available(iOS 13.0, *)
func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set<UISceneSession>) {
    // Called when the user discards a scene session.
    // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
    // Use this method to release any resources that were specific to the discarded scenes, as they will not return.
}

Add back the window to AppDelegate

If you build and run your app now, you will get a dark black screen, because there's no UIWindow initialized.

In iOS 12 and older, there's always a var window: UIWindow? variable located at the top of AppDelegate.swft. iOS 13 has moved this variable to SceneDelegate.swift, and now we are going to add back this variable to AppDelegate.

import UIKit

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
     
    var window: UIWindow?
  
    // ...
}

Now Build and run your app on an iOS 12 devices, and it works!

I guess Apple really wants iOS developers to adopt and focus on iOS 13, to the extent that they don't mind breaking support for iOS 12 and older with default settings in Xcode.

If you are lazy to do these step manually every time, you can also download Xcode 10.3 in the Apple's developer download portal (require sign in with your Apple ID), create a new Xcode project using it, and then edit it using Xcode 11.

How to work with SceneDelegate in iOS 12, UIApplication notifications. Notifications still trigger in iOS 13 if adopting SceneDelegate Get sceneDelegate from AppDelegate Read more. https:// www.donnywals.com/add-ios-12-support-to-a-new-xcode-11-project/� Now you can run your App without Storyboard on iOS 13 or older. Extra step What’s more, if you’re still supporting iOS 12 or below, you’ll need to update your AppDelegate since that’s the

XCode 11 with IOS 12 issue, The app installs and runs properly on my ios 13 devices, but when I tried to install it many things that are not compatible with iOS 12, e.g. SceneDelegate.swift. AppDelegate.swift looks nothing like it ought to for support iOS 12 and below. Photo by Mika Baumeister on Unsplash. During WWDC 2020, SwiftUI got its own app-lifecycle in a bid to get away from UIKit’s AppDelegate and SceneDelegate. To do so, iOS 14 now offers an App

Add iOS 12 support to a new Xcode 11 Project – Donny Wals, You will first learn how to use the SceneDelegate for iOS 13 and up, and use the AppDelegate as a fallback for older versions of iOS. After that� While you should embrace using scenes when your app is run under iOS 13 and later, you can fully opt out while you still support iOS 12 or earlier. First, completely remove the “Application Scene Manifest” entry from Info.plist. If there is a scene delegate class, remove it.

Multi-window support is happening. Next time you create a new Xcode project you’ll see your AppDelegate has split in two: AppDelegate.swift and SceneDelegate.swift. This is a result of the new multi-window support that landed with iPadOS, and effectively splits the work of the app delegate in two. From iOS 13 onwards, your app delegate should:

Comments
  • See stackoverflow.com/a/58208876/1226963
  • You can also just skip the SceneDelegate completely, there's no inherit need for it if you're supporting iOS 12.
  • oh I see, so perhaps something like @available(iOS, obsoleted: 13) on my didFinishLaunchingWithOptions?
  • Please see my update, I added a check which works in iOS12 but iOS13 is still calling it twice. Appreciate your help.
  • Well saying guard #available(iOS 12, *) else { return true } is silly, as that does the opposite of what you want. Now the code runs in both iOS 12 and iOS 13 and excludes iOS 11, which needs it! What you need to do is the opposite of that: return true immediately in iOS 13 but proceed otherwise.
  • Downloadable project here github.com/mattneub/Programming-iOS-Book-Examples/tree/master/…