UIScene生命周期适配
在iOS27由于多窗口机制,iOS底层增加了UIScene场景管理,需要添加新的SceneDeleage实现多窗口机制管理,针对旧的app需要做如下迁移
创建SceneDeleage
SceneDeleage.h
#import<UIKit/UIKit.h>API_AVAILABLE(ios(13.0))@interfaceSceneDelegate:UIResponder<UIWindowSceneDelegate>@property(strong,nonatomic)UIWindow*window;@endSceneDeleage.m
#import"SceneDelegate.h"API_AVAILABLE(ios(13.0))@implementationSceneDelegate-(void)scene:(UIScene*)scene willConnectToSession:(UISceneSession*)session options:(UISceneConnectionOptions*)connectionOptions{if(![scene isKindOfClass:[UIWindowScene class]])return;UIWindowScene*windowScene=(UIWindowScene*)scene;self.window=[[UIWindow alloc]initWithWindowScene:windowScene];// =========替换成你项目真实根控制器=========UIViewController*rootVC=[[UIViewController alloc]init];self.window.rootViewController=rootVC;[self.window makeKeyAndVisible];}-(void)sceneDidDisconnect:(UIScene*)scene{}-(void)sceneDidBecomeActive:(UIScene*)scene{}-(void)sceneWillResignActive:(UIScene*)scene{}-(void)sceneWillEnterForeground:(UIScene*)scene{}-(void)sceneDidEnterBackground:(UIScene*)scene{}@end注意替换项目真是根控制器,将相应appdeleage的代码转移到此处
原有AppDelegate的处理
保留window属性,用于 iOS12 及以下兼容
#import<UIKit/UIKit.h>@interfaceAppDelegate:UIResponder<UIApplicationDelegate>@property(strong,nonatomic)UIWindow*window;@end移除原来rootcontroller的设置,使用系统配置sceneDelegate,增加两个新的deleage方法,Default Configuration命名可以自定但需要跟info.plist中的配置相对应
#import"AppDelegate.h"#import"SceneDelegate.h"@implementationAppDelegate-(BOOL)application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions{if(@available(iOS13.0,*)){// iOS13+ window交给SceneDelegate处理,此处不要操作self.window}else{// iOS12及更低版本 老逻辑保持不变self.window=[[UIWindow alloc]initWithFrame:[UIScreen mainScreen].bounds];// 替换为你的根控制器UIViewController*rootVC=[[UIViewController alloc]init];self.window.rootViewController=rootVC;[self.window makeKeyAndVisible];}// 全局SDK初始化、第三方配置写在这里returnYES;}#pragmamark-UISceneSession LifecycleAPI_AVAILABLE(ios(13.0))-(UISceneConfiguration*)application:(UIApplication*)application configurationForConnectingSceneSession:(UISceneSession*)connectingSceneSession options:(UISceneConnectionOptions*)options{return[[UISceneConfiguration alloc]initWithName:@"Default Configuration"sessionRole:connectingSceneSession.role];}API_AVAILABLE(ios(13.0))-(void)application:(UIApplication*)application didDiscardSceneSessions:(NSSet<UISceneSession*>*)sceneSessions{}@end变更info.plist
<key>UIApplicationSceneManifest</key><dict><key>UIApplicationSupportsMultipleScenes</key><false/><key>UISceneConfigurations</key><dict><key>UIWindowSceneSessionRoleApplication</key><array><dict><key>UISceneConfigurationName</key><string>Default Configuration</string><!--注意!!把下面 MyApp 替换为你实际 Product Module Name--><key>UISceneDelegateClassName</key><string>MyApp.SceneDelegate</string></dict></array></dict></dict>这里需要注意MyApp的设定,如果工程是defines Module为true的,则使用product module name作为MyApp的提黄
如果defines module为false
__attribute__((objc_runtime_name("SceneDelegate")))@interfaceSceneDelegate:UIResponder<UIWindowSceneDelegate>...<key>UISceneDelegateClassName</key><string>SceneDelegate</string>使用运行态SceneDelegate进行替换
这里注意的是info.plist把UIApplicationSupportsMultipleScenes设置为false,如果设置为true,需要处理各个场景下keywindow的处理逻辑
废弃写法[UIApplication sharedApplication].keyWindow不要再用;
获取当前活跃 window OC 版本:
-(UIWindow*)getCurrentKeyWindow{for(UIScene*scenein[UIApplication sharedApplication].connectedScenes){if(scene.activationState==UISceneActivationStateForegroundActive&&[scene isKindOfClass:[UIWindowScene class]]){UIWindowScene*ws=(UIWindowScene*)scene;for(UIWindow*wininws.windows){if(win.isKeyWindow){returnwin;}}}}returnnil;}