WWDC Quick Look 💓 By SwiftGGTeam
What's new in watchOS

What's new in watchOS

观看原视频

Highlight

watchOS 26 把 Controls、可配置 Widget 与基于 WidgetRelevance 的相关性信号一起开放给开发者,并将 Apple Watch Series 9 及以后机型迁移到 arm64 架构。


核心内容

过去做 Apple Watch 应用,开发者最头疼的一件事,是用户必须主动打开应用,才能用上你的功能。表盘上空间有限,复杂功能在小屏上又很难跑得起来。结果就是:很多 iPhone 应用在 Apple Watch 上只剩一个图标,用户点开几次就再也不点了。

watchOS 26 同时改了三件事,把这条路径打通。第一,Controls 来到 Apple Watch(04:04),可以放进 Control Center、Smart Stack,也能绑定到 Apple Watch Ultra 的 Action 按钮,用一次轻点就触发动作。第二,Widget 现在支持配置(06:53),同一份代码可以让用户自己挑选 Widget 展示的内容。第三,相关性 API 升级了:通过 WidgetRelevanceRelevanceEntriesProvider,应用可以告诉系统”在什么场景下值得把我推到 Smart Stack 顶部”,比如位置进入海滩附近、某个时间点临近活动开始(10:5314:37)。

底层也换了发动机。Apple Watch Series 9 及以后机型在 watchOS 26 上迁移到 arm64 架构(02:46)。Xcode 14 起就支持构建 arm64 的 watchOS 应用,模拟器在 Apple Silicon Mac 上一直跑的也是 arm64,所以多数项目只要打开 “Standard Architectures” 即可。需要注意的是 Float、Int 与指针运算在 arm64 上的差异,建议在模拟器与真机上各跑一遍。


详细内容

让 Widget 可配置是这一代 watchOS 最直接的”代码改动”。在 AppIntentTimelineProvider 里返回空数组,就能允许用户自己配置 Widget 内容:

// In the AppIntentTimelineProvider
func recommendations() -> [AppIntentRecommendation<BeachConfigurationIntent>] {
  return []
}

关键点:

  • recommendations()AppIntentTimelineProvider 协议的方法,用来告诉系统有哪些预设配置。
  • 返回 [] 表示不提供预设,让用户自己进入配置界面挑选参数。
  • 泛型参数 BeachConfigurationIntent 是你定义的 AppIntent,承载 Widget 的可配置字段。

如果你的 Widget 需要兼容老系统,加一层 #available 判断即可(07:06):

// In the AppIntentTimelineProvider
func recommendations() -> [AppIntentRecommendation<BeachConfigurationIntent>] {
  if #available(watchOS 26, *) {
    // Return an empty array to allow configuration of the widget in watchOS 12+
    return []
  } else {
    // Return array of recommendations for preconfigured widgets before watchOS 12
    return recommendedBeaches
  }
}

关键点:

  • watchOS 26 上交给用户配置;旧系统继续返回预设列表,避免没法配置时看到一个空 Widget。
  • recommendedBeaches 是你自己维护的预设数组,类型为 [AppIntentRecommendation<BeachConfigurationIntent>]

Control 也可以做成可配置形态(07:46):

struct ConfigurableMeditationControl: ControlWidget {
  var body: some ControlWidgetConfiguration {
    AppIntentControlConfiguration(
      kind: WidgetKinds.configurableMeditationControl,
      provider: Provider()
    ) { value in
      // Provide the control's content
    }
    .displayName("Ocean Meditation")
    .description("Meditation with optional ocean sounds.")
    .promptsForUserConfiguration()
  }
}

关键点:

  • ControlWidget 是控件类型,AppIntentControlConfiguration 把 Control 与一个 AppIntent 关联起来。
  • kind 是 Control 的稳定标识,建议在跨平台时让 iOS 和 watchOS 端共用同一个常量。
  • .promptsForUserConfiguration() 让 Control 在添加到系统时直接弹出配置界面,避免用户先放后改。

