← 所有文章

iOS 27 的 iPad 可调整大小:这个变通方案是有代价的

Apple 的 iOS 27 发行说明,为那些无法连续调整大小的 iPad App 给出了一句话的变通方案:在 Info.plist 中声明支持全部四个界面方向。1 这条说明没有提到的是,系统会把这个 App 级别的声明与每个 view controller 所支持的方向取交集。2 放宽 App 级别的集合,就等于在所有地方一并放宽,iPhone 也不例外——除非每一个需要受限的 view controller 都重写了 supportedInterfaceOrientations

更新,8 月 24 日: 这道门槛已经消失。当前的发行说明把问题 166422120 标记为 Fixed——它在 beta 4 版与 beta 6 版之间从 Known Issues 中移出,beta 7 版也印证了这一点:已声明的方向不再是连续可调整大小的条件,与下文引用的那句意图一致。1 如果已经上线了”声明全部四个方向”的变通方案,在当前的 beta 上它不再是必需的;但在移除之前,请重新检查那些与之一同添加了 supportedInterfaceOrientations 重写的 view controller,因为这些重写本身仍在发挥作用(本文所述的交集行为并没有变化)。beta 4 时期与 UIRequiresFullScreen 相关的调整大小已知问题,同样在 Resolved Issues 中被标记为 Fixed。下面的分析按照写作时的样子保留,以 Beta 4 为锚点,因为只要变通方案还留在已发布的构建里,它的副作用机制就依然成立。关于这项变化所处的更大图景,参见可调整大小的 iPhone 时代

关于这项变化的那个流传版本,对当前状态的描述同样是错的。 Apple 的意图是让已声明的方向不再决定连续可调整大小。而记录这一意图的发行说明条目之所以被归入 Known Issues,是因为在 Beta 4 中方向仍然起着限制作用。1

两半都重要。这个行为是通往一项有意变更途中的 bug,而这个 bug 的变通方案带有一个没人写在同一处的副作用。

TL;DR

在 iOS 与 iPadOS 27 Beta 4 中,一个使用 iOS 27 SDK 构建、且 UISupportedInterfaceOrientations 缺少四个方向中任意一个的 iPad App,会被视为不支持连续调整大小。Apple 把它列为已知问题,同时又表示方向”不应再成为连续可调整大小的条件”。1 文档给出的变通方案是声明全部四个方向。这样做会放宽整个 App 的方向集合,而系统正是通过比较 App 级别的方向与每个 view controller 的方向来决定是否旋转。2 另有四个已知问题涉及 UIRequiresFullScreen:本应以离散的 UIScreen 变更来传递的地方,却收到了连续的调整大小更新。1 UIRequiresFullScreenUISupportedInterfaceOrientations 都没有被废弃。34

发行说明究竟说了什么

iOS 与 iPadOS 27 Beta 4 说明中,UIKit 部分有六条与此相关,其中五条尚未解决。1

门槛本身,归入 Known Issues:

“在 iPad 上,如果您的 iPad App 使用 iOS 27 SDK 构建,且其 UISupportedInterfaceOrientations 未包含全部四个界面方向,该 App 会被视为不支持连续调整大小。从 iOS 27 开始,所支持的界面方向不应再成为连续可调整大小的条件。”

请读一读第二句的语气。”不应再成为条件”描述的是预期行为。这一条之所以作为已知问题存在,正是因为已发布的行为还没有与这个意图对上。

这个区别会改变您该做什么。如果方向真的不再决定可调整大小,建议就应该是移除变通方案。既然它们仍在起作用,建议就是先加上一个,并预期这么做的理由会消失。

围绕 UIRequiresFullScreen 的四个已知问题:

一个使用 iOS 27 SDK 构建、并设置了 UIRequiresFullScreen 的 iPad App 会收到连续的调整大小更新,而”每一次调整大小本应作为一次离散变更,传递给一个 bounds 已更新的新 UIScreen“。同样的情况也出现在 iPad 上运行的 iPhone 专用 App,以及 iPhone 镜像中。1

