Xcode 27.1 beta:把应用放进 iPhone Duo 模拟器

Xcode 27.1 beta(27A9269)于 2026 年 9 月 18 日星期五发布,带来第一个 iOS 27.1 SDK,以及一个供模拟器使用的 iPhone Duo 设备类型,距 Xcode 27.0 只有四天。这个 SDK 收齐了 Apple 适配指南点名的全部 iPhone Duo API;设备类型的配置文件把两块显示屏定义为 3 倍缩放下的 1398 × 2034 像素和 2007 × 2853 像素,也就是 466 × 678 点与 669 × 951 点;模拟器运行时则是单独的下载,由 Xcode 按需取回。Apple 自己的说明列出了模拟器目前还做不到的三件事。我把一个针对 27.1 SDK 链接的探针应用放进 Device Hub 的三种姿态里跑:合上时它占满 466 × 678 点的屏幕,栏沿 trailing 边缘竖向排列;展开时占满 951 × 669 点的屏幕,两个方向都是 regular,折痕以 division 的形式报告,摄像头和状态列以 occlusion 的形式报告;而当应用已经在内屏上时,UIScreen.main 答的仍然是外屏。(10 月 2 日更正:在此之前,这一段说探针没有看到任何保留区域;那个探针当时被链接成了 iOS 27.0 应用。)1245613

TL;DR

  • 日期与构建版本。 Apple 的 Releases 信息源把 Xcode 27.1 beta(27A9269)标在 9 月 18 日星期五。xcodebuild -version 打印 Xcode 27.1 和 Build version 27A9269;iPhoneOS 与 iPhoneSimulator 两个 SDK 都自称 iOS 27.1、构建版本 24A94403;Swift 编译器报出的版本字符串 swiftlang-6.4.0.34.1 与 Xcode 27.0 相同,链接器的 ld-27037.1 也一样。xip 为 2,027,292,809 字节,展开后的应用 3.6 GiB,并且是装在 Xcode 27.0 旁边,不会替换它。14(10月11日:Xcode 27.1 RC(27A9275)随后于 10 月 5 日发布,App Store Connect 不仅在 TestFlight 中、也在 App Store 上接受用它构建的版本。14)(10月15日:Xcode 27.1 已作为正式版发布,构建号 27A9275,与 RC 相同,App Store Connect 当天的条目以这个名称接受其构建上架商店。15)
  • Duo API 已经在 SDK 里。 我在 9 月 17 日那次检查中没能在 27.0 SDK 里找到的十个名字,在 27.1 SDK 中全部出现,其中包括 SwiftUICore 的 ArrangementView 和 reservedRegions(kind:options:layoutDirectionBehavior:)、SwiftUI 的 toolbarVerticalBehavior(_:),以及 UIKit 的 UIArrangementViewController、preferredVerticalBarBehavior 和 verticalBarEdge。SwiftUI 给它们标的是 @available(anyAppleOS 27.1, *);UIKit 的头文件给 arrangement 控制器和保留区域方法标的是 API_AVAILABLE(ios(27.1), tvos(27.1), visionos(27.1)),比文档页面列出的多两个平台。4
  • 模拟器的配置文件把屏幕尺寸写了下来。 iPhone Duo 设备类型(iPhone19,4,产品类 V68,型号 A3447)定义了两块内建显示屏:primary 为 1398 × 2034 像素、缩放 3,primary-1 为 2007 × 2853 像素、缩放 3,原生方向 270。各除以 3 就是 466 × 678 点和 669 × 951 点,其中内屏的数字,正是我那篇 Duo 开发者文章在 9 月 10 日从 App Store Connect 截图尺寸推算出来的值。配置文件要求运行时为 27.1 或更高。5
  • 把真实应用放上去会怎样(10 月 2 日更正)。 Device Hub 提供三种姿态:Closed(合上)、Book(半开)、Open(展开),另加 Rotate Right(向右旋转)。针对 27.1 SDK 链接的探针,合上时拿到整块外屏,466 × 678 点,宽度 compact,工具栏和标签栏竖立在 trailing 边缘,toolbarVerticalEdge 读作 trailing,并报告两个活动的 occlusion 区域,分别是摄像头和状态列。展开时它拿到整块内屏,原生横向的 951 × 669 点,两个方向都是 regular,栏同样是竖向的,中间还有一条 40 点宽、纵贯屏幕的非活动 division,到 Book 姿态时变为活动;旋转之后是 669 × 951 点,栏为横向。应用在内屏上时,UIScreen.main.bounds 仍然报告 466 × 678。10 月 2 日之前,这一条给出的是屏幕尺寸 466 × 678 和 951 × 669,展开时左右安全区域内边距各 34,工具栏横向,任何姿态下都没有保留区域;正文给出的则是探针量到的区域,比屏幕窄 80 点(合上时 386 点,展开时 34 点内边距之内的 803 点)。这些全部来自一个被误链接成 iOS 27.0 应用的探针:那是 27.0 SDK 的应用会得到的结果,下面的更新列出了两种构建的数据。61213
  • 这个 beta 还做不到什么。 Apple 的说明写道:“Initial Simulator launch can take several minutes.”(187708500)、“StandBy is unavailable in the iPhone Duo Simulator runtime.”(187708663),以及“Running and debugging most app extensions is unavailable in the iPhone Duo Simulator runtime.”(187708767)。如果你的应用同时发往 Mac,还要再加上两条 Mac Catalyst 的 Known Issues。另外还有一件 Apple 没有列出的事:运行时下载在我第一次尝试时以 Download failed. 失败,重试才成功。23

10 月 2 日更新:9 月的探针被链接成了 iOS 27.0 应用

本文从 9 月 21 日到 10 月 2 日所载的模拟器结果,测量是对的,描述是错的。它们是 iPhone Duo 模拟器对一个用 iOS 27.0 SDK 构建的应用所做的事。我却把它们当成了模拟器对用 27.1 构建的应用所做的事。

哪里出了错。 探针是单个 Swift 文件,通过直接调用 swiftc -sdk <iPhoneSimulator27.1.sdk> 编译。这个参数能传到编译器,却传不到链接这一步。在链接时,驱动程序退回到同一个 Xcode 里的 macOS SDK,并把那个 SDK 的版本记进了二进制文件:LC_BUILD_VERSION 读作 sdk 27.0。iOS 正是根据这个数字决定给应用哪些行为。10 月 2 日重新运行同一条命令,它会把原因作为警告打印出来:“using sysroot for ‘macOS 27.0’ but targeting ‘arm64-apple-ios27.1.0-simulator’”(目标是 arm64-apple-ios27.1.0-simulator,却在使用 macOS 27.0 的 sysroot)。如果 9 月时它也打印了这条警告,我并没有把它当成任何问题的原因。13

怎么发现的。 10 月 2 日,我在同一个模拟器上运行了一个真实应用,它由 Xcode 27.1 beta 用同一个 SDK 构建。它的工具栏和标签栏沿外屏侧边竖立,而探针的工具栏和标签栏当初是横躺在顶部的。对两个二进制文件运行 otool -l,应用显示 sdk 27.1,按 9 月的方式重新构建的探针显示 sdk 27.0。设置 SDKROOT 后重新构建,探针读作 sdk 27.1,表现也与那个应用一致。另外,用 Xcode 27.0 本身、针对真正的 iOS 27.0 SDK 编译的一个简化版探针,得到的窗口与被错误标记的那个版本相同,所以 9 月的数字确实如实反映了 27.0 构建的情况。13

重新运行。 同一份源码,两种方式链接,在每种姿态下,运行在同一个 Xcode 27.1 beta(27A9269)和运行时(24A94401)上:13

姿态 以 SDK 27.0 链接 以 SDK 27.1 链接
Closed 窗口 386 × 678 点,旁边是黑色侧轨;栏为横向;toolbarVerticalEdge 为 nil;没有区域 窗口 466 × 678,即整块屏幕;工具栏和标签栏竖立在 trailing 边缘;toolbarVerticalEdge 为 trailing;两个活动 occlusion
Closed,旋转 窗口 678 × 386;栏为横向;没有区域 窗口 678 × 466;两个尺寸类别都是 compact;栏为竖向;两个活动 occlusion,分别是摄像头和状态列
Open 窗口 871 × 669;栏为横向;没有区域 窗口 951 × 669;栏为竖向;一个非活动 division,一个非活动和一个活动 occlusion
Open,旋转 窗口 669 × 871;栏为横向;没有区域 窗口 669 × 951;栏为横向;toolbarVerticalEdge 为 nil;同样三个区域,随之旋转
Book 同 Open 同 Open,division 为活动
Book,旋转 同 Open 旋转 同 Open 旋转,division 为活动

