添加 SceneDelegate 并更新 Info.plist 后黑屏 [英] Black screen after adding SceneDelegate and updating Info.plist

查看:72
本文介绍了添加 SceneDelegate 并更新 Info.plist 后黑屏的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前正在使用 Xcode 11 获得空白屏幕,目标 iOS 13.0(该应用程序适用于所有低于 iOS 12.1 到 12.4 的版本),我想让我的应用程序同时适用于 12.1 和 13.0 以上的 iOS 用户.尽管将以下 UIWindowSceneDelegate 添加到我现有的项目和 App Manifest 中,但还是出现了空白屏幕:

添加应用清单文件

导入 UIKit导入 SwiftUI@available(iOS 13.0, *)类 SceneDelegate: UIResponder, UIWindowSceneDelegate {变量窗口:UIWindow?func 场景(_ 场景:UIScene,willConnectTo 会话:UISceneSession,选项 connectionOptions:UIScene.ConnectionOptions){//保护 let _ = (scene as?UIWindowScene) else { return }让用户 = UserDefaults.standard.object(forKey: "defaultsuserid")让 userSelfIdent = UserDefaults.standard.object(forKey: "userinitialident")如果让 windowScene = 场景为?UIWindowScene {让 internalWindow = UIWindow(windowScene: windowScene)如果(用户!= nil && userSelfIdent != nil){让 mainstoryboard:UIStoryboard = UIStoryboard(name: "Main", bundle: nil)让 newViewcontroller:UIViewController = mainstoryboard.instantiateViewController(withIdentifier: "swrevealviewcontroller") as!SWRevealViewControllerinternalWindow.rootViewController = newViewControllerself.window = internalWindowinternalWindow.makeKeyAndVisible()}别的 {守卫让_ =(场景为?UIWindowScene)其他{返回}}}}

以下是我的 AppDelegate,它首先被调用并执行 didFinishLaunchWithOptions 方法.我想知道如何仅当我的 Target ios 小于 13.0 时才调用此方法并在 13.0 之后调用 SceneDelegate 方法来初始化我的 rootViewController?

@UIApplicationMain类 AppDelegate: UIResponder, UIApplicationDelegate {变量窗口:UIWindow?@available(iOS 13.0, *)func 应用程序(_ 应用程序:UIApplication,configurationForConnectingconnectingSceneSession: UISceneSession,选项:UIScene.ConnectionOptions) ->UISceneConfiguration {返回 UISceneConfiguration(名称:默认配置",sessionRole:connectingSceneSession.role)}@available(iOS 13.0, *)func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) {}@available(iOS 13.0, *)func 场景(_ 场景:UIScene,willConnectTo 会话:UISceneSession,选项 connectionOptions:UIScene.ConnectionOptions){守卫让_ =(场景为?UIWindowScene)其他{返回}如果(用户!= nil && userSelfIdent != nil){让 mainstoryboard:UIStoryboard = UIStoryboard(name: "Main", bundle: nil)让 newViewcontroller:UIViewController = mainstoryboard.instantiateViewController(withIdentifier: "swrevealviewcontroller") as!SWRevealViewControllerself.window?.rootViewController = newViewController}}func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) ->布尔{//在应用程序启动后覆盖自定义点.Thread.sleep(forTimeInterval: 3.0)UINavigationBar.appearance().barTintColor = UIColor(red:0.08, green:0.23, blue:0.62, alpha:1.0)如果(用户!= nil && userSelfIdent != nil){让 mainstoryboard:UIStoryboard = UIStoryboard(name: "Main", bundle: nil)让 newViewcontroller:UIViewController = mainstoryboard.instantiateViewController(withIdentifier: "swrevealviewcontroller") as!SWRevealViewControllerself.window?.rootViewController = newViewController}返回真}func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {让 defaultUserID = UserDefaults.standard.string(forKey: "defaultUserID")}func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {开关(application.applicationState){案例 UIApplicationState.active:做点什么案例 UIApplicationState.background, UIApplicationState.inactive:让 mainstoryboard:UIStoryboard = UIStoryboard(name: "Main", bundle: nil)让 newViewcontroller = mainstoryboard.instantiateViewController(withIdentifier: "swrevealviewcontroller") as!SWRevealViewControllerself.window?.rootViewController = newViewController}}

解决方案

这里有几个问题.请务必阅读与应用生命周期相关的文档,其中说明了在 iOS 13 下调用的内容以及在 iOS 12 下调用的内容.

您可能还想查看我的支持 iOS 12 和 13 的单视图应用模板.>

查看您的代码,这里是问题的摘要:

应用程序委托:

  • 如果应用在 iOS 12 或更早版本下运行,您应该只设置主窗口和根视图控制器.您需要在运行时检查这一点.
  • func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) 方法不应在应用程序委托中.
  • 没有直接关系,但在应用启动时从不休眠.删除 Thread.sleep(forTimeInterval: 3.0) 行.用户希望使用您的应用程序,而不是盯着启动屏幕的时间过长.在应用启动时阻塞主线程可能会导致您的应用被终止.

场景委托:

  • 这基本上没问题,但没有理由 guard let _ = (scene as? UIWindowScene) else { return } 行,特别是因为它在 if let 已经进行了检查.
  • 您似乎没有使用 SwiftUI,因此请删除该导入.

我会将您的应用委托更新为更像这样:

@UIApplicationMain类 AppDelegate: UIResponder, UIApplicationDelegate {变量窗口:UIWindow?func application(_ application: UIApplication, willFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil) ->布尔{UINavigationBar.appearance().barTintColor = UIColor(red:0.08, green:0.23, blue:0.62, alpha:1.0)如果#available(iOS 13.0,*){//在 iOS 13 中,设置是在 SceneDelegate 中完成的} 别的 {让窗口 = UIWindow(frame: UIScreen.main.bounds)self.window = 窗口如果(用户!= nil && userSelfIdent != nil){让 mainstoryboard:UIStoryboard = UIStoryboard(name: "Main", bundle: nil)让 newViewcontroller:UIViewController = mainstoryboard.instantiateViewController(withIdentifier: "swrevealviewcontroller") 作为!SWRevealViewControllerwindow.rootViewController = newViewController}}返回真}func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) ->布尔{如果#available(iOS 13.0,*){//在 iOS 13 中,设置是在 SceneDelegate 中完成的} 别的 {self.window?.makeKeyAndVisible()}返回真}func applicationWillResignActive(_ application: UIApplication) {//在 iOS 13 下未调用 - 请参阅 SceneDelegate sceneWillResignActive}func applicationDidEnterBackground(_ application: UIApplication) {//在 iOS 13 下未调用 - 请参阅 SceneDelegate sceneDidEnterBackground}func applicationWillEnterForeground(_ application: UIApplication) {//在 iOS 13 下未调用 - 请参阅 SceneDelegate sceneWillEnterForeground}func applicationDidBecomeActive(_ application: UIApplication) {//在 iOS 13 下未调用 - 请参阅 SceneDelegate sceneDidBecomeActive}//MARK: UISceneSession 生命周期@available(iOS 13.0, *)func application(_ application: UIApplication, configurationForConnecting connectedSceneSession: UISceneSession, options: UIScene.ConnectionOptions) ->UISceneConfiguration {//在创建新场景会话时调用.//使用此方法选择一个配置来创建新场景.返回 UISceneConfiguration(名称:默认配置",sessionRole:connectingSceneSession.role)}@available(iOS 13.0, *)func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) {//当用户丢弃场景会话时调用.//如果在应用程序未运行时丢弃了任何会话,它将在 application:didFinishLaunchingWithOptions 后不久调用.//使用此方法释放特定于丢弃场景的任何资源,因为它们不会返回.}}

你的场景代理可能是这样的:

@available(iOS 13.0, *)类 SceneDelegate: UIResponder, UIWindowSceneDelegate {变量窗口:UIWindow?func 场景(_ 场景:UIScene,willConnectTo 会话:UISceneSession,选项 connectionOptions:UIScene.ConnectionOptions){守卫让 windowScene = (scene as?UIWindowScene) else { return }让窗口 = UIWindow(windowScene: windowScene)self.window = 窗口如果(用户!= nil && userSelfIdent != nil){让 mainstoryboard:UIStoryboard = UIStoryboard(name: "Main", bundle: nil)让 newViewcontroller:UIViewController = mainstoryboard.instantiateViewController(withIdentifier: "swrevealviewcontroller") 作为!SWRevealViewControllerwindow.rootViewController = newViewControllerwindow.makeKeyAndVisible()}}funcsceneDidDisconnect(_场景:UIScene){//当场景被系统释放时调用.}funcsceneDidBecomeActive(_场景:UIScene){//在 iOS 12 下未调用 - 参见 AppDelegate applicationDidBecomeActive}funcsceneWillResignActive(_场景:UIScene){//在 iOS 12 下未调用 - 请参阅 AppDelegate applicationWillResignActive}funcsceneWillEnterForeground(_场景:UIScene){//在 iOS 12 下未调用 - 参见 AppDelegate applicationWillEnterForeground}funcsceneDidEnterBackground(_场景:UIScene){//在 iOS 12 下未调用 - 请参阅 AppDelegate applicationDidEnterBackground}}

I am currently getting a blank screen with Xcode 11, Target iOS 13.0 (the app works fine with all below versions iOS 12.1 till 12.4), I want to make my App work for both iOS users above 12.1 and also 13.0 currently getting blank screen despite adding the below UIWindowSceneDelegate to my existing project and App Manifest:

adding App Manifest file

import UIKit
    import SwiftUI
    
    @available(iOS 13.0, *)
    class SceneDelegate: UIResponder, UIWindowSceneDelegate {
    
        var window: UIWindow?
    
        func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
          
            //guard let _ = (scene as? UIWindowScene) else { return }
            
            let user  = UserDefaults.standard.object(forKey: "defaultsuserid")
    
            let userSelfIdent  = UserDefaults.standard.object(forKey: "userinitialident")
            
            if let windowScene = scene as? UIWindowScene {
                
                let internalWindow = UIWindow(windowScene: windowScene)
                
                if (user != nil && userSelfIdent != nil){
                     let mainstoryboard:UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
                     let newViewcontroller:UIViewController = mainstoryboard.instantiateViewController(withIdentifier: "swrevealviewcontroller") as! SWRevealViewController
                        internalWindow.rootViewController = newViewcontroller
                        self.window = internalWindow
                        internalWindow.makeKeyAndVisible()
                }else {
                    
                    guard let _ = (scene as? UIWindowScene) else { return }
                }
            }
        }

The following is my AppDelegate which is getting called first and executing the didFinishLaunchWithOptions method. I want to know how can i make this method call only if my Target ios is less than 13.0 and call SceneDelegate method to initialize my rootViewController after 13.0?

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?
    
    
    @available(iOS 13.0, *)
    func application(_ application: UIApplication,
                     configurationForConnecting connectingSceneSession: UISceneSession,
                     options: UIScene.ConnectionOptions) -> UISceneConfiguration {
        return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
    }

    @available(iOS 13.0, *)
    func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set<UISceneSession>) {
      
    }
    


    @available(iOS 13.0, *)
    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
        
        guard let _ = (scene as? UIWindowScene) else { return }
        
        if (user != nil && userSelfIdent != nil){

              let mainstoryboard:UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
              let newViewcontroller:UIViewController = mainstoryboard.instantiateViewController(withIdentifier: "swrevealviewcontroller") as! SWRevealViewController
                self.window?.rootViewController = newViewcontroller
        }
    }
    
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        // Override point for customization after application launch.
        
        Thread.sleep(forTimeInterval: 3.0)
        
        UINavigationBar.appearance().barTintColor = UIColor(red:0.08, green:0.23, blue:0.62, alpha:1.0)
        
        if (user != nil && userSelfIdent != nil){

              let mainstoryboard:UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
              let newViewcontroller:UIViewController = mainstoryboard.instantiateViewController(withIdentifier: "swrevealviewcontroller") as! SWRevealViewController
                self.window?.rootViewController = newViewcontroller
        }
        
        return true
    }
    
    func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
        
        let defaultUserID = UserDefaults.standard.string(forKey: "defaultUserID")
        
       
    }
    
    func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
        
        switch (application.applicationState) {
        case UIApplicationState.active:
            do something
           
        case UIApplicationState.background, UIApplicationState.inactive:
            
            let mainstoryboard:UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
            let newViewcontroller = mainstoryboard.instantiateViewController(withIdentifier: "swrevealviewcontroller") as! SWRevealViewController
            self.window?.rootViewController = newViewcontroller            
        }
    }

解决方案

You have several issues here. It's important to read the documentation related to the app lifecycle which states what is called under iOS 13 and what is called under iOS 12.

You may also want to see my Single View App template that supports iOS 12 and 13.

Looking at your code, here is a summary of the problems:

AppDelegate:

  • You should only setup the main window and the root view controller if the app is being run under iOS 12 or earlier. You need to check this at runtime.
  • The func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) method should not be in the app delegate.
  • Not directly related but never sleep on app startup. Remove the Thread.sleep(forTimeInterval: 3.0) line. Users want to use your app, not stare at the launch screen longer than necessary. And blocking the main thread on app launch can cause your app to be killed.

SceneDelegate:

  • This is mostly fine but there is no reason for the guard let _ = (scene as? UIWindowScene) else { return } line, especially since it is inside an if let that already does that check.
  • You don't appear to be using SwiftUI so remove that import.

I would update your app delegate to be more like this:

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
    var window: UIWindow?

    func application(_ application: UIApplication, willFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool {
        UINavigationBar.appearance().barTintColor = UIColor(red:0.08, green:0.23, blue:0.62, alpha:1.0)

        if #available(iOS 13.0, *) {
            // In iOS 13 setup is done in SceneDelegate
        } else {
            let window = UIWindow(frame: UIScreen.main.bounds)
            self.window = window

            if (user != nil && userSelfIdent != nil){
                let mainstoryboard:UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
                let newViewcontroller:UIViewController = mainstoryboard.instantiateViewController(withIdentifier: "swrevealviewcontroller") as! SWRevealViewController
                window.rootViewController = newViewcontroller
            }
        }

        return true
    }

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        if #available(iOS 13.0, *) {
            // In iOS 13 setup is done in SceneDelegate
        } else {
            self.window?.makeKeyAndVisible()
        }

        return true
    }

    func applicationWillResignActive(_ application: UIApplication) {
        // Not called under iOS 13 - See SceneDelegate sceneWillResignActive
    }

    func applicationDidEnterBackground(_ application: UIApplication) {
        // Not called under iOS 13 - See SceneDelegate sceneDidEnterBackground
    }

    func applicationWillEnterForeground(_ application: UIApplication) {
        // Not called under iOS 13 - See SceneDelegate sceneWillEnterForeground
    }

    func applicationDidBecomeActive(_ application: UIApplication) {
        // Not called under iOS 13 - See SceneDelegate sceneDidBecomeActive
    }

    // MARK: UISceneSession Lifecycle

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