第四条涉及 iPhone 镜像中的方向处理:使用 iOS 27 SDK 构建的 App 会得到一个支持所有方向的 scene,”无论 UISupportedInterfaceOrientations 中声明了什么,或 UIViewController.supportedInterfaceOrientations 返回了什么”,而这些本应”在用户开始调整窗口大小之前一直被尊重”。1

一条已解决: 此前那个在 UIRequiresFullScreen 之下调整大小时 UIScreen.main 的 bounds 会发生变化的问题,现已出现在 Resolved Issues 中。1 它在上一个 beta 中还是一条有效的已知问题。如果您正依据几周前记下的笔记工作,动手之前先核对这一条。

连续可调整大小到底带来什么

在权衡代价之前,值得先把被限制的那个东西说清楚,因为”连续可调整大小”这个说法承担着具体的含义。

iPad 窗口改变尺寸有两种方式。一种是在离散状态之间跳变,这正是兼容模式下的 App 所得到的:用 Apple 的话说,系统”为您的 App 维持一致的 scene 尺寸,但不会以全屏方式呈现 App 的 scene”。3 另一种是跟随拖拽,在用户移动调整控件的过程中接收一连串中间尺寸。

差别体现在用户的手上。连续可调整大小的 App 会在窗口移动时同步重排布局;不支持的那种则会一直保持原布局,最后一下吸附到位——与不这样做的系统 App 摆在一起,就显得迟钝。

多年来,Apple 一直在收窄兼容路径。UIRequiresFullScreen 于 iOS 9 出现,用来彻底退出 iPad 多任务与动态调整大小。3 iPadOS 16 的 Stage Manager 与 iPadOS 26 的 Windowed Apps 模式各自扩展了窗口能做的事,而文档如今描述兼容模式的方式,是它扣下了什么,而不是它给了什么。

所以变通方案回答的问题是:您的 iPad App 是要参与现代的窗口化,还是留在一个 Apple 不断压缩的模式里。这值得改一次 Info.plist,但不值得毫无防护地改——这正是下一节的要点。

变通方案的代价

Apple 的变通方案只有一句话:在 Info.plist 中声明全部四个界面方向。1 而它的后果写在另一个页面上。

UIViewController.supportedInterfaceOrientations 记录了旋转是如何被决定的:2

“为了判断是否旋转,系统会将 view controller 所支持的方向,与 App 所支持的方向(由 Info.plist 文件或 app delegate 的[方法]决定),以及设备所支持的方向进行比较。”

三个集合取交集。Info.plist 中的声明是上限,而不是指令。一个仅在 Info.plist 里列出一个方向、从而一直保持竖屏,并且在 view controller 层面从未重写过任何东西的 App,会在应用变通方案的那一刻失去这项约束。

对通用 App 来说,这会同时落在 iPhone 和 iPad 上。而 Apple 自己的指南也反对在 iPhone 上作宽泛声明:关于倒置方向,”最佳做法是为 iPad 惯用类型启用它。没有主屏幕按钮的 iOS 设备,例如 iPhone 12,并不支持这个方向。对 iPhone 惯用类型,您应当完全停用它。”2 Info.plist 的文档从另一个方向说了同样的话,指出系统会”在没有主屏幕按钮的设备上”忽略倒置方向。4

所以诚实的说明是两步,而不是一步:

<!-- Info.plist: the ceiling. Required for continuous resizability on iPad. -->
<key>UISupportedInterfaceOrientations</key>
<array>
    <string>UIInterfaceOrientationPortrait</string>
    <string>UIInterfaceOrientationPortraitUpsideDown</string>
    <string>UIInterfaceOrientationLandscapeLeft</string>
    <string>UIInterfaceOrientationLandscapeRight</string>
</array>
// And the floor, on every controller that must stay constrained.
final class CaptureViewController: UIViewController {
    override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
        UIDevice.current.userInterfaceIdiom == .pad ? .all : .portrait
    }
}