撤回的内容。 三条陈述,每一条对 27.0 构建都成立,对标记为 27.1 的构建都不成立:工具栏从未竖着画过;reservedRegions 在任何姿态下都什么也没返回;模拟器只把状态侧轨旁边的那块屏幕给了应用。第四条错在原因上:我写过,旋转后 split 形式的 arrangement“stays side by side even though the container is now taller than it is wide”(即便容器此时高大于宽,仍保持左右并排)。实际上,探针里的 arrangement 视图在那块屏幕中本身就是宽大于高,而它是按自己的形状来分栏的;一个填满旋转后屏幕的 arrangement 会上下堆叠,正如 Apple 指南所说。第五条:TL;DR 给出的是屏幕尺寸 466 × 678 和 951 × 669,而正文给出的是探针量到的区域,窄了 80 点(合上时 386 点,展开时 34 点内边距之内的 803 点);27.0 构建从未拿到过整块屏幕。713

仍然成立的内容。 模拟器一节之外的一切:日期与构建版本、SDK 符号表、设备配置文件及其像素和点尺寸、运行时下载、Apple 的 Known Issues。在这一节之内:屏幕尺寸、尺寸类别、Device Hub 提供的姿态、screenConfig 引发的崩溃,以及 UIScreen.main 陷阱;最后这一条在重新运行中以 27.1 标记再次复现。本次更新所取代的 9 月 24 日说明曾推测,那些 0 来自读取保留区域过早,并承诺在若干铰链角度下重新运行。这个推测是错的:27.0 构建无论询问多久都不会返回任何区域。但它从 Molzahn 那里引用的观察成立:正确链接的探针在前六到九次求值中读不到任何区域,此后则全部读到。按铰链角度的运行没有做。1213

如果您照着本文自己做过探针,请检查一下:otool -l <app>/<binary> | grep -A4 LC_BUILD_VERSION。用 Xcode 构建的项目会被正确标记。手工编译的文件,需要在运行 swiftc 之前把 SDKROOT export 为模拟器 SDK。发现这个问题的实战示例里有三方对比,还加上了 iOS 26 标记的情况。

10 月 26 日更新:手机搭载 27.1 发售,以及正式版 SDK 的版本号

据 Apple 新闻编辑室和 Apple 的安全更新页面,iPhone Duo 于 10 月 23 日星期五搭载 iOS 27.1 进入零售店;安全更新页面列出的“iOS 27.1”只对应“iPhone Duo”,没有已公开的 CVE 条目;Releases 信息源从未出现过 iOS 27.1 条目,27.1 的发行说明页面也始终没有出现,索引只列出 27 和 27.2。在这台 Mac 上,Xcode 27.1(27A9275)自 10 月 15 日起就是正式版,iPhoneOS 与 iPhoneSimulator SDK 自称 iOS 27.1、构建版本 24A94232,比上文记录的 beta 的 24A94403 还小;iOS 27.1 模拟器运行时为 24A94425,xcrun simctl list runtimes -j 为它只列出一种受支持的设备类型,即 iPhone Duo;针对它 simctl create 一台 iPhone 16 Pro 会失败,报“Incompatible device”。iOS 27.2 于今天(10 月 26 日)发布(24B119,同一分钟还有第二个 iOS 27.2 构建 24B91020),而 Xcode 27.2 RC(27B48,10 月 19 日)的说明载有四条 iPhone Duo 条目:“Fixed: In the iPhone Duo simulator, an app using CameraCaptureAccessory can use both displays at the same time without an active camera capture session.”(已修复:在 iPhone Duo 模拟器中,使用 CameraCaptureAccessory 的应用可以在没有活动相机捕获会话的情况下同时使用两块显示屏。)(190155353);“When switching between the inner and outer display of the iPhone Duo simulator, modifier keys such as Shift and Command might stop working.”(在 iPhone Duo 模拟器的内屏和外屏之间切换时,Shift 和 Command 等修饰键可能失灵。)(189465196),变通办法是“Click with the mouse on the currently visible screen.”(用鼠标点击当前可见的屏幕。);以及两条沿用自 beta 的已知问题,现在都归在 Device Hub 下:截图“black for up to a few minutes after booting the device”(设备启动后最多几分钟内是黑的)(187146039),以及辅助功能工具“cannot convey screen content on an iPhone Duo within Device Hub”(无法在 Device Hub 内传达 iPhone Duo 上的屏幕内容)(187148389)。关于“APIs specific to iOS 27.1”(iOS 27.1 专有的 API)的 Mac Catalyst 条目没有变化。iOS 27.2 的说明里有一条 UIKit 条目点名了 27.1,即 UIView 默认布局边距归零;一个由同一份源码构建、在 iPhone Duo 模拟器的 27.1 运行时上运行的探针,在其 LC_BUILD_VERSION 标记为 sdk 27.0 时报告 8 点(也就是上文 10 月 2 日更新所警告的手工编译陷阱),标记为 sdk 27.1 时报告零,所以这项变化既取决于系统,也取决于二进制文件链接的 SDK;表格见 iOS 27.2 发行说明一文。16

这个 beta 里有什么?

Apple 的 Releases 信息源把“Xcode 27.1 beta (27A9269)”列在 9 月 18 日星期五上午 10 点(太平洋时间),当天下午还有一条“TestFlight Update”;App Store Connect 同日的发行说明写道:“You can now submit apps built with Xcode 27.1 beta using the SDK for iOS 27.1 beta or iPadOS 27.1 beta for internal and external testing.”1 发行说明的 Overview 则点名了 SDK 的清单:“Xcode 27.1 beta includes Swift 6.4 and SDKs for iOS 27.1, iPadOS 27, tvOS 27, watchOS 27, macOS 27, and visionOS 27. Xcode 27.1 beta supports on-device debugging in iOS 17 and later, tvOS 17 and later, watchOS 10 and later, and visionOS. Xcode 27.1 beta requires a Mac running macOS Tahoe 26.6 or later.”2 这份清单要照字面读:停在 27.1 的平台只有 iOS,SDK 自己的 SDKSettings.plist 报告的版本也是 27.1,而 App Store Connect 把同一个 SDK 叫作“iPadOS 27.1 beta”,这道别扭之处由那篇 Xcode 27 的文章一路带着。

下载比版本号给人的印象要小。xip 为 2,027,292,809 字节,由 Apple 的 Software Update 证书签名,展开后是一个 3.6 GiB 的应用,与 Xcode 27.0 同样大小;就命令行工作而言,用 xip --expand 展开到一个文件夹、重命名为 /Applications/Xcode-27.1-beta.app、再把 DEVELOPER_DIR 指过去,安装就到此为止。随后在 beta 下的第一次 xcodebuild 调用自行花了大约两分钟,安装随包附带的 CoreTypes.pkg 和 XcodeSystemResources.pkg,也就是 xcodebuild -runFirstLaunch 会显式执行的那一步;而其中第二个包,正是把 iPhone Duo 设备类型安放到位的那一个。4 应用里没有的,是模拟器运行时。beta 找到了这台 Mac 上已有的各个 iOS 运行时,其中有 27.0,却没有 27.1;在 beta 下运行 xcodebuild -downloadPlatform iOS,它把缺失的那块称为“iOS 27.1 Simulator (24A94401)”,并通过 Apple 的 mobile-asset 服务以 cryptex 磁盘映像的形式取回,而开发者下载页面上的磁盘映像本身还停在 iOS 18.2 Simulator Runtime。34 第一次尝试以 DVTDownloadable: Download Failed 和 Error Domain=DVTDownloadableErrorDomain Code=41 "Download failed." 告终;第二次加上 -buildVersion 24A94401,把运行时报告为 7.85 GB,顺利跑完,随后 simctl list runtimes 里就列出了“iOS 27.1 (27.1 - 24A94401)”。磁盘空间要预留够:这个运行时是 Xcode 下载量的四倍。3

运行 iOS 27.1 beta 的 iPhone Duo 模拟器首次启动时的外屏:深色主屏幕,左上角是设置图标,右侧边缘竖向排着时钟与 Wi-Fi 状态,右边是一块 Dock 方块,右下角是搜索按钮

iPhone Duo 模拟器首次启动时的外屏,1398 × 2034 像素:状态区沿右侧边缘竖着排列,正是 Apple 的 Human Interface Guidelines 在 iPhone Duo 上安放 Dynamic Island 与状态栏的那一侧。10

