21

我需要支持 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
}

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 版本中我最终会出现黑屏,但如果我这样做并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
}
4

3 回答 3

27

您确实需要复制代码,但您需要确保它仅在正确的系统上运行。在 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 上调用应用程序委托方法。所以问题仅限于这种情况,即您有窗口/ 在启动时执行的根视图控制器操作(例如,没有情节提要)。

于 2019-10-16T03:51:54.537 回答
7

Xcode 11.* 和 Swift 5.*

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

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

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

于 2020-01-27T12:34:23.737 回答
5

这是我的工作。

@available 出 SceneDelegate.swift

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

import UIKit

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

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

将窗口添加回 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 对其进行编辑。

于 2020-06-26T02:05:25.103 回答