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;
}
相关推荐
TheLittleBoy2 小时前
iOS 27支持的设备列表
macos·ios·cocoa·ios 27
李永吉3 小时前
mac软件安装包pkg公证装订处理去掉安全拦截弹窗
macos
朝阳58118 小时前
Mac 上找窗口,可以先按这几种情况来
macos
庚鑫20 小时前
iOS 27 兼容放大模式下,keyboardFrame 与 UIScreen.bounds 的坐标差异
ios·objective-c
william_yangshun20 小时前
DigUp 实测:用多模态嵌入做 macOS 全盘语义搜索
macos·向量检索
czt_java21 小时前
网络基础入门:IPv4、IPv6、私网公网、MAC、以太网帧与 DNS 学习笔记
网络·学习·macos
HEJOO921 小时前
iOS 高效绘图:从 Core Graphics 到 Metal 的实践指南
macos·ios·cocoa
Hello_Pyhx1 天前
RetainPDF v4.2.6:Windows、macOS、Linux PDF 翻译的 API 配置与任务排查
linux·macos·pdf
HEJOO91 天前
iOS 性能优化全面详解
ios·性能优化·cocoa