怎样获取 iPhone Duo 模拟器?

一共三步,没有一步是网页上的下载按钮。Apple 只在 Xcode 里提供这个模拟器,而且只在 27.1 beta 里:27.2 beta 的说明中有一段旁注写道“Download Xcode 27.1 beta to get the iOS SDK and simulator support for iPhone Duo.”(下载 Xcode 27.1 beta,即可获得 iPhone Duo 的 iOS SDK 和模拟器支持)。8(10月11日:Xcode 27.1 RC(27A9275)已于 10 月 5 日发布,其说明列出了同样的 iPhone Duo Simulator 已知问题,因此说明涵盖 Duo 模拟器的 Xcode 27.1 已不再只有 beta;我还没有安装 RC。14)(10月15日:Xcode 27.1 已作为正式版发布,构建号 27A9275,与 RC 相同,其说明列出了同样两个 Duo 模拟器已知问题;我也没有安装它。15)

  1. Xcode 27.1 beta(27A9269),从开发者下载页面获取,Apple 的 Releases 信息源把它标在 9 月 18 日星期五。展开 xip,把应用以带版本号的名称(例如 /Applications/Xcode-27.1-beta.app)移到 Xcode 27.0 旁边,并在命令行工作时把 DEVELOPER_DIR 指向它;这个 beta 要求 macOS Tahoe 26.6 或更高版本。12
  2. iOS 27.1 运行时,xip 里并不包含。在 DEVELOPER_DIR 指向 beta 的情况下运行 xcodebuild -downloadPlatform iOS,它会取回让 iPhone Duo 设备类型可以启动的 27.1 运行时;Apple 的说明还提醒,除了下载之外,Simulator 首次启动“can take several minutes”(可能要花上几分钟)。我第一次尝试失败了,重试后成功,所以请先重试,再去排查原因。23
  3. Device Hub,设备和它的姿态都在这里。添加或选中 iPhone Duo 设备,启动它,然后使用姿态按钮 Closed、Book 和 Open,以及 Rotate Right;simctl 没有姿态命令。下文按姿态给出的尺寸和截图都来自这条路径。6

Apple 没有浏览器版本。搜索“iPhone Duo simulator online”找到的页面并没有运行 Apple 的 iOS 27.1 运行时,所以无论它画出什么,都不是这里测得的尺寸类别、保留区域或外屏行为的来源;如果想在没有运行时的情况下检查布局,这个 beta 为 Xcode 的 Previews 画布加了一个面向备用显示屏的 Display 分组。2

27.1 SDK 里有 Duo API 吗?

9 月 17 日,我按 Apple 那份“Preparing your app for iPhone Duo”指南里的名字去搜 iOS 27.0 SDK,专属于这台设备的十个一个也没找到。同样的搜索、同样的做法,也就是对模块接口和头文件做一次朴素的文本搜索,换到 27.1 SDK 上就全都找得到。表中的行是搜索用的子串:其中七行承载了十个名字里的九个,因为两个 reservedRegions 方法共用一行,两个 axisBehavior 成员也共用一行;另外三行是这些名字背后的类型,即 ReservedRegion、对应 toolbarVerticalBehavior(_:) 的 ToolbarVerticalBehavior,以及对应 preferredVerticalBarBehavior 的 UIVerticalBarBehavior。4

搜索的子串 SwiftUICore 接口 SwiftUI 接口 UIKit 接口 UIKit 头文件
ArrangementView 45 0 19 4 个文件
UIArrangementViewController 0 0 19 4 个文件
ReservedRegion 16 0 15 3 个文件
reservedRegions 2 0 5 1 个文件
ToolbarVerticalBehavior 0 5 0 0
UIVerticalBarBehavior 0 0 0 1 个文件
verticalBarEdge 0 0 0 1 个文件
toolbarVerticalEdge 1 0 0 0
axisBehavior 0 2 0 1 个文件
preferredVerticalBarBehavior 0 0 0 1 个文件

这张表里有两处细节会影响你怎么写代码。其一,SwiftUI 的那些类型住在 SwiftUICore 里,而这个模块由 import SwiftUI 再导出,所以普通的 import 就能找到它们;其二,可用性属性在平台范围上与文档不一致。SwiftUICore 接口声明 ArrangementView、SwiftUI 接口声明 toolbarVerticalBehavior(_:),两者都在 @available(anyAppleOS 27.1, *) 之下,而 anyAppleOS 是 Apple 用来表示“该版本的所有平台”的简写;与此同时,UIArrangementViewController.h 以及 UIView.h 里的 reservedRegionsOfKind: 方法带的是 API_AVAILABLE(ios(27.1), tvos(27.1), visionos(27.1)) 加上 API_UNAVAILABLE(watchos);在 UIVerticalBarEdge.h 中,枚举和 verticalBarEdge 特性带着同一组标注,而 Leading 与 Trailing 两个成员带的是 API_AVAILABLE(ios(27.1)) API_UNAVAILABLE(visionos) API_UNAVAILABLE(watchos, tvos)。Apple 这五个名字的文档页面,都只列出 iOS 27.1 和 iPadOS 27.1,并标记为 beta。47 照着 iOS 写,其余的让编译器告诉你。

指南用到的名字里,已经存在于 27.0 SDK 的那三个没有变化:presentationPlacement(_:) 仍在 @available(anyAppleOS 27.0, *) 之下,backgroundExtensionEffect() 从 iOS 26 起就一直在;至于指南点名的两个 ToolbarItemPlacement 成员,topBarPinnedTrailing 在 @available(iOS 27.0, visionOS 27.0, *) 之下,而 cancellationAction 除了类型本身的可用性之外没有另行标注。4

模拟器的配置文件怎么说这两块屏?

Apple 随 beta 装上的设备类型 iPhone Duo.simdevicetype,是 /Library/Developer/CoreSimulator/Profiles/DeviceTypes 下一个朴素的 bundle,而它的两个属性列表回答了规格表留着没说的问题。5

profile.plist 给出身份:型号标识符 iPhone19,4,产品类 V68,别名 com.apple.CoreSimulator.SimDeviceType.V68,minRuntimeVersion 为 27.1,还有一条规则,让 27.1 及以上的运行时默认创建这台设备。capabilities.plist 给出硬件:型号 A3447,HomeButtonType 为 2,DeviceSupportsDynamicIsland 为 true,DeviceSupportsEnhancedMultitasking 为 false,IsLargeFormatPhone 为 true,CompatibleDeviceFallback 为 iPhone18,3,设备圆角半径 59,以及一个包含两个内建条目和三个虚拟条目的 displays 数组。5

配置文件中的显示屏 像素 缩放 点 原生方向 圆角半径 色彩空间
primary(“LCD”,屏幕 1) 1398 × 2034 3 466 × 678 0 8、59、8、59 P3
primary-1(“LCD-1”,屏幕 3) 2007 × 2853 3 669 × 951 270 四角均为 55 sRGB

第一行是外屏,与 Apple 的规格表逐像素吻合。第二行是内屏,而它的像素数是 App Store Connect 的截图尺寸 2007 × 2853,而非面板自身的 1878 × 2670:模拟器把内屏按 3 倍缩放渲染成 669 × 951 点,这正是那篇 Duo 开发者文章在 9 月 10 日做过、并明确标注为推断的那道算术。如今 Apple 自己的配置文件带上了这个数字。270 度的原生方向说明内屏是原生横向的,设备展开时宽 951 点、高 669 点,这与 Apple 给出的展开状态尺寸一致。剩下两个数字属于模拟器而非硬件:两块屏都写着每英寸 460 像素、60 Hz,而规格表给内屏面板的是 430 ppi,所以请把 hdpi 当作占位值。5

配置文件还带来了形状。每块显示屏都引用一个帧缓冲遮罩,也就是一份描述可见区域的 PDF。外屏的遮罩四角并不对称,配置文件里的值是一条长边 8、另一条长边 59;依我的判断,半径小的那一侧就是 Apple 设计指南所说的、与中间铰链相接的那一侧。内屏的遮罩则是一个普通的圆角矩形,用的就是配置文件里 55 的圆角值,并且没有为前置摄像头留挖空;也就是说,摄像头造成的遮挡来自运行时的保留区域 API,而不是帧缓冲的形状。510

模拟器里能看到什么?

