【问题标题】:AppDelegate and SceneDelegate when supporting iOS 12 and 13支持 iOS 12 和 13 时的 AppDelegate 和 SceneDelegate
【发布时间】:2020-02-12 18:25:12
【问题描述】:

我需要支持 iOS 12 和 iOS 13。

我应该在AppDelegateSceneDelegate 之间复制代码吗?

例如:

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
}

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
}

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

我更新了我的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
}

【问题讨论】:

  • 您也可以完全跳过 SceneDelegate,如果您支持 iOS 12,则无需继承。
  • 请注意,如果您计划构建现代 Catalyst 应用程序,可能需要采用场景代理。 macOS 上的 Segmented bar 等功能需要您采用 Scene Delegate。

标签: ios swift appdelegate uiscenedelegate


【解决方案1】:

您确实需要复制代码,但您需要确保它仅在正确的系统上运行。在 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
    }
}

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

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

【讨论】:

  • 哦,我明白了,所以我的didFinishLaunchingWithOptions 上可能有类似@available(iOS, obsoleted: 13) 的东西?
  • 请查看我的更新,我添加了一个在iOS12 中有效的检查,但iOS13 仍然调用它两次。感谢您的帮助。
  • guard #available(iOS 12, *) else { return true } 很愚蠢,因为这与您想要的相反。现在代码可以在 iOS 12 和 iOS 13 中运行,并且不包括需要它的 iOS 11!你需要做的恰恰相反:在 iOS 13 中立即返回 true,否则继续。
  • 为什么不干脆删除SceneDelegate
【解决方案2】:

Xcode 11.* 和 Swift 5.*

按照下面给出的步骤,您的代码将在 iOS 12 和 iOS 13 上正常工作 -

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

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

【讨论】:

    【解决方案3】:

    这是我的工作。

    @available 出 SceneDelegate.swift

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

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

    @available out 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.
    }
    

    将窗口添加回 AppDelegate

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

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

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

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

    我猜 Apple 确实希望 iOS 开发者采用并专注于 iOS 13,只要他们不介意在 Xcode 中使用默认设置中断对 iOS 12 及更早版本的支持。

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

    【讨论】:

      猜你喜欢
      • 2021-08-23
      • 1970-01-01
      • 2019-10-23
      • 2021-08-01
      • 2020-08-17
      • 2020-03-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多