简体   繁体   English

支持 iOS 12 和 13 时的 AppDelegate 和 SceneDelegate

[英]AppDelegate and SceneDelegate when supporting iOS 12 and 13

I need to support iOS 12 and iOS 13.我需要支持 iOS 12 和 iOS 13。

Should I be duplicating code between AppDelegate and SceneDelegate ?我应该在AppDelegateSceneDelegate之间复制代码吗?

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.如果我不这样做,在 1 版本中我最终会出现黑屏,但如果我这样做并在HomeViewControllerviewDidLoad方法中打印,我可以看到它被调用了两次。

I update my didFinishLaunchingWithOptions and I can see in iOS13 it is still called twice.我更新了我的didFinishLaunchingWithOptions并且我可以在iOS13中看到它仍然被调用了两次。

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.在 iOS 13 中,您不希望应用程序委托didFinishLaunching主体代码运行,因此使用可用性检查来阻止它。 In the same way, use availability to hide the window scene stuff from iOS 12.同样,使用可用性从 iOS 12 中隐藏 window 场景内容。

Here's the basic sketch of a solution that runs correctly on both iOS 12 and iOS 13:这是在 iOS 12 和 iOS 13 上正确运行的解决方案的基本草图:

AppDelegate.Swift 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 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 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 (eg no storyboard).请注意,处理其他重复项(例如应用程序激活)要简单得多,因为如果您支持 window 场景,则不会在 iOS 12 上调用应用程序委托方法。所以问题仅限于这种情况,即您有 Z05B8C735296FBF2FZDE4C1 / 根视图 controller 在启动时执行的操作(例如,没有情节提要)。

Xcode 11.* and Swift 5.* Xcode 11.* 和 Swift 5.*

Follow the steps given below after that your code will work fine for both iOS 12 and iOS 13 -按照下面给出的步骤,您的代码将适用于 iOS 12 和 iOS 13 -

  1. Remove the scene manifest from info.plist file从 info.plist 文件中删除场景清单
  2. Remove scene delegate移除场景委托
  3. Add window property inside the AppDelegate在 AppDelegate 中添加 window 属性
  4. Remove all the methods(2 methods mostly) related to the scene from AppDelegate从 AppDelegate 中移除所有与场景相关的方法(主要是 2 种方法)

Hope this will work for someone.希望这对某人有用。 Happy Coding快乐编码

This is work on me.这是我的工作。

@available out the SceneDelegate.swift @提供了 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. 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:为此,我们将在 SceneDelegate class 声明的正上方添加这一行“@available(iOS 13.0, *)”,如下所示:

import UIKit

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

@available out some methods in AppDelegate.swift @在 AppDelegate.swift 中提供一些方法

Next, there are two new methods added in AppDelegate.swift, which only supports iOS 13 and above.接下来在AppDelegate.swift中新增两个方法,仅支持iOS 13及以上。 We will add the same @available(iOS 13.0, *) on top of them as well:我们还将在它们之上添加相同的 @available(iOS 13.0, *) :

// 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将 window 添加回 AppDelegate

If you build and run your app now, you will get a dark black screen, because there's no UIWindow initialized.如果您现在构建并运行您的应用程序,您将看到黑屏,因为没有初始化 UIWindow。

In iOS 12 and older, there's always a var window: UIWindow?在 iOS 12 和更早版本中,总是有一个 var window: UIWindow? variable located at the top of AppDelegate.swft.位于 AppDelegate.swft 顶部的变量。 iOS 13 has moved this variable to SceneDelegate.swift, and now we are going to add back this variable to AppDelegate. iOS 13 已将此变量移至 SceneDelegate.swift,现在我们将将此变量添加回 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!现在在 iOS 12 设备上构建并运行您的应用程序,它可以工作了!

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. 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. 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.

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM