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

What's new in watchOS 8

观看原视频

Highlight

watchOS 8 把 Always-On Display 从表盘扩展到第三方应用,配合 isLuminanceReduced 环境变量和 TimelineView,让手表应用在垂腕时既能保持可见,又能控制更新频率、保护隐私。

核心内容

你开发了一个 Apple Watch 应用。用户抬腕时,一切正常。但垂腕后,屏幕要么黑掉,要么显示一个模糊的界面——这是 watchOS 7 的行为。

watchOS 8 改变了这个局面。

从 watchOS 8 开始,第三方应用也能在 Always-On 状态下保持可见。Apple Watch Series 5 及后续机型支持这个功能。用户不用抬腕,扫一眼就能看到应用内容。

这带来两个直接问题:

第一,低亮度下怎么设计 UI?

第二,垂腕时怎么更新内容?

Apple 用一套 API 回答了这两个问题。

详细内容

isLuminanceReduced:感知 Always-On 状态

02:40

watchOS 8 引入了新的 SwiftUI 环境属性:

@Environment(\.isLuminanceReduced) var isLuminanceReduced

当手表进入 Always-On 状态,系统会自动降低屏幕亮度。isLuminanceReduced 变为 true,你的应用可以据此调整 UI。

Xcode Preview 里也能模拟这个状态:

ContentView().environment(\.isLuminanceReduced, true)

03:00

关键点:

  • @Environment 从系统环境中读取状态
  • isLuminanceReduced 在垂腕低亮度时为 true
  • Preview 和模拟器都支持模拟该状态,模拟器窗口有专门按钮触发 wrist-down 事件

Apple 在 session 里展示了三个真实应用的设计做法。

Fitbod 保持了界面结构的一致性,只把次要文字进一步压暗。

AnyList 移除了列表项的背景色,把”希腊酸奶口味”、“牛奶数量”这类次要信息变暗,让主标题更突出。

Pandora 把专辑封面去掉,改用暗色描边,底部控制栏也压暗,只保留歌曲名和艺人名清晰可见。

03:50

敏感信息也要处理。银行账户余额、个人健康数据,在垂腕时应该模糊或隐藏。SwiftUI 的 .redacted(reason:) 修饰符和 widget 共用同一套模型。

动画需要重置到第一帧或静止状态,不要停在中间。

TimelineView:控制垂腕时的更新节奏

06:59

有活跃会话的应用(比如 workout 或音频播放),垂腕时每秒最多更新一次 UI。没有活跃会话的应用,每分钟最多一次。

SwiftUI 的 TimelineView 专门处理这种定时刷新。它接收一个 schedule,按时间构造视图。

watchOS 8 内置了五种 schedule:

  • EveryMinute:每分钟更新,对齐系统时钟,在整分触发
  • Periodic:自定义间隔,比如每两分钟,不对齐系统时钟
  • Explicit:在指定时间点更新,适合精确计时场景
  • Custom:混合策略,比如倒计时前 59 分钟每分钟更新,最后 60 秒每秒更新
  • Animation:动画专用

07:18

一个典型的 TimelineView 用法:

TimelineView(.everyMinute) { context in
    Text(context.date, style: .time)
}

关键点:

  • TimelineView 的闭包接收一个 TimelineViewContext,包含当前日期
  • 非活跃会话下请求快于每分钟更新,系统会尝试但不保证
  • 默认两分钟后系统会切回表盘,但用户可以在设置里改,应用要做好长时间可见的准备

HealthKit 后台数据投递

08:58

watchOS 8 把 iOS 上已有的 HealthKit 后台投递带到了 Watch 应用。设置方式和 iOS 一样:

let query = HKObserverQuery(
    sampleType: heartRateType,
    predicate: nil
) { query, completionHandler, error in
    fetchLatestHeartRateData()
    completionHandler()
}

healthStore.execute(query)
healthStore.enableBackgroundDelivery(
    for: heartRateType,
    frequency: .immediate
) { success, error in
    // 启用后台投递
}

09:13

关键点:

  • HKObserverQuery 监听数据变化
  • enableBackgroundDelivery 开启后台唤醒
  • 普通应用每小时最多唤醒一次
  • 如果 complications 在活跃表盘上,每小时最多四次
  • 所有唤醒次数计入后台刷新预算,上限是每小时四次
  • 跌倒事件、低血氧、心率异常等关键数据类型会立即投递
  • 其他数据类型按小时或更长间隔投递

HealthKit 授权表单也更新了,会告知用户应用将在 Apple Watch 上更频繁地访问健康数据。

