支持 iOS 12 和 13 时的 AppDelegate 和 SceneDelegate

Ted*_*y K 20 ios appdelegate swift uiscenedelegate

我需要支持 iOS 12 和 iOS 13。

我应该在AppDelegate和之间复制代码SceneDelegate吗?

例如:

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
}
Run Code Online (Sandbox Code Playgroud)

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
}
Run Code Online (Sandbox Code Playgroud)

如果我不这样做,在 1 个版本中我最终会出现黑屏,但是如果我这样做并以 的viewDidLoad方法打印,HomeViewController我可以看到它被调用了两次。

我更新了我的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
}
Run Code Online (Sandbox Code Playgroud)

mat*_*att 23

您确实需要复制代码,但需要确保它仅在正确的系统上运行。在 iOS 13 中,您不希望该应用程序委托didFinishLaunching正文代码运行,因此请使用可用性检查来阻止它。同样,使用可用性从 iOS 12 中隐藏窗口场景内容。

这是在 iOS 12 和 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
    }
}
Run Code Online (Sandbox Code Playgroud)

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
            }
    }
}
Run Code Online (Sandbox Code Playgroud)

视图控制器.swift

import UIKit
class ViewController : UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        print("view did load")
        self.view.backgroundColor = .green
    }
}
Run Code Online (Sandbox Code Playgroud)

请注意,处理其他重复项(例如应用程序激活)要简单得多,因为如果您支持窗口场景,则不会在 iOS 12 上调用应用程序委托方法。因此问题仅限于这种情况,即您有窗口的地方/ 在启动时执行的根视图控制器操作(例如,没有故事板)。


Pra*_*wad 7

Xcode 11.* 和 Swift 5.*

按照下面给出的步骤之后,您的代码将适用于 iOS 12 和 iOS 13 -

  1. 从 info.plist 文件中删除场景清单
  2. 移除场景委托
  3. 在 AppDelegate 中添加 window 属性
  4. 从 AppDelegate 中删除与场景相关的所有方法(主要是 2 个方法)

希望这对某人有用。快乐编码


Trầ*_*iền 7

这是我的工作。

@在 SceneDelegate.swift 中可用

由于 SceneDelegate 类仅在 iOS 13 及更高版本上可用,因此我们必须告诉编译器仅包含适用于 iOS 13 及更高版本的类。为此,我们将在 SceneDelegate 类声明的正上方添加这一行“@available(iOS 13.0, *)”,如下所示:

import UIKit

@available(iOS 13.0, *)
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
//...
}
Run Code Online (Sandbox Code Playgroud)

@available AppDelegate.swift 中的一些方法

接下来,AppDelegate.swift 中添加了两个新方法,仅支持 iOS 13 及以上版本。我们还将在它们之上添加相同的 @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.
}
Run Code Online (Sandbox Code Playgroud)

将窗口添加回 AppDelegate

如果您现在构建并运行您的应用程序,您将看到深黑屏幕,因为没有初始化 UIWindow。

在 iOS 12 及更早版本中,总是有一个 var 窗口:UIWindow?变量位于 AppDelegate.swft 的顶部。iOS 13 已将此变量移至 SceneDelegate.swift,现在我们要将此变量添加回 AppDelegate。

import UIKit

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
     
    var window: UIWindow?
  
    // ...
}
Run Code Online (Sandbox Code Playgroud)

现在,在 iOS 12 设备上构建并运行您的应用程序,它就可以工作了!

我猜苹果确实希望 iOS 开发者采用并专注于 iOS 13,以至于他们不介意用 Xcode 中的默认设置破坏对 iOS 12 及更早版本的支持。

如果您懒得每次都手动执行这些步骤,您还可以在 Apple 开发者下载门户中下载 Xcode 10.3(需要使用您的 Apple ID 登录),使用它创建一个新的 Xcode 项目,然后使用 Xcode 11 进行编辑。