跳过第二步,就等于为了换取 iPad 的窗口行为,告诉一个通用 App 在 iPhone 上可以倒过来旋转。这个失败不是崩溃,也不是构建错误,而是有人正在使用时相机画面翻了个个儿。

另外请注意,supportedInterfaceOrientations 的默认值因惯用类型而异,而且只有当 shouldAutorotate 返回 true 时系统才会去查询它。2 如果重写过后者,在断定约束仍然成立之前,值得把这两者的相互作用重读一遍。

判断自己是否受影响

这些都不会产生构建错误,所以排查只能靠手工。三项检查,按节省时间的多少从高到低排列。

逐个 target 查看 Info.plist 实际声明了什么。 方向相关的键往往在创建项目时设置一次,此后再没人回头看;而通用 App 可以通过 UISupportedInterfaceOrientations~ipad 为 iPhone 和 iPad 携带不同的声明。两处都要读。

# Every orientation and fullscreen declaration across the project
rg -l 'UISupportedInterfaceOrientations|UIRequiresFullScreen' --glob '*.plist'

# And what each one says
/usr/libexec/PlistBuddy -c "Print :UISupportedInterfaceOrientations" Info.plist
/usr/libexec/PlistBuddy -c "Print :UIRequiresFullScreen" Info.plist

当某个键不存在时,PlistBuddy 会以非零状态退出——对 UIRequiresFullScreen 而言,这本身就是答案:没有这个键,说明从来就没进过兼容模式。

找出在代码中约束方向的 controller。 改动 Info.plist 之后仍然生效的正是它们,而它们的缺席正是这项改动危险的原因。

rg 'supportedInterfaceOrientations|shouldAutorotate' --type swift

结果为空,再加上一份狭窄的 Info.plist 声明,正是会出问题的那种组合:这个 App 完全靠 property list 才保持竖屏,一旦放宽,唯一存在过的约束也就没了。

然后在两种惯用类型上亲眼看看这个 App。 这个失败是视觉性的,自动化信号很弱。一个驱动界面并对内容做断言的 UI 测试,在任何方向下都会通过。要找的是一个此前无法旋转的视图旋转了起来——这意味着在改动 Info.plist 之后,运行 iPhone 构建,并实际转动设备或模拟器。

媒体采集、文稿扫描、签名区域、游戏,以及任何带有固定宽高比画布的界面,是意外旋转代价最高的地方,也最明显地属于该写 per-controller 重写的地方。

UIRequiresFullScreen 正在被掏空,而不是被废弃

五条未解决问题中有四条涉及 UIRequiresFullScreen1 这个让 App 退出 iPad 多任务的键,如今成了调整大小传递行为不正确的前提条件。

它并没有被废弃。UIRequiresFullScreen 的文档显示其可用于 iOS 9.0 与 iPadOS 9.0,没有任何废弃、不可用或 beta 标记。3 UISupportedInterfaceOrientations 同样如此,自 iOS 3.2 起可用。4

这个组合值得点名。一个在 2026 年设置 UIRequiresFullScreen 的 App,编译时不会有警告,发布时不会有迁移提示,最后落在一个 Apple 持续收窄的兼容模式里。这个模式在现代系统上意味着什么,文档已经写清楚了:在支持 Windowed Apps 模式的 iPad 上的 iPadOS 26 及更高版本,以及在支持 Stage Manager 的 iPad 上的 iPadOS 16 及更高版本,系统”为您的 App 维持一致的 scene 尺寸,但不会以全屏方式呈现 App 的 scene”。3

这个键已经不再做它名字所说的事。它没有被退役,而您的构建里没有任何东西会告诉您这一点。

共同的模式:SDK 链接说了算

上面每一条都共享同一个条件,而这个条件不是操作系统版本。每一条都适用于”使用 iOS 27 SDK 构建”的 App。1

