What's new in tvOS
tvOS 进阶 30m

tvOS 新特性

What's new in tvOS

2025年6月13日

在 Apple 官方观看视频

一句话判断

如果你只做一件事:把你的 tvOS 应用的焦点管理从 UIKit 迁到 SwiftUI 的新 @FocusState 体系,这是回报最高的投入。

这场 Session 讲了什么

tvOS 26 这次的更新量不大,但方向很清楚——Apple TV 不再只是”用遥控器翻翻找找然后播放”的设备了。WidgetKit 进入屏保、SwiftUI 大屏布局补齐、焦点引擎重做,三条线合在一起指向同一个趋势:Apple TV 想成为家里那块”永远亮着的屏幕”,而不只是一个流媒体盒子。

Liquid Glass 落到 tvOS 上的效果比 iOS 自然得多。三米开外看一块大电视,玻璃质感本身就很契合——导航栏通透了,内容区的纵深感反而更强。系统自动给 TabView 和 NavigationBar 套上了 Liquid Glass,你几乎不用动代码。但问题也在这:如果你的 app 有大量自定义控件,光靠系统默认样式是不够的,你得手动处理透明度和背景的协调。

真正让开发者松口气的是焦点引擎的改进。tvOS 开发最大的痛点从来不是 UI,而是遥控器按下之后焦点飞到哪里去了。SwiftUI 和 UIKit 混用的时候尤其离谱——焦点经常跳到你完全没预料到的地方。这次 Apple 终于给了更细粒度的控制手段,focusSectionfocusability 修饰符让你能明确告诉系统”这块区域的焦点该往哪走”。

值得深挖的点

焦点引擎:终于可以精确控制了

tvOS 的焦点引擎是所有 Apple 平台里最独特的交互模型。iOS 开发者习惯触摸,macOS 开发者习惯鼠标,但 tvOS 用户只有一个遥控器和方向键。焦点”飘”到哪里,直接决定了用户能不能顺畅用你的 app。

旧方案的痛点在于,SwiftUI 的 @FocusState 只能绑定一个布尔值或者枚举,当你的界面是一个复杂网格(比如视频流媒体 app 的首页),你根本不知道焦点从第一行最后一个元素按右键之后会跳到哪。更糟的是,当你在 SwiftUI 里嵌套 UIKit 视图(比如自定义播放器),焦点传递经常断掉——UIKit 的 UIFocusGuide 和 SwiftUI 的焦点系统各管各的,互不相让。

tvOS 26 的解法是引入 focusSection 概念。你可以把界面划分成多个焦点区域,每个区域内部有独立的焦点优先级和传递逻辑。这类似于 UIKit 时代你手动摆放 UIFocusGuide 的做法,但声明式写法让维护成本降了一个量级。另一个关键改进是 focusability(_:on:) 修饰符,它允许你针对 tvOS 平台单独控制某个视图是否可获得焦点,而不是像以前那样用 allowsHitTesting(false) 这种”一刀切”的方式。

trade-off 很明确:新 API 的学习成本不低,特别是 focusSection 的嵌套规则,搞错了焦点会陷入死循环。但一旦用对,你的 tvOS app 的遥控器体验会从”碰运气”变成”确定性”。

WidgetKit 进屏保:被动展示的价值

屏保里的 WidgetKit 支持看起来是个小功能,但它打开了一扇门。想想看:Apple TV 待机时间远超主动使用时间。如果用户的客厅里有一台 Apple TV,它一天可能有 20 个小时处于屏保状态。你的小组件如果能在这 20 小时里持续展示有价值的信息——天气、比分、外卖配送进度——那你的 app 在用户心智中的存在感会完全不同。

这跟 iOS 上的 Widget 逻辑不一样。iOS 用户会整理主屏幕,不想要的 widget 随手就删了。但 tvOS 屏保是自动轮播的,用户不需要做任何操作就能看到你的内容。当然,这也意味着你的小组件必须在”远距离可读”这个约束下做设计——大字体、高对比度、信息极度精简。一个塞满文字的 widget 在三米外就是一团模糊。

代码片段

1. 声明焦点区域

场景:网格布局中控制遥控器方向键的焦点走向。

MediaGrid()
    .focusSection(.named("mediaGrid")) {
        $0.onMove(.right, to: .named("sidebar"))
           .priority(.aboveOthers)
    }

坑:focusSection 的命名必须唯一,重名会导致焦点行为不可预测,debug 极其困难。

2. 平台条件焦点控制

场景:同一个视图在 tvOS 上需要焦点,在 iOS 上不需要。

Text("继续观看")
    .focusable(.on(.tvOS)) { isFocused in
        if isFocused {
            highlightCard()
        }
    }

坑:focusable(.on(...)) 是 tvOS 26 新 API,低版本系统会直接编译失败,记得用 #available 做版本守卫。

3. 屏保小组件配置

场景:为 tvOS 屏幕保护程序提供一个天气小组件。

@main
struct WeatherWidget: Widget {
    var body: some WidgetConfiguration {
        StaticConfiguration(kind: "weather", provider: WeatherProvider()) { entry in
            WeatherEntryView(entry: entry)
        }
        .supportedFamilies([.systemLarge])  // 屏保只支持大尺寸
        .contentMarginsDisabled()           // 屏保场景去除边距
    }
}

坑:屏保场景下只支持 .systemLarge.systemExtraLarge,小尺寸小组件不会出现在屏保轮播里。

最佳实践

先花半天时间用 Siri Remote 把自己的 app 从头到尾走一遍,专门观察焦点走向。哪里卡住了、哪里跳错了,记下来。然后对照 tvOS 26 的新焦点 API,优先修那些”焦点飞走”的场景——这是用户感知最强的体验问题。

Liquid Glass 的适配优先级较低。系统控件会自动更新,如果 app 主要依赖标准 TabView 和 NavigationView,基本不需要改。只有自定义控件才需要手动处理透明度。

屏保小组件建议花一天时间做一个 PoC。成本很低——已有 WidgetKit 的话,加一个 .systemLarge 的配置就行。但回报可能超出预期,特别是 app 有”信息类”内容(天气、体育、新闻)的场景。

还有什么值得关注

  • SharePlay 的多人同步改进支持更灵活的交互延迟容错,适合派对游戏和多人观影场景,但 Session 里没有给具体 API 变化。
  • SwiftUI 的 LazyVGrid 在 tvOS 上的性能有明显提升,大列表滚动不再掉帧了,这对内容浏览类 app 是直接的体验改善。
  • 自定义视频播放叠加层现在支持章节导航 UI,可以不离开播放界面就切换章节,对长视频内容(课程、纪录片)体验提升明显。
tvOS SwiftUI UIKit