设备以合上的状态启动。首次启动时外屏显示主屏幕,内屏的帧缓冲亮着却是黑的;simctl io enumerate 会按配置文件里的名字把两块内建屏幕都列出来,primary 为 1398 × 2034,primary-1 为 2007 × 2853,与那些常见的虚拟屏并排。6 姿态住在 Device Hub 里。选中这台 Duo 设备后,它的窗口会把 Rotate Right、Closed、Book 和 Open 显示为辅助功能 API 可以按下的按钮,本节的全部内容都是这么驱动出来的;simctl 没有切换姿态的命令。6

探针是一个单文件的 SwiftUI 应用:一个标签视图,里面是带五个工具栏项目的导航堆栈;一块读数区,显示几何信息、尺寸类别、toolbarVerticalEdge 环境值、铰链,以及带 includeInactive 的两类保留区域;还有一个 split 样式的 ArrangementView。它在每次 body 求值时读取保留区域,并每秒重新求值一次。下面的数字来自 10 月 2 日的重新运行,针对 27.1 SDK 链接;9 月那几次被误链接成 27.0 的运行,放在后面单独的标题下。13

针对 27.1 SDK 链接

Closed。 应用拿到整块外屏:窗口为 466 × 678 点,宽 compact、高 regular。工具栏和标签栏竖立在时钟下方的 trailing 边缘,toolbarVerticalEdge 读作 trailing,UIKit 的 verticalBarEdge 特性读作原始值 2。导航堆栈内的内容为 382 × 562 点,安全区域内边距为顶部 82、底部 34、trailing 一侧 84,这 84 点就是侧轨。系统报告了两个 occlusion 区域,都是活动的:一个是外屏摄像头所在处 37 点见方的区域,另一个是栏上方覆盖摄像头和状态列的 84 × 170 区域。这块屏幕上没有报告 division。横过来之后是 678 × 466,两个尺寸类别都是 compact,栏仍在 trailing 边缘。13

针对 27.1 SDK 链接的探针在 iPhone Duo 模拟器外屏上:内容尺寸 382 × 562 点,尺寸类别为 compact 和 regular,toolbarVerticalEdge 为 trailing,铰链为 closed,两个活动 occlusion,split 形式的 arrangement 上下堆叠,右边缘的一列里依次是时钟和 Wi-Fi 状态、四个工具栏按钮和三个标签按钮

Closed,27.1 SDK:整块 466 × 678 点的屏幕,栏沿 trailing 边缘竖向排列。

Open。 应用移到内屏,处于其原生的横向方向:951 × 669 点的窗口,两个尺寸类别都是 regular,栏仍竖立在 trailing 边缘。内容为 867 × 553,三处内边距不变。系统返回三个区域。一条 40 点宽的 division 在屏幕中部纵贯上下,从 x 455 到 495,两侧各有 20 点边距,它是非活动的:手机是平的。一个 58 × 37 的非活动 occlusion 标出内屏摄像头,按 Apple 设计规范的说法,这颗摄像头“stays hidden until the camera is active.”(在摄像头启用之前一直隐藏)。10 一个 84 × 120 的活动 occlusion 覆盖状态列。split 形式的 arrangement 把两个窗格左右并排,平分宽度。13

针对 27.1 SDK 链接的探针在 Open 姿态的内屏上:内容尺寸 867 × 553 点,尺寸类别为 regular 和 regular,toolbarVerticalEdge 为 trailing,铰链完全展开为 180 度,x 455 处有一个 40 点宽的非活动 division,一个非活动和一个活动 occlusion,split 形式的 arrangement 左右并排,栏位于右边缘的一列中

Open,27.1 SDK:951 × 669 点,折痕被报告为一条纵贯中部的非活动 division。

Book。 Device Hub 的 Book 姿态把铰链报告为部分展开,127 度。窗口尺寸不变。变的是 division:框架相同,现在是活动的。split 形式的 arrangement 随之把分隔线移到折痕上,并让那条 40 点的带子空着,于是主窗格止于 x 455,次窗格从 495 开始。在这个姿态下弹出的表单会偏离中心,移到 leading 一侧的那一半。13

针对 27.1 SDK 链接的探针在 Book 姿态的内屏上:铰链部分展开为 127 度,一个活动 division,split 形式的 arrangement 的两个窗格被屏幕中部一条空带隔开

Book,27.1 SDK:division 变为活动,split 形式的 arrangement 让折痕处空着。

旋转。 在展开状态下按 Rotate Right,得到 669 × 951 点的窗口,两个尺寸类别仍是 regular,栏回到横向:toolbarVerticalEdge 为 nil,工具栏位于顶部时钟旁边,标签栏浮在底部。这与 Apple 的设计规范一致,规范在竖屏的内屏上保留“standard horizontal bars”(标准的横向栏)。10 同样三个区域在旋转后的坐标空间中报告:division 现在是一条横贯中部、高 40 点的带子,平放时非活动,Book 时活动。探针的 arrangement 视图在那块屏幕中宽大于高,所以仍保持左右并排。13

针对 27.1 SDK 链接的探针在旋转为竖屏的内屏上:内容尺寸 669 × 734 点,尺寸类别为 regular 和 regular,toolbarVerticalEdge 为 nil,顶部时钟旁是横向工具栏,底部是浮动的标签栏,一个非活动 division 和两个 occlusion

Open 并旋转,27.1 SDK:栏为横向,折痕现在是一条横带。

有两件事在每种姿态下都成立。其一,保留区域到得晚:每次启动时,探针 body 的前六到九次求值读不到任何区域,之后的每一次都能全部读到,所以只在第一次布局时问一次的视图,得到的是一个空答案。Sven-Eric Molzahn 的 DuoProbe 测试夹具在 9 月 20 日就记录了这一现象,以及那条 40 点的带子:“reservedRegions is empty on the first geometry evaluation and populated on a later one”(reservedRegions 在第一次几何计算时为空,在之后的某次计算中才有内容)。SwiftLee 9 月 22 日的模拟器指南补充说“Holding Option ⌥ reveals a slider that you can use to control the hinge angle of the device with precision”(按住 Option ⌥ 会出现一个滑块,可以用它精确控制设备的铰链角度),这个滑块我没有用过。12 其二,当应用在内屏上时,UIScreen.main.bounds 答的是 466 × 678 点,也就是外屏,这正是 Apple 指南提醒要把布局计算“based on your scene or containing view’s bounds rather than screen dimensions”(基于场景或所在视图的 bounds,而不是屏幕尺寸)时所警告的陷阱:主屏幕并不是你正身处的那块屏幕。窗口场景自己的屏幕,报告的才是应用实际所在的那块显示屏。713

通往其他姿态的路,有一条是走不通的。simctl io screenConfig 可以把某块屏幕断电,但在内屏亮着的情况下把外屏断电,并不会让手机展开;它反而让模拟器的 system shell 崩溃,随后的 simctl launch 以“The system shell probably crashed.”失败,只能重启。姿态住在 Device Hub 的窗口里。6

针对 27.0 SDK 链接

以下是本节在 10 月 2 日之前所载的数字:9 月 19 日和 20 日用一个有导航堆栈、没有标签视图的探针测得,10 月 2 日又用当前的探针重测了一遍。它们描述的是用 Xcode 27.0 构建的应用在这个模拟器上得到的东西。613

Closed 时,窗口在 466 点宽的屏幕上只有 386 点宽:系统把 80 点的侧轨留给自己,在那里以黑底绘制时钟和状态,应用的工具栏横躺在顶部。Open 时,窗口为 871 × 669,右侧同样少了 80 点,左右安全区域内边距各 34。Open 并旋转时,这 80 点改从顶部扣除。在每种姿态下,尺寸类别都与 27.1 构建相同,toolbarVerticalEdge 为 nil,verticalBarEdge 读作原始值 0,两次保留区域查询即便算上非活动区域、无论探针持续询问多久,都返回空数组;Book 与 Open 毫无区别。

以 SDK 27.0 链接的 9 月探针在 iPhone Duo 模拟器外屏上:右上角的工具栏里有分享图标、省略号溢出按钮和对勾,数值为尺寸 386 × 510 点,尺寸类别 compact 和 regular,toolbarVerticalEdge 为 nil,divisions 0、occlusions 0,split 形式的 arrangement 中主视图位于次视图之上,时钟和 Wi-Fi 状态堆叠在右边缘的黑色侧轨上

Closed,以 27.0 链接:应用止步于侧轨,工具栏保持横向。