同一份源码,不同的二进制,不同的行为。这一点在本次发布中反复出现:菜单项图片取决于链接的是哪个 SDK,横跨两代 SDK 共有三种不同的行为。而 macOS 27 的跨团队容器拒绝看起来是相反的情形,是一项没有 SDK 限定的系统级策略——正因如此,这个区别值得去核实,而不是想当然。

对测试的实际影响是:针对 iOS 26 SDK 的构建与针对 iOS 27 SDK 的构建是两个不同的对象。如果 CI 矩阵里只有一个 Xcode 版本,那么测到的只是其中之一。

现在该做什么

先判断自己是否真的需要连续可调整大小。 如果 iPad App 已经声明了全部四个方向,这里的内容都不适用。变通方案只在您有意约束过方向时才相关。

如果采用变通方案,就要配上 per-controller 的重写。 Info.plist 的改动是上限;约束必须转移到需要它的那些 controller 的 supportedInterfaceOrientations 上,并按惯用类型分支。

单独排查 UIRequiresFullScreen 有四条未解决问题涉及它,而构建过程中不会有任何提示。请 grep 所有 Info.plist 文件,包括那些您并不认为是 iPad App 的 target,因为其中一条问题针对的正是在 iPad 上运行的 iPhone 专用 App。

预期这道门槛会消失。 Apple 表示方向不应再决定连续可调整大小。当这一点落地时,声明全部四个方向的理由就没有了,但被放宽的方向集合会一直留在 Info.plist 里,直到有人去删掉它。请留一条注释说明它为什么在那里。

动手之前重新核对说明。 这六条中已经有一条从 Known Issues 移到了 Resolved。本文反映的是 2026 年 8 月 2 日时的 Beta 4。

要点回顾

对 iPad App 开发者: - 尽管 Apple 表示方向不应再起限制作用,但在 Beta 4 中已声明的方向仍然决定连续可调整大小。请把它当作一个有变通方案的 bug,而不是新的行为。 - 变通方案会放宽整个 App 的方向上限。请添加 per-controller 的 supportedInterfaceOrientations 重写,否则 iPhone 构建就会开始旋转。 - 四条未解决问题涉及 UIRequiresFullScreen 传递连续而非离散的调整大小更新。

对维护老 App 的人: - UIRequiresFullScreen 没有被废弃,也不会产生警告,而它所请求的那种行为却在持续收窄。请显式地排查它。 - 这里的每一条问题都以”使用 iOS 27 SDK 构建”为条件,而不是以用户运行的系统版本为条件。

FAQ

已声明的方向是否已经不再决定连续可调整大小?

在 Beta 4 中还没有。Apple 表示”从 iOS 27 开始,所支持的界面方向不应再成为连续可调整大小的条件”,同时把这句话归入 Known Issues,因为当前行为仍然以方向为条件。1

实际的变通方案是什么?

UISupportedInterfaceOrientations 中声明全部四个界面方向。1 并且要为那些必须保持受限的 view controller 配上 supportedInterfaceOrientations 重写,因为系统会把 App 级别的集合与每个 controller 的集合取交集。2

这会影响我的 iPhone 构建吗?

如果发布的是通用 App,且仅依赖 Info.plist 来约束方向,那么会。Apple 建议对 iPhone 惯用类型完全停用倒置方向,并指出在没有主屏幕按钮的设备上系统会忽略它。24

UIRequiresFullScreen 被废弃了吗?

没有。它的文档显示其可用于 iOS 与 iPadOS 9.0,且没有废弃标记。3 这里四条未解决问题都涉及它,所以不要把缺少废弃标记读成一种认可。

Apple 修好这道门槛之后,我应该移除变通方案吗?

移除不再需要的那部分,保留保护您的那部分。当已声明的方向不再决定连续可调整大小时,列出全部四个方向的理由就消失了,可以把 UISupportedInterfaceOrientations 收回到 App 实际支持的范围。而 per-controller 的 supportedInterfaceOrientations 重写无论如何都应该留着:把方向约束表达在约束本该所在的位置,比依赖一个 App 级别的上限更耐久。