Your scene delegate could be like:

@available(iOS 13.0, *)
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
    var window: UIWindow?

    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
        guard let windowScene = (scene as? UIWindowScene) else { return }

        let window = UIWindow(windowScene: windowScene)
        self.window = window

        if (user != nil && userSelfIdent != nil){
            let mainstoryboard:UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
            let newViewcontroller:UIViewController = mainstoryboard.instantiateViewController(withIdentifier: "swrevealviewcontroller") as! SWRevealViewController
            window.rootViewController = newViewcontroller
            window.makeKeyAndVisible()
        }
    }

    func sceneDidDisconnect(_ scene: UIScene) {
        // Called as the scene is being released by the system.
    }

    func sceneDidBecomeActive(_ scene: UIScene) {
        // Not called under iOS 12 - See AppDelegate applicationDidBecomeActive
    }

    func sceneWillResignActive(_ scene: UIScene) {
        // Not called under iOS 12 - See AppDelegate applicationWillResignActive
    }

    func sceneWillEnterForeground(_ scene: UIScene) {
        // Not called under iOS 12 - See AppDelegate applicationWillEnterForeground
    }

    func sceneDidEnterBackground(_ scene: UIScene) {
        // Not called under iOS 12 - See AppDelegate applicationDidEnterBackground
    }
}

这篇关于添加 SceneDelegate 并更新 Info.plist 后黑屏的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