相关性信号是把 Widget 推到 Smart Stack 顶部的关键。点位类相关性最简单(10:53):

func relevance() async -> WidgetRelevance<Void> {
  guard let context = RelevantContext.location(category: .beach) else {
    return WidgetRelevance<Void>([])
  }
  return WidgetRelevance([WidgetRelevanceAttribute(context: context)])
}

关键点:

  • RelevantContext.location(category:) 描述一个语义化的位置场景,比如海滩、健身房,由系统判断当前是否符合。
  • WidgetRelevanceAttribute 把上下文打包成系统可以读取的相关性属性。
  • 返回空数组表示当前不申请任何相关性,Smart Stack 不会主动展示。

如果 Widget 是可配置的,需要给每个具体配置都标注它的相关性(14:37):

struct BeachEventRelevanceProvider: RelevanceEntriesProvider {
  let store: BeachEventStore

  func relevance() async -> WidgetRelevance<BeachEventConfigurationIntent> {
    // Associate configuration intents with RelevantContexts
    let attributes = events.map { event in
      WidgetRelevanceAttribute(
        configuration: BeachEventConfigurationIntent(event: event),
        context: .date(interval: event.date, kind: .default)
      )
    }

    return WidgetRelevance(attributes)
  }
}

关键点:

  • RelevanceEntriesProvider 让你为多个配置实例分别声明相关性。
  • .date(interval:kind:) 表示相关性窗口与某个时间区间挂钩,活动临近时系统会自动提升优先级。
  • events.map 把数据源映射成系统识别的属性数组,是把领域数据接入 Smart Stack 的常见模式。

核心启发

  • 做什么:先把项目升级到 arm64 架构,所有 C/Objective-C 依赖跟着确认一遍。

    • 为什么值得做:这是 watchOS 26 上一切优化的前置条件,依赖卡住会让后面的工作全部停摆。
    • 怎么开始:在 Xcode 里把 Apple Watch target 的 Architectures 切到 Standard Architectures,跑一遍真机,关注 Float/Int 转换与指针运算的告警。
  • 做什么:为应用最高频的一个动作做一个 Control,并和 iOS 端共用 kind 标识。

    • 为什么值得做:Control 是 watchOS 26 新增的零打开成本入口,Action 按钮、Smart Stack、Control Center 三处都能用,写一次覆盖多个系统空间。
    • 怎么开始:从「开始一次冥想」「记一笔账」「打开常用界面」这种单一动作入手,先用 AppIntentControlConfiguration 做出最小可用版本,再判断是否需要 .promptsForUserConfiguration()
  • 做什么:用 WidgetRelevance 给 Widget 打上 1–2 个高质量相关性信号。

    • 为什么值得做:Smart Stack 决定了 Widget 能不能在合适时机出现在用户眼前,没有相关性信号等于没接入。
    • 怎么开始:从 RelevantContext.location.date(interval:kind:) 起步,结合应用核心场景写第一个 RelevanceEntriesProvider,避免一次性堆十几个模糊信号。
  • 做什么:把 Widget 改成可配置形态,让用户自己挑选展示的内容。

    • 为什么值得做:固定内容的 Widget 在 Smart Stack 里很容易被淘汰,可配置 Widget 让用户主动留下。
    • 怎么开始:把 recommendations() 返回空数组放在 watchOS 26 分支,旧系统继续返回预设,平滑过渡。
  • 做什么:用 Icon Composer 重新导出 watchOS 26 与 iOS 26 图标。

    • 为什么值得做:iPhone 转发到 Watch 的通知会显示 iOS 图标,没更新的图标会在新设计语言下显得突兀。
    • 怎么开始:参考 “Create icons with Icon Composer”,统一导出 iOS 与 watchOS 的图标,覆盖通知与表盘场景。

关联 Session

评论

GitHub Issues · utterances