要避免的失败模式恰恰相反:把 Info.plist 收窄回去,却忘了正是那些重写在支撑着采集界面不被转过来。

我怎么知道自己的 App 目前是否支持连续调整大小?

在 iPad 上调整窗口大小,看布局是跟随拖拽,还是最后一下吸附到位。跟随就是支持连续调整大小。如果是吸附,检查两件事:是否设置了 UIRequiresFullScreen(它会彻底退出动态调整大小),以及 UISupportedInterfaceOrientations 是否列出了全部四个方向——后者正是这条已知问题所描述的条件。13

针对更旧的 SDK 构建能不能规避这一切?

每一条都以使用 iOS 27 SDK 构建为条件。1 更旧的 SDK 可以避开这些具体问题,但那是推迟最终的变化,而不是阻止它。

来源


  1. Apple,“iOS & iPadOS 27 Beta 4 Release Notes,” UIKit。Known Issues:radar 166422120(方向决定连续可调整大小,附带声明全部四个方向的变通方案)、178560235 与 178562971 与 178558224(UIRequiresFullScreen 收到连续而非离散的调整大小更新,分别发生在 iPad 上、iPad 上的 iPhone 专用 App,以及 iPhone 镜像中),以及 178555304(iPhone 镜像的 scene 无论声明如何都支持所有方向)。Resolved Issues:radar 178559386(在 UIRequiresFullScreen 之下调整大小时 UIScreen.main 的 bounds 发生变化),它在更早的 beta 中曾是一条已知问题。各条目所属的分区已于 2026-08-02 对照 Beta 4 的 JSON 重新核实。更新 2026-08-24: 对照 Beta 7 版的 JSON 重新核实——166422120 与 UIRequiresFullScreen 这一组现在全部出现在 Resolved Issues 中(根据存档副本,这次移动发生在 beta 6 版之前),而 UIKit 的 Known Issues 列表已为空。 

  2. Apple,“UIViewController.supportedInterfaceOrientations.” 上文完整引用的交集规则出自此处:系统将 view controller 所支持的方向,与 App 所支持的方向(来自 Info.plist 或 app delegate)以及设备所支持的方向进行比较。它同时也是各惯用类型默认值、shouldAutorotate 前提条件,以及”对 iPhone 惯用类型停用倒置方向”这一指南的出处。 

  3. Apple,“UIRequiresFullScreen.” 可用于 iOS 9.0 与 iPadOS 9.0,截至 2026-08-02 没有废弃、不可用或 beta 标记。兼容模式描述的出处,包括在 iPadOS 26 及更高版本的 Windowed Apps 模式与 iPadOS 16 及更高版本的 Stage Manager 之下的行为。 

  4. Apple,“UISupportedInterfaceOrientations.” 可用于 iOS 3.2 与 iPadOS 3.2,没有废弃标记。四个方向取值的出处,以及”系统在没有主屏幕按钮的设备上忽略倒置选项”这一说明的出处。 

相关文章

可调整大小的 iPhone 时代:在 9 月之前让你的 App 做好准备

iOS 27 把可调整大小的分界线画在了你所使用的 SDK 上。检查清单:排查固定尺寸的假设、采用自适应布局、在 Xcode 27 中测试。

7 分钟阅读

面向开发者的 iPhone Duo:1.42 的难题与 SDK 空窗期

面向开发者的 iPhone Duo:从 App Store Connect 截图推算出的显示屏点数、两种屏幕形状、Split View、Touch ID、SDK 时间表,以及六场 Tech Talks。

20 分钟阅读

为 iPhone Duo 做设计:什么会移动,什么会分栏,什么保持不动

把 Apple 的 iPhone Duo 设计指南和三场 Tech Talk 当作规则来读:用两个尺寸类别取代逐一适配的姿态、折痕处的位移、arrangement,以及侧边栏。

16 分钟阅读