以 SDK 27.0 链接的 9 月探针在 Open 姿态的内屏上:尺寸 803 × 515 点,尺寸类别 regular 和 regular,toolbarVerticalEdge 为 nil,divisions 0、occlusions 0,split 形式的 arrangement 中主视图与次视图左右并排,工具栏在右上角,时钟和 Wi-Fi 状态位于右边缘的黑色侧轨中

Open,以 27.0 链接:两个方向都是 regular,侧轨被系统占着。

以 SDK 27.0 链接的 9 月探针在旋转为竖屏的内屏上:尺寸 669 × 703 点,尺寸类别 regular 和 regular,split 形式的 arrangement 左右并排,时钟和 Wi-Fi 状态位于横贯顶部的黑色带子中

旋转,以 27.0 链接:横贯顶部的那条带子属于系统。

这个 beta 还做不到什么

Apple 在 beta 自己的说明中,于 Simulator、Known Issues 下列了三条限制:“Initial Simulator launch can take several minutes.”(187708500)、“StandBy is unavailable in the iPhone Duo Simulator runtime.”(187708663),以及“Running and debugging most app extensions is unavailable in the iPhone Duo Simulator runtime.”(187708767)。2 其中 StandBy 那条,对于做了相应小组件或实时活动的人很要紧:Apple 的发布稿说这台手机“enters StandBy on either the outer or inner display”(在外屏或内屏上进入 StandBy),并把它称作“hub for widgets”(小组件的中枢);那里会出现什么,那篇 Duo 开发者文章已经讲过。在后续 beta 解除这条限制之前,这台设备上的 StandBy 只能到真机上去验(10月15日:正式版的说明仍列有这一条15)。11

另外两条位于 Mac Catalyst、Known Issues 之下,会咬到任何既采用这些 API、又要为 Mac 构建的应用:“Projects that use APIs specific to iOS 27.1 show compile errors when building for Mac Catalyst (“undeclared identifier”, “not found”, “has no member”, “cannot find”, etc). (185924957)”,Apple 给的绕行办法是在 Swift 中用 #if !targetEnvironment(macCatalyst)、在 Objective-C 中用 #if !TARGET_OS_MACCATALYST;以及“Projects that target iOS 27.1 show no Mac Catalyst run destination available. (187046347)”,绕行办法是“Add a Mac Catalyst 27.0 minimum deployment in target settings.”。2 Xcode 27.2 beta 的说明又从另一个方向补上第三条:“macOS, watchOS, tvOS, and visionOS SDKs in Xcode 27.2 incorrectly report 27.1 as a valid deployment target,”以及“Mac Catalyst builds with a 27.1 or 27.2 deployment target may be unable to use newly introduced API.” (187160501)。8

这周我会做什么

  1. 把 beta 装在 Xcode 27.0 旁边,而不是覆盖它:展开 xip、重命名应用,再把 DEVELOPER_DIR 指向它用于命令行构建。beta 的说明里没有任何一项改动 27.0 的工具链,编译器和链接器的版本字符串也完全相同。4
  2. 在真正需要之前就开始下载运行时:在 beta 下执行 xcodebuild -downloadPlatform iOS,失败就重试。正是这个运行时让 iPhone Duo 设备类型可以启动,而且 Apple 还警告说首次启动要再花上几分钟。23
  3. 带上 Mac Catalyst 目标,对着 27.1 SDK 构建一次,并在决定是用 #if !targetEnvironment(macCatalyst) 把新 API 围起来、还是把 Catalyst 最低部署版本提到 27.0 之前,先读一读 Apple 点名的那两条诊断。2
  4. 把配置文件里的数字当作预览和测试的尺寸:合上 466 × 678 点,展开 669 × 951 点,内屏原生横向。beta 的 Previews 说明还在画布的覆盖选择器里加了一个 Display 分组,“for previewing content on a device’s alternative display.”(用于在设备的另一块显示屏上预览内容)(182598534)25
  5. 在会被反复读取的地方读取保留区域:在视图的 body 里通过几何代理读取,或者在每次几何变化时读取,绝不要只在第一次布局时读一次。带 .includeInactive 的 reservedRegions(kind:options:layoutDirectionBehavior:) 在探针的前六到九次求值中什么也没返回,之后的每一次都返回这块屏幕上的全部区域(合上时是摄像头和状态列;展开时是折痕、内屏摄像头和状态列),所以第一次求值时缓存下来的值,在这个视图的整个生命周期里都是空数组。另外,在相信这一切之前,先确认构建被标记为 27.1 SDK:otool -l <app>/<binary> | grep -A4 LC_BUILD_VERSION。713

常见问题

Xcode 27.1 beta 里有 iPhone Duo 模拟器吗?

有。这个 beta 会装上一个 iPhone Duo 设备类型,即 com.apple.CoreSimulator.SimDeviceType.iPhone-Duo,它的配置文件要求一个 iOS 27.1 运行时,而该运行时由 Xcode 通过 xcodebuild -downloadPlatform iOS 单独下载。Apple 的说明提醒,首次启动“can take several minutes”(可能要花上几分钟),并且在该运行时中无法使用 StandBy 和大多数 App Extension。235

如何获取 iPhone Duo 模拟器?

安装 Xcode 27.1 beta,在该 beta 下用 xcodebuild -downloadPlatform iOS 下载 iOS 27.1 运行时,然后在 Device Hub 里选择 iPhone Duo 设备,姿态就是那里的按钮。27.2 beta 并不包含它;Apple 的 27.2 说明把开发者指向 27.1 beta,以获得“the iOS SDK and simulator support for iPhone Duo.”(iPhone Duo 的 iOS SDK 和模拟器支持)。238(10月11日:Xcode 27.1 RC(27A9275)已于 10 月 5 日发布,其说明列出了同样的 iPhone Duo Simulator 已知问题,因此说明涵盖 Duo 模拟器的 Xcode 27.1 已不再只有 beta;我还没有安装 RC。14)(10月15日:Xcode 27.1 已作为正式版发布,构建号 27A9275,与 RC 相同,其说明列出了同样两个 Duo 模拟器已知问题;我也没有安装它。15)

有在线的 iPhone Duo 模拟器吗?

Apple 没有提供。在 RC 推出之前,这个模拟器只随 Xcode 27.1 beta 提供,运行的是 Apple 的 iOS 27.1 运行时;打着这个名字的浏览器页面画的是别的东西。如果只想快速检查布局,beta 的 Previews 画布提供了面向备用显示屏的 Display 分组。2(10月11日:Xcode 27.1 RC(27A9275)已于 10 月 5 日发布,其说明列出了同样的 iPhone Duo Simulator 已知问题,因此说明涵盖 Duo 模拟器的 Xcode 27.1 已不再只有 beta;我还没有安装 RC。14)(10月15日:Xcode 27.1 已作为正式版发布,构建号 27A9275,与 RC 相同,其说明列出了同样两个 Duo 模拟器已知问题;我也没有安装它。15)

怎样把 Xcode 27.1 beta 装在 Xcode 27 旁边?

用 xip --expand 展开 xip,把得到的应用移成一个带版本号的名字,例如 /Applications/Xcode-27.1-beta.app,再为 xcodebuild、xcrun 和 swiftc 把 DEVELOPER_DIR 设到它的 Contents/Developer 文件夹。这个 beta 要求 macOS Tahoe 26.6 或更高,与 Xcode 27.0 的门槛相同。24

iPhone Duo 内屏按点算是多大?

669 × 951 点。模拟器的设备配置文件把内屏定义为缩放 3 下的 2007 × 2853 像素,且原生方向为横向;外屏则是缩放 3 下的 1398 × 2034 像素,合 466 × 678 点。5

Xcode 27.1 beta 会改动 iOS 27.0 SDK 或 Xcode 27 的工具链吗?

不会。Swift 编译器和链接器报出的版本字符串与 Xcode 27.0 相同,而这个 beta 的发行说明只有 Mac Catalyst、Previews 和 Simulator 三节,没有一节触及工具链。iOS 27.1 SDK 是新增的,在设备端和模拟器端的 SDK 中都标识为构建版本 24A94403。24

iPhone Duo 什么时候发售,运行什么系统?

10 月 23 日,运行 iOS 27.1,依据是 Apple 9 月 16 日的新闻稿:“When iPhone Duo becomes available on October 23, it will run iOS 27.1.”9(10 月 26 日:确实如此,而且 iOS 27.1 没有在其他任何设备上发布;Apple 的安全页面只把它列给 iPhone Duo,这台 Mac 上的 27.1 模拟器运行时也只接受 iPhone Duo 这一种设备类型。16)

