WWDC Quick Look 💓 By SwiftGGTeam
Meet Watch Face Sharing

Meet Watch Face Sharing

观看原视频

Highlight

watchOS 7 和 iOS 14 引入 Watch Face Sharing,用户可以通过手表、iPhone、App 或网站分享配置好的 Apple Watch 表盘,接收者添加含第三方 Complication 的表盘时会被提示安装对应 App。

核心内容

Apple Watch App 的 Complication 很适合放在表盘上,但过去开发者很难把一个“已经配置好”的表盘直接交给用户。用户要自己打开 Watch App,找到合适的表盘,选择样式,再把某个 App 的 Complication 放到正确位置。这个路径太长,很多人不会走完。

watchOS 7 和 iOS 14 给出了一条更短的路径:表盘可以作为 .watchface 文件分享。用户可以从 Apple Watch 长按表盘后点分享,也可以在 iPhone 的 Watch App 里通过分享按钮发出。接收者看到预览后点一下,就会进入添加表盘的系统流程(00:12)。

这对开发者的意义更直接。你可以把自己的 Complication 放进一个预先设计好的表盘,再从 iOS App、watchOS App 或网站交给用户。如果表盘里包含你的 Complication,用户添加表盘时会被提示安装你的 App;如果 App 在对方地区不可用,那个 Complication 就不会出现在表盘上(01:00)。

Session 的 Coffee Tracker 示例把完整流程拆成四步:先在 Watch App 里做出包含 App Complication 的表盘;把 .watchface 文件和预览图放进 Xcode bundle;在 App 里做一个添加表盘的界面;最后处理旧款 Apple Watch 不支持某些新表盘的问题(03:51)。

详细内容

先确认用户有配对的 Apple Watch

06:49)示例 App 在 iPhone 端提供“添加表盘”入口。入口出现前,先用 WatchConnectivity 检测这台 iPhone 是否配对了 Apple Watch。

var isPaired: Bool {
    if (WCSession.isSupported()) {
        let session = WCSession.default
        session.delegate = self
        session.activate()
        return session.isPaired
    } else {
        return false
    }
}

关键点:

  • WCSession.isSupported() 先判断当前设备是否支持 WatchConnectivity。
  • WCSession.default 取得系统会话,后续用它读取配对状态。
  • session.delegate = selfsession.activate() 让会话进入可用状态。
  • session.isPaired 只回答一个问题:这台 iPhone 是否已经配对 Apple Watch。
  • 不支持 WatchConnectivity 时直接返回 false,界面就不展示添加表盘入口。

从 bundle 里的 .watchface 文件发起添加流程

08:47)真正添加表盘时,App 需要导入 ClockKit,找到 bundle 里的 .watchface 文件,然后调用 CLKWatchFaceLibrary().addWatchFace(at:completionHandler:)

private func addFaceWrapper(withName: String) {
    if let watchfaceURL = Bundle.main.url(forResource: withName, withExtension: "watchface") {
        CLKWatchFaceLibrary().addWatchFace(at: watchfaceURL, completionHandler: {
            (error: Error?) in
            if let nsError = error as NSError?, nsError.code == CLKWatchFaceLibrary.ErrorCode.faceNotAvailable.rawValue {
                print(nsError)
            }
            isLoading = false
        })
    }
}

关键点:

  • Bundle.main.url(forResource:withExtension:) 读取 App bundle 中已经打包好的 .watchface 文件。
  • CLKWatchFaceLibrary() 是 ClockKit 提供的入口,用来让系统接管添加表盘流程。
  • addWatchFace(at:completionHandler:) 接收本地文件 URL,随后把用户带到 Watch App 的确认界面。
  • completion handler 会返回错误。示例重点处理 faceNotAvailable,因为有些表盘不支持旧款 Apple Watch。
  • isLoading = false 对应界面上的活动指示器,添加流程结束后停止加载状态。

给旧设备准备 fallback face

