众所周知,iOS16中,界面旋转的UIDevice相关写法已经失效,需要用setNeedsUpdateOfSupportedInterfaceOrientations以及配合requestGeometryUpdateWithPreferences来进行界面的旋转。

        在我的工程中,是iOS原生与unity混编的,同时unity中接入了ARKit来进行相关的AR扫描、识别功能,整个工程iPhone orientation只勾选了portrait。

        在升级iOS16之前,我采用了两种方法进行界面的旋转。

        一种是在AppDelegate中,通过supportedInterfaceOrientationsForWindow方法来设置。即在需要横屏的界面设置allowRotation参数来达到屏幕的旋转,这种用于视频播放、横屏网页。

- (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window
{
    if (self.allowRotation)
    {
        return UIInterfaceOrientationMaskLandscapeRight;
    }

    return UIInterfaceOrientationMaskPortrait;
}

        另一种是在单个界面中添加如下代码进行界面旋转。在unity相关的界面中采用了此种方法。

- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
    return UIInterfaceOrientationLandscapeRight;
}

- (BOOL)shouldAutorotate {
    return NO;
}

- (UIInterfaceOrientationMask)supportedInterfaceOrientations {
    return UIInterfaceOrientationMaskLandscapeRight;
}

        升级iOS16后,我发现第二种方法无法达到界面旋转的作用,但是第一种方法仍然管用,即使不使用新的api,也可以正确旋转为横屏。

        为了达到横屏的效果,在unity的相关界面中,改用了第一种方法来进行屏幕旋转,在unity显示界面的willAppear函数中设置了AppDelegate的allowRotation参数,实际运行后发现虽然我们自己的unity界面以及UI可以正常显示,但是ARKit中相机发生了失真,屏幕宽高颠倒,导致摄像头的界面进行了拉伸(比如从375拉伸到812,说明宽高颠倒)。

        经过一系列的分析尝试,最终得到了正确的显示效果,重点如下:

        1. 界面旋转,即allowRotation参数的设定需要在重新激活unity操作之前进行。猜测是因为ARKit的相机所拿取的屏幕参数时机较早,一旦激活就会拿取,而unity中我们自己自定义的场景模型等的UI则在显示的时候即可进行更改。

        具体来说,我们的工程中,主体是原生界面,部分功能需要显示unity界面

[self.view addSubview:UnityGetMainWindow().rootViewController.view];

         在通过上述代码显示unity界面之前,需要在UnityAppController.mm中调用下方代码来激活unity

if (_didResignActive) {
        UnityPause(false);
    }
    _didResignActive = false;

        在此之前就需要通过AppDelegate的allowRotation参数来进行界面的旋转。

        2.设置AppDelegate的allowRotation参数以后,还需要调用[UIViewController attemptRotationToDeviceOrientation]来使设置生效。

        正常情况下,在VC的生命周期中,系统会自动调用supportedInterfaceOrientationsForWindow,如果在其他时候想要supportedInterfaceOrientationsForWindow被调用,就需要通过attemptRotationToDeviceOrientation来操作。

        3.iOS16中,通过[UIScreen mainScreen].bounds.size获取到的宽高不一定为正确的宽高,需要进行相关大小判断,拿到正确的数值。

        4.在我的工程中,由于在新的unity界面推出前就进行了屏幕旋转,所以跳转过程中会看到上一个界面的横屏状态,不太美观。

        这个问题的出现是因为unity加载速度比较慢(可能是因为我们的工程中有大量模型),对于正常的UI界面跳转速度较快就不会出现这种情况。

        为了解决这个问题,可以在unity的界面之前添加一个只有背景图的横屏VC进行遮挡,但是要注意当unity的界面退出后,还要退出这个中间界面才能达到返回上一界面的效果。