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 UIRequiresFullScreen 与 UISupportedInterfaceOrientations 都没有被废弃。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 正在被掏空,而不是被废弃
五条未解决问题中有四条涉及 UIRequiresFullScreen。1 这个让 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 可以避开这些具体问题,但那是推迟最终的变化,而不是阻止它。
来源
-
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 列表已为空。 ↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩ -
Apple,“UIViewController.supportedInterfaceOrientations.” 上文完整引用的交集规则出自此处:系统将 view controller 所支持的方向,与 App 所支持的方向(来自
Info.plist或 app delegate)以及设备所支持的方向进行比较。它同时也是各惯用类型默认值、shouldAutorotate前提条件,以及”对 iPhone 惯用类型停用倒置方向”这一指南的出处。 ↩↩↩↩↩↩↩ -
Apple,“UIRequiresFullScreen.” 可用于 iOS 9.0 与 iPadOS 9.0,截至 2026-08-02 没有废弃、不可用或 beta 标记。兼容模式描述的出处,包括在 iPadOS 26 及更高版本的 Windowed Apps 模式与 iPadOS 16 及更高版本的 Stage Manager 之下的行为。 ↩↩↩↩↩↩↩
-
Apple,“UISupportedInterfaceOrientations.” 可用于 iOS 3.2 与 iPadOS 3.2,没有废弃标记。四个方向取值的出处,以及”系统在没有主屏幕按钮的设备上忽略倒置选项”这一说明的出处。 ↩↩↩↩