支持iOS 12和13时的AppDelegate和SceneDelegate

时间:2019-10-16 03:36:32

标签: ios swift appdelegate uiscenedelegate

我需要支持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个版本中,我最终会出现黑屏,但是如果这样做并以viewDidLoad的{​​{1}}方法进行打印,则可以看到它被两次调用。

我更新了HomeViewController,在didFinishLaunchingWithOptions中看到它仍然被调用两次。

iOS13

3 个答案:

答案 0 :(得分:5)

Xcode 11. *和Swift 5。*

请按照以下步骤操作,之后您的代码就可以在iOS 12和iOS 13上正常工作-

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

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

答案 1 :(得分:2)

这是我的工作。

@ SceneDelegate.swift可用

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

import UIKit

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

@在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设备上构建并运行您的应用程序,它可以正常工作!

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

如果您不愿意每次手动执行这些步骤,也可以在Apple开发人员下载门户中下载Xcode 10.3(要求使用Apple ID登录),使用它创建一个新的Xcode项目,然后使用Xcode 11。

答案 2 :(得分: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上调用应用程序委托方法。因此,问题仅限于这种情况,即您可以在启动时执行窗口/根视图控制器操作(例如,没有情节提要)。