今天是 2026 年 10 月 15 日。Apple 产品页写着预购从 10 月 16 日太平洋时间凌晨 5 点开始,10 月 23 日起开卖。10 月 5 日的开发者新闻已经允许用 Xcode 27.1 重新编译并提交;从 2027 年 4 月起,新提交还要带上 iPhone Duo 截图。能启动只说明旧二进制还在。它不说明内屏铺满,不说明横竖屏走对了分支,也不说明分屏时主按钮还在安全区里。10 月 13 日那篇把改造工期和 Mac 买断放在一起算。这篇只回答上市前的问题:要不要改代码,以及这一轮测试该花多少。
为什么能打开还不等于重新适配
旧判断和新判断卡在同一句用户反馈上。旧判断是「模拟器里能启动,上市后再看差评」。新判断先看布局还在读哪一个事实:整块屏幕、设备方向,还是当前这一个窗口。Apple 的准备页写得很直:用 iOS 27 SDK 及之后构建的 App,会在 Duo 折叠时改变尺寸。写死的屏幕尺寸、固定方向和设备假设,会把布局拉变形、裁切或放错位置。
同一份源码在三档 SDK 上长得不一样,这是上市前的第一刀,不是设计偏好。iOS 26 SDK 或更早能跑,展开后窗口居中、四周留白,合盖后内容偏在状态栏和相机左侧。iOS 27 SDK 会铺满内屏的大部分,仍避开右侧状态栏。iOS 27.1 SDK 及之后才是优化态:内容用满显示区域,工具栏和标签栏竖在状态栏下方。只换商店截图、二进制仍是旧 SDK 的团队,用户打开内屏看到的是一块留白。留白不会被理解成「我们下周再适配」。
第二刀是窗口不等于屏幕,方向不等于形状。准备页要求每次尺寸变化都重新读:在 viewIsAppearing 里读一次不够,因为折叠发生在会话中途。UIKit 把依赖尺寸的布局放进 layoutSubviews 或 viewDidLayoutSubviews,需要在尺寸变化时做事就用 viewWillTransition(to:with:)。SwiftUI 用 GeometryReader 或 onGeometryChange。缩放从 trait collection 取,不要从 UIScreen.main.scale 取。双屏设备上的 main screen 语义含糊,Apple 说它会在未来版本废弃。
第三刀才是测试机器。Xcode 27.1 里的 iPhone Duo 模拟器、Device Hub 底部的开合旋转,以及 macOS 27 上 iPhone 镜像的极端拉伸,都绑在 Mac 上。Windows 没有这条链路。团队打包机怎么选,见 Xcode Cloud 与远程 Mac 对比。Xcode Cloud 能编包,替代不了你坐在 Device Hub 前把合盖、半折、展开各转一次,再把分屏从左边拖到右边。
折叠屏尺寸、横竖屏和多窗口怎么分类
把「支持 iPhone Duo」写成一个里程碑,上市前的排期一定漂。按用户真正会撞上的行为分成四道门。缺一道,你就会把「能编译」写成「已适配」。
| 工具 | 入口 | 执行能力 | 上下文 | 适合人群 |
|---|---|---|---|---|
| 折叠屏尺寸 | 外屏、内屏、当前窗口 | 用 size class 和 bounds 布局,不写死像素或英寸 | 规格页上的分辨率只用来理解量级 | 任何还在比较 bounds.height == 844 的代码 |
| 横竖屏 | 外屏方向声明;内屏宽高比 | 外屏遵守支持方向;内屏不遵守,包括分屏 | 帐篷姿态会让人把合盖的手机横过来放 | 用 interfaceOrientation 切换布局的页面 |
| 多窗口 | 分屏、第二场景、场景配件 | 所有 App 都会并排;新窗口只在内屏 | 外屏请求新场景会失败 | 把「新窗口」按钮从 iPad 原样搬过来的 App |
| Xcode 测试 | Xcode 27.1 的 Device Hub | 三姿态、旋转、左右分屏、第二次场景请求 | 日租五个工作日等于 16GB 月租 | 要在 10 月 23 日前给出一张回归表的人 |
尺寸:两块屏,加上一个会变的窗口
规格页把数字写死了,布局代码不该跟着写死。外屏是 5.4 英寸 Super Retina XDR,分辨率 1398×2034,460 ppi。合盖机身高 117.8 毫米、宽 84.1 毫米、厚 11.3 毫米。内屏是 7.6 英寸折叠 Super Retina XDR,分辨率 1878×2670,430 ppi,带纳米纹理。展开后高仍是 117.8 毫米,宽 164.6 毫米,厚 5.2 毫米,重量 254 克。Apple 写明两块屏长宽比一致,内容按比例缩放;按标准矩形测量大约是 5.36 英寸和 7.58 英寸,实际可视区域更小,圆角在矩形里面。
size class 才是布局该读的档。外屏和其他 iPhone 一样:竖持是垂直 regular、水平 compact,横持两边都是 compact。内屏水平和垂直都是 regular,侧栏有地方放。窗口还可以再小。分屏、半折、镜像拉伸都会让窗口不等于整块屏。所以规格页上的像素是量级,不是常量。缩放用 traitCollection.displayScale 或 SwiftUI 的 displayScale。不要把 1398 或 1878 写进 ==。
还有两个容易和「屏幕尺寸」搅在一起的系统行为。圆角用 iOS 26 的 Concentricity:SwiftUI 用 ConcentricRectangle,UIKit 用 UICornerConfiguration。折痕和相机用预留区,不靠你自己量中缝。SwiftUI 从几何代理取 ReservedRegion,UIKit 用 UIViewReservedRegion。铰链角度是另一条通道:onHingeChange 和 UIHingeInteraction 给出 closed、partially open、fully open,以及连续角度。Apple 说角度适合做动效,布局走 arrangement 和预留区。用角度去改 frame,开卖第一周就会在半折上抖。
横竖屏:外屏听话,内屏不听话
准备页的 Tech Talk 把方向说成两句。外屏的界面方向和其他 iPhone 一样,Duo 也是补上横屏的机会,因为有人会把合盖的手机像帐篷一样横放。内屏不遵守你在 Info 里声明的支持方向。和 idiom 一样,不要用方向做布局分支。要知道是不是比高更宽,就比较你实际拿到的宽和高:视图控制器里用 view.bounds,视图里用 superview.bounds,SwiftUI 用 GeometryReader 的尺寸。
要搜掉的属性是 UIDevice.current.orientation、statusBarOrientation,以及 interfaceOrientation,包括 windowScene.effectiveGeometry.interfaceOrientation。人机界面指南还补了一句连续体验:横放时控件留在侧面,保持同一条垂直高度,而不是把手机横过来就整页重排。标准系统组件会自己这样做。你自己画的栏不会。
UIRequiresFullScreen 仍然有效,但开合时 App 还是会改尺寸。另一句更容易误读:Duo 尊重你声明的支持方向,可是内屏上的 App 仍会缩放,分屏里也一样。所以「我锁了竖屏,内屏就不会变宽」不成立。安全区经常不对称。横屏和分屏里,竖排按钮可以出现在左侧。用左边 inset 乘二去推算宽度,会在另一侧把按钮推出屏幕。每一边单独减。
多窗口:分屏是默认,第二扇窗不是
多窗口 Tech Talk 的原话是:所有 App 都参与 Duo 上的多任务,两个 App 可以并排。已经为 iPad 或 iPhone 镜像做过尺寸变化的,起点更好。还有一种把视频和 App 叠在一起的新布局,处理方式和分屏相同,仍然读 size class 和场景几何,不要为它再写一套「这是视频」的分支。
Duo 是第一台支持同一 App 多个界面实例的 iPhone。iPad 上能开新窗口的,这里也能。差别只有一条:外屏不能创建新窗口,这个行为留给内屏。请求新场景必须处理失败。用 UIWindowSceneActivationAction,它会在新窗口不可用时自己隐藏,而不是留一个点了就报错的按钮。场景配件是第三条路,让补充界面出现在另一块屏上。相机的 CameraCaptureAccessory 把额外界面放在外屏,主界面留在内屏全屏,并且要有正在进行的相机会话。合盖后配件不可用,按钮要用 onAvailabilityChange 关掉。这是相机 App 的加分项。分屏不是加分项,是所有 App 的默认。
import SwiftUI
struct LaunchCheck: View {
@Environment(\.horizontalSizeClass) private var widthClass
var body: some View {
GeometryReader { proxy in
let wider = proxy.size.width > proxy.size.height
Root(regularWidth: widthClass == .regular, widerThanTall: wider)
}
.onHingeChange { _, context in
guard let hinge = context.hinge, hinge.status == .partiallyOpen else { return }
// hinge.angle drives an effect. Do not lay out from the angle.
playBend(hinge.angle)
}
}
}
这段不是工程模板。它只固定三件事:内屏 regular 宽时可以出侧栏,外屏 compact 时收回;横竖看当前窗口谁更长,不看方向;铰链角度只在半折时推动效,布局仍走 size class 和 bounds。第二个窗口的按钮交给会自动隐藏的激活动作,不要在外屏上留一个永远可点的「新窗口」。
核心对比:尺寸、方向、窗口和测试成本
真正差异在于代码还假不假设「手机只有一块屏、一个方向、一个窗口」,而不是设计师愿不愿意做折叠动效。下面两张表用同一套列。测试费用是本站定价页上 M4 16GB 与 24GB 的美元标价:日租 20.2 与 40.2,周租 54.5 与 108.5,月租 100.9 与 200.9。人日不在这篇折成美元,工期档位和买断比较在 10 月 13 日的适配成本里。
| 工具 | 入口 | 执行能力 | 上下文 | 适合人群 |
|---|---|---|---|---|
| 只重编译到 27.1 | 已有 size class,没有屏幕单例 | 核对竖栏、预留区、全幅图焦点、左右分屏 | 扫描是干净的,一天可以收口 | 已经为 iPad 分屏或镜像缩放过的 App |
| 方向分支还在 | interfaceOrientation 决定布局 | 改成比较宽高;外屏横屏单独看一眼帐篷姿态 | 内屏不遵守支持方向,锁竖屏也挡不住变宽 | 资讯、阅读、播放器里大量 if 横屏 |
| 单窗口假设 | iPad 的「新窗口」原样搬来 | 外屏隐藏入口;内屏处理创建失败;分屏当默认 | 第二实例只在内屏合法 | 文档、邮件、设计工具 |
| 固定像素 | 844、1398 或一份机型表 | 容器重建,不对称 inset,去掉 idiom | 规格页的分辨率不能写进常量 | 多年只对一块 iPhone 屏画过的商城 |
| 工具 | 入口 | 执行能力 | 上下文 | 适合人群 |
|---|---|---|---|---|
| 手里已有的 Apple Silicon | 本机 Xcode 27.1 | 模拟器全矩阵 | 增量设备费为 0,但和日常 DerivedData 抢磁盘 | 机器已经能装你锁定的 Xcode |
| 日租 M4 16GB | 远程桌面 | 一轮 Device Hub | 20.2 美元/天。五个工作日是 101.0 美元 | 扫描干净,而且两天内真能收口 |
| 周租 M4 16GB | 远程桌面 | 一个自然周 | 54.5 美元/周。两周是 109.0 美元,仍高于月租 | 可能拖过周五,但不会进第二个月 |
| 月租 16GB / 24GB | 远程桌面 | 整个回归周期;24GB 能同时开更多模拟器 | 100.9 或 200.9 美元/月。24GB 五个日租是 201.0 美元 | 方向或像素分支在第二天就露出来 |
| Xcode Cloud | 云端归档 | 编译和签名 | 日志里没有你拖 Home 指示条的那一下 | 包继续走云,姿态留在远程 Mac |
把日租乘开,测试成本的结论和改造成本是同一句算术。16GB 的 20.2×5 = 101.0,已经等于月租 100.9。24GB 的 40.2×5 = 201.0,对上月租 200.9。周租 54.5×2 = 109.0,仍略高于一个月的 16GB。所以「先按天试试」只在你确信一到两天能把矩阵跑完时成立。App Resizability 在第二天扫出一串方向判断或 UIScreen.main,计费周期就该改成月。第八天付的是周期,不是测试。
矩阵本身可以列成格子,而不是一段「测一下折叠」。三档 SDK 各看一眼:留白、避开右侧状态栏,还是全屏竖栏。然后在 27.1 的模拟器里,合盖、半折、展开各转一次。内屏上用底部的 Home 指示条把 App 拖到左边,再拖到右边,确认竖栏换边之后主按钮还在。内屏请求第二个场景;外屏确认激活动作消失,或请求失败被你接住。macOS 27 的镜像拉伸是加项,用来看比 Duo 更宽或更窄的窗口,不是开卖前的必选项。截图在主路径不留白之后再换。提交 Duo 截图会在产品页上出现优化徽章。2027 年 4 月起新提交必须带这些截图,那是商店截止日,不是 10 月 23 日的布局截止日。
场景怎么选
| 如果你是 | 就选 | 理由 |
|---|---|---|
| 纯 SwiftUI,已经支持 iPad 分屏 | 本机或一天远程节点,先跑技能扫描 | 底已经在。剩下的是竖栏、预留区、全幅图和左右分屏 |
| 第二天扫出方向或 UIScreen.main | 立刻改月租,不要把日租付完一周 | 五个工作日已经等于一个月 |
| 锁了竖屏,觉得内屏不用管 | 先改宽高比较,再谈截图 | 内屏不遵守支持方向,分屏里仍会缩放 |
| 文档或邮件,iPad 上有新窗口 | 外屏隐藏入口,内屏处理失败 | 新窗口不能在外屏创建 |
| 相机 App,想做提词器 | 分屏先过,配件后补 | 配件要内屏全屏加相机会话;分屏是所有 App 的默认 |
| 只想换 App Store 截图 | 先过 27.1,再换图 | 旧 SDK 的内屏是留白,徽章不会把留白变成适配 |
| 办公室没有 Mac | 租一台,先看 sw_vers 和 xcodebuild -version | 系统对不上时,日付出去也不产生有效格子 |
真机单独放一行。铰链手感和模拟器做不到的项需要一台机器,标价以你下单时的 Apple 商店页面为准,不要把那一行摊进每一张 Xcode 工单。每人一台 Duo 不会让 UIScreen.main 消失,也不会让外屏突然可以创建新窗口。
推荐组合
A — 独立开发者,布局已经跟着尺寸走: Xcode 27.1,本机或一天远程节点。让编码助手跑「get my app ready for iPhone Duo」,或在终端执行 xcrun agent skills export 交给别的代理。扫描是空的,再进 Device Hub:合盖、半折、展开,各转一次,再把分屏拖到左右。外屏点一次「新窗口」,确认入口消失。商店截图用 App Store Connect 的预览看 Duo。这一轮不必为了测试去买机器。节点月费见 定价页。
B — 小团队,方向和自定义栏还在: 第一周只做扫描和屏幕单例,用周租或直接月租,不要日租滚到第七天。第二周把方向分支改成宽高比较,安全区四边分开写。第三周把分屏左右各留一张图,第二场景的失败路径写进回归。CI 仍走现有打包机;需要人盯着开合的那次,用同一台远程 Mac。24GB 月租 200.9 美元,只在你要并行 Duo 和其他模拟器时才上。五个 40.2 已经等于这一档月租。
C — 要在开卖当周提交: 今天是 10 月 15 日,预购明天开始,开卖 10 月 23 日。能承诺的是 27.1 下主路径不留白、竖栏不挡主按钮、分屏换边后按钮还在、外屏不会冒出无效的新窗口。做不到的铰链动效和相机配件不要写进商店文案。开通见 租用页。系统版本和账号走 帮助中心,不要假设镜像里已经预装 Xcode 27.1。
常见误区
- 把能启动写成已适配。 iOS 26 SDK 的内屏是居中留白。用户不会把空边读成「适配中」。
- 把规格页的 1398 或 1878 写进常量。 那是像素量级。窗口在分屏和半折时更小,缩放也不该手写。
- 用方向判断内屏横竖。 内屏不遵守支持方向。横竖拿当前窗口的宽高比。
- 以为 UIRequiresFullScreen 关掉了分屏和开合。 键仍然有效,开合时尺寸还是会变;声明的方向也挡不住内屏缩放。
- 外屏上留一个永远可点的新窗口。 新窗口只在内屏。失败不处理,就会在合盖时弹错误。
- 用铰链角度做布局。 角度适合动效。布局用 size class、预留区和 arrangement。
- 日租付满一周。 16GB 五个工作日已经等于月租。第八天是在为计费周期付钱。
落地步骤:7 步
- 用同一套源码对上你能装的 SDK,先记录是留白、避让右侧状态栏,还是全屏垂直栏。目标锁定 27.1。
- 全局搜索
UIScreen.main、UIDevice.current.orientation、statusBarOrientation、interfaceOrientation、userInterfaceIdiom,以及 844、1398、1878 这类尺寸常量。 - 在 Xcode 里让编码助手跑 App Resizability,或执行
xcrun agent skills export。技能找得到大部分,找不到的用上面的清单补。 - 打开 Device Hub 的 iPhone Duo。合盖、半折、展开各转一次。再用 Home 指示条把内屏上的 App 拖到左边和右边。主路径每格留一张图。
- 内屏请求第二个场景,确认成功或失败都被接住。外屏确认
UIWindowSceneActivationAction自己隐藏。 - 看竖栏是否挡住主按钮,左右 inset 是否被写成相等,全幅图的主体还在不在,半折时预留区有没有压住控件。铰链角度只检查动效,不检查布局。
- 选计费周期:一到两天用日租;扫描已经变脏就改月租。下单前在节点上跑
sw_vers和xcodebuild -version。主路径干净之后,再换 Duo 截图,用 Connect 的预览看,不要用别的 iPhone 画布硬缩放。
FAQ
旧 App 不改代码,iPhone Duo 上市当天能打开吗?
能打开。用 iOS 26 SDK 或更早构建时,展开后窗口居中留白,合盖后内容偏在状态栏和相机左侧。能跑不等于适配完成。要铺满并使用垂直栏,需要 iOS 27.1 SDK。分屏和第二窗口也不会因为「能打开」就自动正确。
横屏只在 Info 里声明,内屏会遵守吗?
外屏会遵守你声明的支持方向,帐篷姿态值得单独看一眼。内屏不遵守,分屏里 App 仍会缩放。UIRequiresFullScreen 挡不住开合带来的尺寸变化。布局比较当前窗口的宽和高。
多窗口是可选项吗?
分屏不是可选项。Apple 写明所有 App 都会并排,视频和 App 叠放也走同一套 size class。新窗口只能在内屏创建。外屏上的入口应使用会自动隐藏的 UIWindowSceneActivationAction。相机外屏配件是加分项,要求内屏全屏并且相机会话正在进行。
只有模拟器,测试成本怎么算?
布局主路径够。Apple 把 Xcode 27.1 里的 iPhone Duo 模拟器写成完整体验的最佳测试方式。M4 16GB 日租 20.2 美元,五个工作日等于月租 100.9 美元。扫描在第二天变脏,就不要把日租付到第八天。24GB 是 40.2 美元一天、200.9 美元一月,五个日租同样对齐月租。铰链手感仍要真机,那一行不要摊进模拟器工单。
没有 Mac,上市前还能测吗?
不能在 Windows 上跑 Xcode 27.1。先确认节点 macOS 能装你锁定的 Xcode,系统要求以 Apple 的 Xcode 系统要求为准。镜像拉伸那一项,准备页写的是 macOS 27。远程节点从 租用页开通,价格以 定价页为准。
总结
iPhone Duo 10 月 23 日开卖。重新适配的门槛不是「能不能打开」。先看尺寸是不是还在读整块屏幕,方向是不是还在决定内屏,新窗口是不是在外屏上仍可点;这三道门都干净,测试成本就是一轮模拟器矩阵,五个日租等于一个月就改月租。 已经自适应的小 App 用本机或短租。方向、像素和单窗口假设还在的,用月租把回归留住。截图徽章解决不了留白。远程节点从 租用页 和 定价页 查看,账户和系统版本走 帮助中心。