← 所有文章

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。

19 分鐘閱讀

為 iPhone Duo 做設計:什麼會移動、什麼會分割、什麼保持不動

把 Apple 的 iPhone Duo 設計指南與三場 Tech Talk 當成規則來讀:以兩個尺寸類別取代逐一適配的姿勢、摺痕處的位移、arrangement,以及側邊列。

16 分鐘閱讀