iPadOS上启动黑屏翻车问题分析(一)
昨天我们说了旧的项目在iOS 13下完全启动之后黑屏的问题,然后紧跟问题通过UI图层分析方式一步步的分析基本找到了问题的根源---iPadOS的底层以及操作思路转变啦
单窗口时代
咱们暂且吧单窗口的iOS定义为旧时代,也就是之前的iOS应用默认的情况下基于单一窗口模式开发的(如下图),而作为开发人员也是十分的享受这种内置的开发模版
新的时代--支持多窗口模式
在升级到iOS 13之后系统开始支持多窗口这个尤其是在iPadOS上尤为显著,这样你可以同时的在一个设备屏幕上同时享受到至少两个App的视图内容…
AppDelegate对App管理权限的转移
我们提到之前的iOS App是基于单视窗的而我们在开发中也是默认情况下不去而外的去添加新的window,因此在这种情况下我们的APPDelegate就成了整个App的生命周期的管理者啦。但是iOS 13之后这个规律被打破,将很多的任务转移给了UIWindowScene
旧项目黑屏拯救
既然App的声明周期在转移那么我们的App代码也要跟着迁移处理
1 Info.plist更改
代码语言:javascript复制<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>UIApplicationSupportsMultipleScenes</key>
<true/>
<key>UISceneConfigurations</key>
<dict>
<key>UIWindowSceneSessionRoleApplication</key>
<array>
<dict>
<key>UISceneDelegateClassName</key>
<string>$(TARGET_NAME).SceneDelegate</string>
<key>UISceneStoryboardFile</key>
<string>Main</string>
<key>UISceneConfigurationName</key>
<string>Default Configuration</string>
</dict>
</array>
</dict>
</dict>
</plist>
Swift来说由于一般情况下
OC项目配置
从plist配置来看的话,我们需要新建一个类来作为WindowScene的代理的载体
②对APPDelegate的修改
OC版本
代码语言:javascript复制-(UISceneConfiguration *)application:(UIApplication *)application configurationForConnectingSceneSession:(UISceneSession *)connectingSceneSession options:(UISceneConnectionOptions *)options API_AVAILABLE(ios(13.0)){
UISceneConfiguration * config = [[UISceneConfiguration alloc] initWithName:@"Default" sessionRole:connectingSceneSession.role];
return config;
}
Swift版本
代码语言:javascript复制 func application(_ application: UIApplication,
configurationForConnecting connectingSceneSession: UISceneSession,
options: UIScene.ConnectionOptions) -> UISceneConfiguration {
return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
}
从API_AVAILABLE(ios(13.0))的attribute可知这个会在iOS13才会调用,我们做好版本兼容即可
③ 新建的SceneDelegate载体
OC版本
.m文件
代码语言:javascript复制#import "SceneDelegate.h"
#import "LoginViewController.h"
@interface SceneDelegate()
@end
@implementation SceneDelegate
-(void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions API_AVAILABLE(ios(13.0)){
UIWindow * aWindow = [[UIWindow alloc] initWithWindowScene:scene];
aWindow.rootViewController = [[LoginViewController alloc] init];
self.window = aWindow;
[self.window makeKeyAndVisible];
AppDelegate *app = [UIApplication sharedApplication].delegate;
[app setWindow:self.window];
}
@end
上篇文章我们分析到UIWindow的继承关系发生了变化需要通过Scene来进行初化,而Scene变化为称为Respender的子类可以响应事件而不再是之前那个单纯的UIScene
在这个为了对以前的代码的支持我们依然给AppDelegate一个window,但是这个已经不是之前项目那个widow那么简单啦
Swift版本我们就不详细说了代码逻辑依然是OC的
代码语言:javascript复制
class SceneDelegate: UIResponder,UIWindowSceneDelegate {
var window: UIWindow?
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
var aWindow = UIWindow(windowScene: scene as! UIWindowScene)
aWindow.rootViewController = LoginViewController()
self.window = aWindow
self.window?.makeKeyAndVisible()
var app: AppDelegate = UIApplication.shared.delegate as! AppDelegate
app.window = window
}
}