10:33)Coffee Tracker 选择的 Modular Compact face 不兼容 Series 3。处理方式是在第一次添加失败且错误码为 faceNotAvailable 时,再尝试一个 Series 3 兼容的备用表盘。

private func addFaceWrapper(withName: String, fallbackName: String?) {
    if let watchfaceURL = Bundle.main.url(forResource: withName, withExtension: "watchface") {
        CLKWatchFaceLibrary().addWatchFace(at: watchfaceURL, completionHandler: {
            (error: Error?) in
            if let nsError = error as NSError?, nsError.code == CLKWatchFaceLibrary.ErrorCode.faceNotAvailable.rawValue {
                if let name = fallbackName {
                    // We failed, trying with fallbackName.
                    addFaceWrapper(withName: name, fallbackName: nil)
                }
            }
            isLoading = false
        })
    }
}

关键点:

  • fallbackName 是第二个 .watchface 文件名,示例里用 Modular face 作为 Series 3 兼容版本。
  • 只有 faceNotAvailable 触发 fallback,其他错误不会被误当成兼容性问题。
  • 递归调用时传入 fallbackName: nil,避免 fallback 继续失败后无限重试。
  • 两个表盘文件都需要提前放入 Xcode project,运行时才可能从 bundle 取到 URL。
  • 兼容性列表来自 Human Interface Guidelines,Session 建议开发者按表盘支持范围准备替代方案。

网站托管表盘文件

12:45)表盘也可以放在网站上。用户在 iOS Safari 下载表盘文件时,系统会提示把它添加到 Apple Watch。

这部分没有给出服务端代码,但 transcript 明确说到三个实现细节。第一,服务器最好用 session 展示的 watch face MIME type 提供文件,Safari 更容易识别。第二,网页上应该把表盘预览图放在官方 “Add Apple Watch Face” 按钮上方。第三,如果主表盘不兼容 Series 3,网页上应该同时提供备用表盘、对应预览图和按钮(12:5413:33)。

QR code 和 NFC tag 的作用也被限定在“承载一个网页链接”。Session 的说法是把托管 .watchface 文件的 Web link 放进去,让用户扫到链接后走 Safari 的添加流程(13:50)。

核心启发

  • 做一个 App 内推荐表盘入口:把最适合新用户的表盘打包进 bundle,在 iOS App 的设置页或关键功能页展示预览图。为什么值得做:用户添加表盘时就能看到你的 Complication。怎么开始:用 Watch App 生成 .watchface 文件和预览图,再用 CLKWatchFaceLibrary().addWatchFace 发起添加。

  • 为不同硬件准备两套表盘:给新款 Apple Watch 设计一个信息密度更高的 face,再给 Series 3 准备兼容版本。为什么值得做:用户不会因为 faceNotAvailable 卡在失败状态。怎么开始:按 Human Interface Guidelines 选择兼容表盘,并在 completion handler 中处理 fallback。

  • 把 Complication 的默认状态做成可分享配置:为天气、潮汐、健身或日程类 App 准备包含 sample entry 的表盘,让未安装 App 的用户也能看到合理预览。为什么值得做:transcript 提到 watch face 文件会包含 sample entry,预览不会空白。怎么开始:先完善 ClockKit Complication 的 sample data,再导出包含该 Complication 的表盘。

  • 为活动或内容页面托管表盘下载:在网站上的活动页、课程页或品牌专题页提供 .watchface 文件、预览图和官方按钮。为什么值得做:Session 明确支持网站托管,Safari 可以提示用户添加表盘。怎么开始:用正确 MIME type 提供文件,并为不兼容 Series 3 的表盘附带备用下载。

  • 把 Shortcuts 和表盘入口串起来:如果 App 已经有 watchOS Shortcuts,把常用操作放进 Complication,再通过共享表盘交给用户。为什么值得做:用户从表盘看到状态,也能快速进入动作。怎么开始:先完成 App intents 和 Apple Watch Complication,再用本 session 的表盘分享流程分发。

关联 Session

评论

GitHub Issues · utterances