蓝牙设备后台连接

10:49

watchOS 4 开始支持蓝牙设备直连 Apple Watch。watchOS 8 的新能力是在后台刷新期间连接蓝牙设备。

这意味着 complications 可以持续从蓝牙配件获取数据。比如 Qardio 的医疗级 ECG、Sonra Watch 的足球运动员 GPS 追踪器。

后台刷新每小时最多提供四次连接机会,同样计入后台刷新预算。

Apple 给 WKRefreshBackgroundTask 加了 expiration handler:

func handle(_ backgroundTasks: Set<WKRefreshBackgroundTask>) {
    for task in backgroundTasks {
        task.expirationHandler = {
            // 时间快用完了,清理连接
        }
        // 连接蓝牙设备、获取数据
    }
}

12:35

关键点:

  • 蓝牙设备初始连接必须在应用前台完成,后台不能建立新连接
  • 连接建立后,后台刷新期间可以重连获取数据
  • 数据处理必须在短时间内完成
  • expirationHandler 让你能在时间耗尽前优雅收尾

基于地理位置的区域通知

13:15

watchOS 8 支持 UNLocationNotificationTrigger,让用户进入或离开指定区域时收到通知。

let center = CLLocationCoordinate2D(latitude: 37.7749, longitude: -122.4194)
let region = CLCircularRegion(
    center: center,
    radius: 200,
    identifier: "gym"
)
region.notifyOnEntry = true

let trigger = UNLocationNotificationTrigger(region: region, repeats: false)
let content = UNMutableNotificationContent()
content.title = "到达健身房"
content.body = "开始记录你的训练吧"

let request = UNNotificationRequest(
    identifier: "gym-entry",
    content: content,
    trigger: trigger
)
UNUserNotificationCenter.current().add(request)

13:40

关键点:

  • CLCircularRegion 定义圆形地理围栏
  • UNLocationNotificationTrigger 基于区域触发通知
  • 需要 “When in use” 位置权限
  • 用户先收到静态通知,点击后才显示完整动态内容,保护隐私
  • 区域半径建议几百米,只设置用户明确感兴趣的位置

Core Location 的 location button 也来到了 watchOS。用户点击按钮即授予一次性位置权限,不用每次都弹窗授权。

其他系统增强

15:18

watchOS 8 还有一些值得注意的改进:

  • 睡眠呼吸率:Apple Watch 可以在睡眠时测量呼吸率,应用可以通过 HealthKit 读取
  • AssistiveTouch:通过手势识别帮助上肢差异用户操作手表
  • 大号辅助文字:更大的无障碍文字尺寸
  • 大标题:滚动视图顶部支持 iOS 风格的大标题
  • 文本输入优化:记住用户每个应用的 Scribble / 听写偏好,支持快速切换
  • 搜索 APIsearchable 修饰符支持自定义搜索建议
  • 列表滑动操作:列表项支持自定义滑动操作(如收藏)
  • Button roles:区分按钮类型(如 destructive),支持控制 prominence 和额外触觉反馈
  • Canvas API:SwiftUI Canvas 来到 watchOS,支持 GPU 程序化绘制

核心启发

  1. 做一个垂腕可见的计时器应用。利用 TimelineView + EveryMinute schedule,让用户在做饭或健身时垂腕也能看到剩余时间。最后 60 秒切换到每秒更新。入口 API:TimelineView + Custom schedule。

  2. 做一个蓝牙血糖仪配套 complication。在后台刷新期间连接血糖仪,每小时更新一次表盘 complication。利用 expirationHandler 确保连接及时关闭。入口 API:CBCentralManager + WKRefreshBackgroundTask

  3. 做一个基于位置的健身提醒应用。用户到达健身房自动提醒开始记录训练,离开提醒保存数据。利用 UNLocationNotificationTrigger 设置 200 米半径的地理围栏。入口 API:CLCircularRegion + UNLocationNotificationTrigger

  4. 做一个睡眠呼吸监测 dashboard。利用 watchOS 8 新增的睡眠呼吸率数据,每天早上展示呼吸率变化趋势。结合 HealthKit 后台投递,无需用户手动刷新。入口 API:HKQuantityType.respiratoryRate)+ HKObserverQuery

  5. 做一个 Always-On 友好的音乐播放界面。垂腕时隐藏专辑封面和播放控制,只显示歌曲名和艺人名。利用 isLuminanceReduced 控制不同状态下的 UI 层级。入口 API:@Environment(\.isLuminanceReduced) + .redacted(reason:)

关联 Session

评论

GitHub Issues · utterances