xcode27适配iOS27多窗口生成机制处理的问题

UIScene生命周期适配

在iOS27由于多窗口机制,iOS底层增加了UIScene场景管理,需要添加新的SceneDeleage实现多窗口机制管理,针对旧的app需要做如下迁移

创建SceneDeleage

SceneDeleage.h

objectivec 复制代码
#import <UIKit/UIKit.h>

API_AVAILABLE(ios(13.0))
@interface SceneDelegate : UIResponder <UIWindowSceneDelegate>
@property (strong, nonatomic) UIWindow * window;
@end

SceneDeleage.m

objectivec 复制代码
#import "SceneDelegate.h"

API_AVAILABLE(ios(13.0))
@implementation SceneDelegate

- (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 及以下兼容

objectivec 复制代码
#import <UIKit/UIKit.h>

@interface AppDelegate : UIResponder <UIApplicationDelegate>
@property (strong, nonatomic) UIWindow *window;
@end

移除原来rootcontroller的设置,使用系统配置sceneDelegate,增加两个新的deleage方法,Default Configuration命名可以自定但需要跟info.plist中的配置相对应

objectivec 复制代码
#import "AppDelegate.h"
#import "SceneDelegate.h"

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    
    if (@available(iOS 13.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初始化、第三方配置写在这里
    
    return YES;
}

#pragma mark - UISceneSession Lifecycle
API_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

objectivec 复制代码
<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

objectivec 复制代码
__attribute__((objc_runtime_name("SceneDelegate")))
@interface SceneDelegate : UIResponder<UIWindowSceneDelegate>
...
<key>UISceneDelegateClassName</key>
<string>SceneDelegate</string>

使用运行态SceneDelegate进行替换

这里注意的是info.plist把UIApplicationSupportsMultipleScenes设置为false,如果设置为true,需要处理各个场景下keywindow的处理逻辑

废弃写法 [UIApplication sharedApplication].keyWindow 不要再用;

获取当前活跃 window OC 版本:

objectivec 复制代码
- (UIWindow *)getCurrentKeyWindow {
    for (UIScene *scene in [UIApplication sharedApplication].connectedScenes) {
        if (scene.activationState == UISceneActivationStateForegroundActive && [scene isKindOfClass:[UIWindowScene class]]) {
            UIWindowScene *ws = (UIWindowScene *)scene;
            for (UIWindow *win in ws.windows) {
                if (win.isKeyWindow) {
                    return win;
                }
            }
        }
    }
    return nil;
}
相关推荐
FPGA小迷弟10 小时前
FPGA 与千兆以太网:各类物理接口的形式、区别、使用方法与应用场景详解
tcp/ip·macos·fpga开发·udp·fpga
2501_916008892 天前
iOS App 图标、启动屏和多语言搭配 方法,上架前使用KXBuild一次做好 App 图标
ide·vscode·ios·objective-c·个人开发·swift·敏捷流程
2501_915918412 天前
iOS 推送通知怎么实现,从 APNs p8 密钥到 iOS 真机收到第一条推送
vscode·ios·objective-c·个人开发·swift·敏捷流程
周小董3 天前
[1379]mac安装nvm
macos
bossjuemfc3 天前
不记得文件名时,Mac 上的搜索还能怎么做?
macos
2501_915909063 天前
Windows 打开 Xcode 工程,编译调试 Xcode 项目并和 Mac 同事协作
ide·windows·vscode·macos·ios·个人开发·xcode
请为小H留灯3 天前
Mac 常用操作与维护技巧
macos·电脑·清理电脑·常用技巧
hantmac3 天前
不记得文件名时,Mac 上的搜索还能怎么做?
人工智能·macos
这是谁的博客?3 天前
AI 加速器 RTL 数字系统设计深度解析:从 MAC 阵列 Verilog 实现到时序收敛与时钟功耗的芯片落地全链路
人工智能·macos·ai·verilog·数字ic设计·ai芯片·rtl
slacker-kian3 天前
M 系列 Mac 清除顽固的 CorpLink
macos·corplink·m系列