本站相关内容:Duo 开发者文章给出了这篇文章拿去和 SDK 对照的参数表数字与 API 清单;为 iPhone Duo 做设计的文章读的是 Apple 的设计指南;可调整大小的 iPhone 检查清单正是这些配置文件数字要喂进去的布局功课;Xcode 27 汇总文章收着按日期编排的 beta 小节;Xcode 27 构建失败文章讲的是这个 beta 没有动过的工具链;iOS 27 发行说明文章则在追 27.x 的构建。

参考来源


  1. Apple,Releases,2026 年 9 月 19 日获取的 RSS 信息源:“Xcode 27.1 beta (27A9269)”标注为 Fri, 18 Sep 2026 10:00:00 PDT,“TestFlight Update”标注为 Fri, 18 Sep 2026 14:00:00 PDT。Apple,App Store Connect 发行说明,2026 年 9 月 18 日,TestFlight 更新,全文引用。 ↩↩↩↩

  2. Apple,Xcode 27.1 Beta Release Notes,2026 年 9 月 19 日通过文档 JSON 端点获取:Overview,引用;Mac Catalyst、Known Issues 185924957 和 187046347 连同其绕行办法,引用;Previews、New Features 182598534,引用;Simulator、Known Issues 187708500、187708663 和 187708767,引用。这份说明再无其他章节。 ↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩

  3. 作者在 macOS 26.6.2(25G83)上于 2026 年 9 月 19 日进行的运行时下载,DEVELOPER_DIR 指向 Xcode 27.1 beta:xcodebuild -downloadPlatform iOS 对已安装的 27.0 运行时打印“iOS is already downloaded.”,随后打印“Downloading iOS 27.1 Simulator (24A94401) (arm64)”,接着是 DVTDownloadable: Download Failed. Downloadable: DVTDownloadable(identifier: 0a4e7582-0061-5907-bea9-fe234c1f9392, version: 27.1.0.1, category: simulator, contentType: cryptexDiskImage, downloadMethod: mobileAsset, platform: com.apple.platform.iphoneos) 和 Error Domain=DVTDownloadableErrorDomain Code=41 "Download failed.";重试的 xcodebuild -downloadPlatform iOS -buildVersion 24A94401 打印“Downloading iOS 27.1 Simulator (24A94401) (arm64): 0.0% (66 kB of 7.85 GB)”并完成,此后 xcrun simctl list runtimes 列出“iOS 27.1 (27.1 - 24A94401) - com.apple.CoreSimulator.SimRuntime.iOS-27-1”。同日以登录状态在 Apple 开发者下载页面搜索“Simulator Runtime”,列出的磁盘映像最新不过 iOS 18.2 Simulator Runtime。 ↩↩↩↩↩↩↩

  4. 作者于 2026 年 9 月 19 日对 /Applications/Xcode-27.1-beta.app 的检查:xcodebuild -version 打印 Xcode 27.1 和 Build version 27A9269;xcrun --sdk iphoneos --show-sdk-version 与 xcrun --sdk iphonesimulator --show-sdk-version 都打印 27.1;两个 SDK 的 SystemVersion.plist 都带有 ProductBuildVersion 24A94403 和 ProductVersion 27.1;xcrun swift --version 打印 Apple Swift version 6.4 (swiftlang-6.4.0.34.1 clang-2100.3.34.1),xcrun ld -v 打印 ld-27037.1,与同一台 Mac 上 Xcode 27.0(27A266a)打印的版本字符串相同。Xcode_27.1_beta.xip 为 2,027,292,809 字节;pkgutil --check-signature 报告为“signed Apple Software”,证书链来自 Software Update;对展开后应用执行 du -sk 得到 3,813,336 KB,而展开在 /Applications/Xcode-27.app 的 Xcode 27.0(27A266a)为 3,804,188 KB。名称计数来自对 iPhoneOS SDK 中 SwiftUICore.swiftmodule/arm64e-apple-ios.swiftinterface、SwiftUI.swiftmodule/arm64e-apple-ios.swiftinterface 和 UIKit.swiftmodule/arm64e-apple-ios.swiftinterface 的 grep -c,以及对 UIKit.framework/Headers 全目录的 grep -rl 文件数;可用性属性同样读自这些文件:SwiftUICore 接口中 public struct ArrangementView< 之上,以及 SwiftUI 接口中声明 func toolbarVerticalBehavior 的那个 extension SwiftUICore.View 之上,都是 @available(anyAppleOS 27.1, *);UIArrangementViewController.h、UIView.h 中两处 reservedRegionsOfKind: 声明,以及 UIVerticalBarEdge 枚举和 verticalBarEdge 特性上,都是 API_AVAILABLE(ios(27.1), tvos(27.1), visionos(27.1)) 后接 API_UNAVAILABLE(watchos),而其 UIVerticalBarEdgeLeading 与 UIVerticalBarEdgeTrailing 成员上是 API_AVAILABLE(ios(27.1)) API_UNAVAILABLE(visionos) API_UNAVAILABLE(watchos, tvos);func presentationPlacement 之上是 @available(anyAppleOS 27.0, *);public static let topBarPinnedTrailing 之上是 @available(iOS 27.0, visionOS 27.0, *),public static let cancellationAction 之上没有属性。关于首次启动:在 beta 的 DEVELOPER_DIR 下第一次执行的 xcodebuild -version 超过了两分钟的超时;/var/log/install.log 记录 xcodebuild 于 9 月 19 日 16:01:54 排入一次 PackageKit 安装,从 Xcode-27.1-beta.app/Contents/Resources/Packages 解出 CoreTypes.pkg 和 XcodeSystemResources.pkg,并于 16:03:04 结束;此后 xcodebuild -checkFirstLaunchStatus 返回 0。 ↩↩↩↩↩↩↩↩↩↩↩

  5. /Library/Developer/CoreSimulator/Profiles/DeviceTypes/iPhone Duo.simdevicetype,由 Xcode 27.1 beta 安装,于 2026 年 9 月 19 日用 plutil -convert xml1 读取。profile.plist:modelIdentifier iPhone19,4,productClass V68,aliases com.apple.CoreSimulator.SimDeviceType.V68,minRuntimeVersion 27.1,createByDefaultForRuntimeVersions 的 versionMin 27.1。capabilities.plist:ModelNumber A3447,ThinningProductType iPhone19,4,CompatibleDeviceFallback iPhone18,3,DeviceCornerRadius 59,HomeButtonType 2,DeviceSupportsDynamicIsland true,DeviceSupportsEnhancedMultitasking false,IsLargeFormatPhone true;ScreenDimensionsCapability 的 main-screen-width 1398、main-screen-height 2034、main-screen-pitch 460、main-screen-scale 3;displays:primary(displayName LCD,screenID 1,width 1398,height 2034,scale 3,hdpi 与 vdpi 460,refreshRate 60,nativeOrientation 0,cornerRadiusUL 8、UR 59、LL 8、LR 59,colorspace P3)与 primary-1(displayName LCD-1,screenID 3,width 2007,height 2853,scale 3,hdpi 与 vdpi 460,refreshRate 60,nativeOrientation 270,四个圆角半径均为 55,colorspace sRGB),另有 external-0(TVOut)、wireless0(carPlay)和 resizable(scene)。两个 framebufferMaskIdentifier 的 PDF 用 qlmanage 渲染后查看。Apple 规格表上关于面板的数字见那篇 Duo 开发者文章。在 beta 下运行 xcrun simctl list devicetypes 会列出“iPhone Duo (com.apple.CoreSimulator.SimDeviceType.iPhone-Duo)”。 ↩↩↩↩↩↩↩↩↩

  6. 作者在 macOS 26.6.2(25G83)上于 2026 年 9 月 19 日和 20 日的运行。设备:simctl create "Duo-27.1" com.apple.CoreSimulator.SimDeviceType.iPhone-Duo com.apple.CoreSimulator.SimRuntime.iOS-27-1,用 simctl boot 和 simctl bootstatus -b 启动(在这台 Mac 上约一分钟);simctl io <udid> enumerate 列出两个显示类别为 0 的 com.apple.framebuffer.display 端口,分别是 1398 × 2034 和 2007 × 2853,并在 Connected Screens 下列出“LCD-1”,设备名 primary-1,屏幕 ID 3,像素尺寸 {2007, 2853}。探针:DuoProbe,一个单文件 SwiftUI 应用,在 Xcode 27.1 beta 下用 xcrun swiftc -sdk <iPhoneSimulator.sdk> -target arm64-apple-ios27.1-simulator -parse-as-library 构建,用 simctl install 安装,用 simctl launch --console-pty 启动,截图用 simctl io <udid> screenshot --mask=alpha --display=primary 和 --display=primary-1。合上姿态的控制台行:DUOPROBE screen=(466.0, 678.0) scale=3.0 idiom=0 model=iPhone name=Duo-27.1;DUOPROBE size=386x510 h=compact v=regular verticalEdge=nil safe=EdgeInsets(top: 134.0, leading: 0.0, bottom: 34.0, trailing: 0.0);DUOPROBE uikit bounds=(354.0, 44.0) divisions=0 occlusions=0 verticalBarEdge=UIVerticalBarEdge(rawValue: 0);没有 division[ 或 occlusion[ 开头的行。--display=primary-1 的截图是黑的。屏幕电源:simctl io <udid> screenConfig --display=primary power off 打印“Screen 1 power state set to off”;随后的 simctl launch 以 FBSOpenApplicationServiceErrorDomain 代码 5 失败,提示“The system shell probably crashed.”;simctl shutdown 加 boot 让设备恢复。姿态相关的运行在 9 月 20 日分两轮进行,两轮都通过辅助功能 API 对 Device Hub 为所选设备提供的按钮执行 AXPress 动作,依次按下 Rotate Right、Closed、Book 和 Open,并且两轮都由 27.2 beta 的 simctl 命令行工具(脚本所设置的 DEVELOPER_DIR)驱动,针对的是 27.1 beta 的运行时、设备类型和 Device Hub。第一轮中,按下下一个按钮时上一种姿态的探针仍在运行,之后才终止并重新启动,控制台捕获十二秒,并对两块屏幕分别截图;上文中旋转后的读数和过渡行来自这一轮。第二轮中,每次捕获后都终止探针,因此按下下一个按钮时前台没有应用;重新启动前的截图来自这一轮。Open:DUOPROBE size=803x515 h=regular v=regular verticalEdge=nil safe=EdgeInsets(top: 134.0, leading: 34.0, bottom: 20.0, trailing: 34.0)、DUOPROBE uikit bounds=(771.0, 44.0) divisions=0 occlusions=0 verticalBarEdge=UIVerticalBarEdge(rawValue: 0) 和 DUOPROBE screen=(466.0, 678.0);--display=primary-1 的截图中能看到探针,--display=primary 是黑的。Book:重新启动后是同样的三行;按下按钮之后、重新启动之前拍下的内屏截图显示的是主屏幕,此时没有应用在运行。Closed:即上面那几行合上姿态的输出。Rotate Right 之后再 Open:DUOPROBE size=669x703 h=regular v=regular verticalEdge=nil safe=EdgeInsets(top: 134.0, leading: 0.0, bottom: 34.0, trailing: 0.0) 和 uikit bounds=(637.0, 44.0),内屏截图为竖向。没有任何一次运行打印过 division[ 或 occlusion[ 行。旋转后的合上状态只作为姿态切换过程中的过渡行出现过,即 DUOPROBE size=610x232 h=compact v=compact ... screen=(678.0, 466.0),未计入上文。这个构建被标记为 sdk 27.0;参见 10 月 2 日的更新和脚注 13。 ↩↩↩↩↩↩↩

  7. Apple,2026 年 9 月 19 日获取的文档 JSON,涉及 ArrangementView、UIArrangementViewController、reservedRegions(kind:options:layoutDirectionBehavior:)、reservedRegions(kind:options:) 和 toolbarVerticalBehavior(_:):每个页面的平台可用性都写着 iOS 27.1 和 iPadOS 27.1,并标记为 beta。Apple,Preparing your app for iPhone Duo,同日获取,用于确认该指南所使用的名字。 ↩↩↩↩

  8. Apple,Xcode 27.2 Beta Release Notes,2026 年 9 月 19 日获取,SDK、Known Issues、187160501,引用;2026 年 9 月 26 日为 Overview 中的旁注“Download Xcode 27.1 beta to get the iOS SDK and simulator support for iPhone Duo.”重新获取,引用。 ↩↩↩

  9. Apple,“Get ready with the latest beta releases”,新闻,2026 年 9 月 16 日,“Note about iOS 27.1 and iPhone Duo”,引用。 ↩

  10. Apple,Designing for iPhone Duo,Human Interface Guidelines,2026 年 9 月 20 日通过文档 JSON 端点获取:“Controls on the side include both system and app elements: the Dynamic Island, the status bar, the toolbar (including navigation buttons), and the tab bar.”以及“A hinge in the center lets people open and close the device”。2026 年 10 月 2 日重新获取,Vertical controls:“The exception is the inner display in portrait, which has enough vertical space to keep standard horizontal bars.”;Anatomy:“The inner camera is behind the display and stays hidden until the camera is active.” ↩↩↩↩

  11. Apple Newsroom,Apple unveils iPhone Duo,2026 年 9 月 9 日,2026 年 9 月 20 日获取:“Set iPhone Duo down and it enters StandBy on either the outer or inner display”和“hub for widgets”,引自 StandBy 段落。 ↩

  12. Sven-Eric Molzahn,iphone-duo-probe,GitHub README,2026 年 9 月 24 日获取(最新提交为 2026 年 9 月 20 日):引用“Two caveats before reaching for it: reservedRegions is empty on the first geometry evaluation and populated on a later one”和“Half-folded, inner display, content 867 × 575, hinge band at x 455.5…495.5”。Antoine van der Lee,iPhone Duo Simulator: Testing and optimizing your SwiftUI app,SwiftLee,2026 年 9 月 22 日,引用。 ↩↩↩

  13. 作者于 2026 年 10 月 2 日的重新运行:macOS 27.0(26A428),Xcode 27.1 beta(27A9269),iOS 27.1 运行时(24A94401),同一台 Duo-27.1 模拟器。探针:DuoProbe2,单个 Swift 文件,包含一个 TabView(其第一个标签中是带五个工具栏项目的 NavigationStack)、正文所述的读数区,以及一个 UIKit 视图,记录其窗口、窗口场景的屏幕、UIScreen.main 和 verticalBarEdge 特性。从这个文件针对 27.1 模拟器 SDK 构建两次,并告诉链接器要记录哪个 SDK 版本(-Xlinker -platform_version -Xlinker ios-simulator -Xlinker 27.1 -Xlinker 27.0 和 ... 27.1);otool -l 打印 sdk 27.0 和 sdk 27.1。按 9 月的方式做的第三个构建,即在 SDKROOT 未设置时运行 swiftc -sdk <iPhoneSimulator27.1.sdk>,打印了 clang: warning: using sysroot for 'macOS 27.0' but targeting 'arm64-apple-ios27.1.0-simulator',被标记为 sdk 27.0;把 SDKROOT export 为模拟器 SDK 后,同一条命令标记为 sdk 27.1。暴露出差异的真实应用是 Kiradex(941 Apps),由 Xcode 27.1 beta 构建:minos 27.0,sdk 27.1。控制台输出,27.1 标记,合上:size=382x562 ... h=compact v=regular verticalEdge=trailing safe=EdgeInsets(top: 82.0, leading: 0.0, bottom: 34.0, trailing: 84.0) divisions=0 occlusions=2,occlusion[0] active=true frame=(399,-52 37x37),occlusion[1] active=true frame=(382,-82 84x170),window=(466.0, 678.0),verticalBarEdge=2;合上并旋转:size=594x350 ... h=compact v=compact verticalEdge=trailing,window=(678.0, 466.0);展开:size=867x553 ... h=regular v=regular verticalEdge=trailing ... divisions=1 occlusions=2,division[0] active=false frame=(455,-82 40x669) margins=EdgeInsets(top: 0.0, leading: 20.0, bottom: 0.0, trailing: 20.0),occlusion[0] active=false frame=(677,-61 58x37),occlusion[1] active=true frame=(867,-82 84x120),window=(951.0, 669.0),hinge=fullyOpen 180 deg;Book:同上,但 division[0] active=true、hinge=partiallyOpen 127 deg,并且 mainScreen=(466.0, 678.0) 与 sceneScreen=(951.0, 669.0) 并列;展开并旋转:size=669x734 ... verticalEdge=nil safe=EdgeInsets(top: 134.0, leading: 0.0, bottom: 83.0, trailing: 0.0) divisions=1 occlusions=2,division[0] active=false frame=(0,321 669x40),occlusion[0] active=false frame=(611,543 37x58),occlusion[1] active=true frame=(535,-134 134x82),window=(669.0, 951.0),mainScreen=(466.0, 678.0),verticalBarEdge=0;Book 并旋转:同上,但 division[0] active=true。框架采用读数视图的坐标,其原点位于窗口顶部以下 82 或 134 点处。27.0 标记:合上 window=(386.0, 678.0),展开和 Book 为 (871.0, 669.0),展开并旋转为 (669.0, 871.0),合上并旋转为 (678.0, 386.0),每一行都是 verticalEdge=nil、verticalBarEdge=0 和 divisions=0 occlusions=0。PlainProbe 拥有同样的标签视图、导航堆栈和工具栏,不含任何来自 27.1 SDK 的东西,由 Xcode 27.0(27A266a)针对其自带的 iOS 27.0 SDK 编译(otool:minos 27.0,sdk 27.0):合上 window=(386.0, 678.0),展开 (871.0, 669.0)。每次以 27.1 启动时,前六到九次求值在区域出现之前记录的都是 divisions=0 occlusions=0,其中三次发生在视图拥有尺寸之前。摄像头的 occlusion 与 Apple 的“Outer Closed Portrait”边框 PNG 做了比较:在 3 倍下,其摄像头开孔横向跨 400.3 到 436.3 点,纵向跨 29.7 到 65.7 点;occlusion 以窗口点计横向跨 399 到 436,纵向跨 30 到 67,每条边的误差都在 1.3 点以内。窗格位置从截图中测得:平放时主窗格从 x 8 到 433.7,次窗格从 433.7 到 859;Book 时主窗格到 455.7,空带到 495.7,次窗格到 859。探针的表单在展开时测得 653x501、居中,在 Book 时测得 459x501、位于 leading 边缘。加上一个让探针的 arrangement 视图填满内容区的启动选项后,旋转后的屏幕上主窗格显示在次窗格之上,而 .split.axes(.horizontal) 只显示主窗格。 ↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩

  14. Apple,Releases,2026 年 10 月 11 日获取的 RSS 信息源:“Xcode 27.1 RC (27A9275)”日期为 Mon, 05 Oct 2026 10:00:00 PDT。Apple,App Store Connect release notes,2026 年 10 月 11 日获取,2026 年 10 月 5 日的条目:“You can now upload apps built with Xcode 27.1 RC using the SDK for iOS 27.1, iPadOS 27.0, macOS 27.0, tvOS 27.0, visionOS 27.0, and watchOS 27.0 for the App Store, and for internal and external testing through TestFlight.”(现在可以上传用 Xcode 27.1 RC、以 iOS 27.1、iPadOS 27.0、macOS 27.0、tvOS 27.0、visionOS 27.0 和 watchOS 27.0 SDK 构建的应用,用于 App Store,以及通过 TestFlight 进行的内部和外部测试)。Apple,Xcode 27.1 RC Release Notes,2026 年 10 月 11 日获取,Simulator,Known Issues:“StandBy is unavailable in the iPhone Duo Simulator runtime. (187708663)”(iPhone Duo Simulator 运行时中无法使用待机显示)和“Running and debugging most app extensions is unavailable in the iPhone Duo Simulator runtime. (187708767)”(iPhone Duo Simulator 运行时中无法运行和调试大多数 App Extension),与 beta 的说明相同。 ↩↩↩↩

  15. Apple,Releases,2026年10月15日太平洋时间17:16(10月16日 00:16 UTC)获取的RSS信息源:“Xcode 27.1 (27A9275)”日期为 Thu, 15 Oct 2026 13:00:00 PDT,构建号与10月11日获取时的10月5日RC条目相同,信息源中已不再有那个RC条目。Apple,Xcode 27.1 Release Notes,2026年10月15日太平洋时间17:21通过文档JSON端点获取,标题由“Xcode 27.1 RC Release Notes”改为现名;Overview:“Xcode 27.1 includes Swift 6.4 and SDKs for iOS 27.1, iPadOS 27, tvOS 27, watchOS 27, macOS 27, and visionOS 27.”(Xcode 27.1 包含 Swift 6.4 以及 iOS 27.1、iPadOS 27、tvOS 27、watchOS 27、macOS 27 和 visionOS 27 的 SDK);两个iPhone Duo Simulator Known Issues,187708663和187708767,没有变化。Apple,App Store Connect release notes,2026年10月15日太平洋时间17:20获取,2026年10月15日的条目“App Store Connect updates”:“You can now upload apps built with Xcode 27.1 using the SDK for iOS 27.1, iPadOS 27.0, macOS 27.0, tvOS 27.0, visionOS 27.0, and watchOS 27.0 for the App Store, and for internal and external testing through TestFlight.”(现在可以上传用 Xcode 27.1、以 iOS 27.1、iPadOS 27.0、macOS 27.0、tvOS 27.0、visionOS 27.0 和 watchOS 27.0 SDK 构建的应用,用于 App Store,以及通过 TestFlight 进行的内部和外部测试)和“Submit your iPhone Duo optimized apps and games in App Store Connect today. Starting April 2027, any apps or games submitted will need to include screenshots for iPhone Duo.”(今天就在 App Store Connect 中提交为 iPhone Duo 优化的应用和游戏。自2027年4月起,提交的任何应用或游戏都需要包含 iPhone Duo 截图)。同一时段获取的Apple开发者新闻信息源中没有关于这次发布的条目。 ↩↩↩↩↩

  16. Apple Newsroom,“iPhone Duo arrives at Apple Store locations worldwide”,2026年10月23日,10月26日获取:“On Friday, October 23, the highly anticipated iPhone Duo made its debut at Apple Store locations worldwide.”Apple Support,“Apple security releases”,2026年10月26日获取:其中一行为“iOS 27.1”“This update has no published CVE entries.”“iPhone Duo”“23 Oct 2026”,没有链接。Apple,Releases,2026年10月26日太平洋时间16:12获取的RSS信息源:“iOS 27.2 (24B91020)”和“iOS 27.2 (24B119)”的日期为 Mon, 26 Oct 2026 10:00:00 PDT;“Xcode 27.2 RC (27B48)”的日期为 Mon, 19 Oct 2026,是最新的Xcode条目;没有任何条目标题提到iOS 27.1正式版。2026年10月26日获取的iOS & iPadOS Release Notes索引只列出“iOS & iPadOS 27 Release Notes”和“iOS & iPadOS 27.2 Release Notes”;27.1页面的JSON端点返回404。Apple,Xcode 27.2 RC Release Notes,2026年10月26日获取(Last-Modified为 Mon, 19 Oct 2026 04:56:10 GMT):Device Hub,Known Issues(187146039、187148389、189465196附变通办法);Mac Catalyst,Known Issues(185924957);Simulator,Resolved Issues(190155353);引用。Apple,iOS & iPadOS 27.2 Release Notes,2026年10月26日获取:UIKit,New Features(186294594)。作者的Mac,2026年10月26日,macOS 27.0(26A428),Xcode 27.1(27A9275)位于 /Applications/Xcode.app:iPhoneOS.sdk/System/Library/CoreServices/SystemVersion.plist 和 iPhoneSimulator SDK 的 plist 都报告 ProductVersion 27.1 和 ProductBuildVersion 24A94232;xcrun simctl list runtimes 打印“iOS 27.1 (27.1 - 24A94425)”,-j 只列出一个 supportedDeviceTypes 条目“iPhone Duo”;在 com.apple.CoreSimulator.SimRuntime.iOS-27-1 上 xcrun simctl create 一台 com.apple.CoreSimulator.SimDeviceType.iPhone-16-Pro 失败,报“Incompatible device”(SimError 403);边距探针及其输出见 iOS 27.2 发行说明一文的脚注 4。 ↩↩

相关文章

让应用为 iPhone Duo 做好准备:一个完整的实例

为 iPhone Duo 准备并提交应用:决定布局的 SDK 标记、一款真实应用走完每种姿态的过程、两块屏的截图,以及 App Store 的规则。

43 分钟阅读

iOS 27.2发行说明:发布了什么,27.1又去了哪里

iOS 27.2(24B119)于10月26日发布:2项新功能、5项修复、7项已知问题、162个CVE,以及一个只有iPhone Duo得到的iOS 27.1。面向开发者的发行说明解读。

20 分钟阅读

像素艺术建筑:在 iPhone 上盖房子、大厅与室内

宝可梦、SNES 时代的 RPG 和《星露谷物语》如何搭建房屋、室内与楼层,全部从源码实测;以及 Kiradex 的 iPhone 小镇如何盖起真正的建筑。

55 分钟阅读