初识 Apple Watch App

2015 年 4 月 24 日,Apple 发布了第一代 Apple Watch。 无论咱们对 Apple Watch 看法怎么,watchOS 肯定是咱们要支撑的 Apple 生态体系的一部分,保证咱们的运用获得更大的曝光率。

在本章中,咱们将创立一个 watchOS 运用程序,并将咱们现有的 iOS 开发知识直接转移到 watchOS 上来。

Swift & SwiftUI

新项目

翻开 Xcode 经过挑选 File ▸ New ▸ Project 或运用快捷键 Shift-Command-N 创立一个新项目。 在咱们挑选项目类型的对话框窗口中,挑选 watchOS 选项卡,然后挑选 iOS App with Watch App 模板:

「Apple Watch 应用开发系列」初识 Apple Watch App

在开发支撑 Apple Watch 的项目时,咱们可以挑选是否提供配套的 iOS 运用。 需求配套 iOS 运用会包含 iOS 项目。

接下来,咱们输入 Product Name,例如 watchOS&SwiftUI,可以选中底部标题为 Include Notification Scene 的勾选框。在后面的章节中,咱们将探索怎么向 Apple Watch 发送推送通知。

「Apple Watch 应用开发系列」初识 Apple Watch App

Hello, World!

挑选 Product ▸ Run 或运用 Command-R 来构建和运转运用程序,模拟器加载 watchOS 运用程序一般需求一些时间,所以假如运用程序没有立即发动。 稍等片刻,Apple Watch 模拟器将呈现,咱们会看到“Hello, World!” :

「Apple Watch 应用开发系列」初识 Apple Watch App

翻开项目的 ContentView.swift。假如你从前触摸过 SwiftUI 项目,那么你现在或许会十分兴奋。 咱们会看十分了解的 SwiftUI 代码!咱们只需编写 SwiftUI 代码,就像编写 iOS 项目相同。

相对传统的 WatchKit 特定类仍然是支撑的,但和 SwiftUI 相比,假如咱们只需求针对 watchOS 6.0 及更高版本的设备,那么没有理由在新运用程序上运用传统的方案。

项目结构

Target

「Apple Watch 应用开发系列」初识 Apple Watch App

咱们来看一下项目的 TARGETS,现在咱们有三个 template:

  1. watchOS&SwiftUI 是咱们项目的 Target。它充任项目的包装器,以便咱们可以将 App 提交到 App Store。

  2. watchOS&SwiftUI WatchKit App 是构建 watchOS App 的 Target。 包含咱们的 watchOS App 的 storyboard 和 storyboard 运用的 assets。

  3. watchOS&SwiftUI WatchKit Extension 是构建 watchOS extension 的 Target。 包含咱们的 watchOS App 的代码。

咱们很少与前两个 Target 互动。 当咱们想到 Apple Watch App 开发时,一般指的是 WatchKit Extension。

Scheme

「Apple Watch 应用开发系列」初识 Apple Watch App

翻开 scheme 挑选器,除去 iOS App 以外,咱们会看到三个默许 scheme,这些 scheme 不直接映射到三个 Target,它们操控咱们在模拟器或物理设备上运转时希望履行的履行类型:

  1. watchOS&SwiftUI WatchKit App 是咱们最常运用的方案。咱们可以将此方案视为“运转我的运用程序”。当咱们运用该方案构建和运转时,模拟器或物理设备将履行最终用户在发动咱们的运用程序时看到的内容。

  2. watchOS&SwiftUI WatchKit App (Notification) 当咱们在创立项目时选中包Include Notification Scene时,项目即创立该 scheme。可让咱们直接向设备发送通知。假如咱们挑选该 scheme 并构建运转 App,将直接跳转到咱们定义的 notification view。只有在测试本地或长途推送通知时咱们才会运用此 scheme。

「Apple Watch 应用开发系列」初识 Apple Watch App

  1. watchOS&SwiftUI WatchKit App (Complication) 杂乱功用是咱们在手表外表看到的信息。例如计时器、仪表和活动环等。在调试手表运用程序的杂乱功用时,咱们将运用该 scheme。

增加 iOS App

假如咱们需求一起开发 iOS App 和 watchOS App,请在创立项目时挑选 iOS App with Watch App 模板。 尽管许多 watchOS App 需求一个配套的 iOS 项目,但 watchOS App 也可以在没有配套的 iOS App 的情况下运转。 默许情况下,Xcode 假定咱们的 watchOS App 可以在没有装置配套 iOS App 的情况下运转。

假如咱们的手表运用在没有相应 iOS 运用的情况下无法运转,咱们需求进行一些装备更改:

「Apple Watch 应用开发系列」初识 Apple Watch App

  1. 挑选项目导航中的项目;

  2. 挑选 Extension target;

  3. 挑选 General tab;

  4. 在 Deployment Info 部分,选中 Supports Running without iOS App Installation

假如咱们忘记包含对 watchOS App 的支撑,只需经过 File ▸ New ▸ Target 挑选 Watch App 模板增加一个新 target。

咱们无法将 watchOS 目标命名为与 iOS 目标相同。

运用命名

运转咱们的 watchOS App 后,翻开设置,挑选 App View 并更改为 List View。然后回来主屏幕并向下滚动到 App 列表的底部,咱们会看到 App 显现了它的名字:

「Apple Watch 应用开发系列」初识 Apple Watch App

「Apple Watch 应用开发系列」初识 Apple Watch App

「Apple Watch 应用开发系列」初识 Apple Watch App

默许情况下,Xcode 会将 WatchKit App 附加到咱们 App 的称号中。

假如需求进行更改,挑选 watchOS&SwiftUI WatchKit App Target,然后切换到 General Tab,只需经过修改“Display Name”来输入要显现的名字即可。

「Apple Watch 应用开发系列」初识 Apple Watch App

构建并从头运转运用程序。 咱们讲看到咱们为 watchOS App 设置的新称号:

「Apple Watch 应用开发系列」初识 Apple Watch App

App 与 Extension

咱们为 App 分配图标时,需求在以 App 结束的目录中操作,例如 watchOS&SwiftUI WatchKit App/Assets.xcassets。但不要在该文件夹结构内履行任何其他操作。关于一切其他 asset 以及咱们将履行的一切代码,咱们将防治在 Extensions 目录中。

这是由于以前版本的 watchOS 工作方法不同。 此外,WWDC 22 在此处页做了更新。

欢迎参阅:

  • xiaozhuanlan.com/topic/24876…

  • developer.apple.com/videos/play…

走运表情

咱们将完成一个简略的 Watch App Demo “走运表情”。

增加图标与图画

首要,将 AppIcon.appiconset 增加到 watchOS&SwiftUI WatchKit App 的 Assets 中。运转项目并切换到主屏幕检查 App,图标现已进行了替换:

「Apple Watch 应用开发系列」初识 Apple Watch App

「Apple Watch 应用开发系列」初识 Apple Watch App

接着,咱们将 luck_icon.png 增加到 watchOS&SwiftUI WatchKit Extension 的 Assets 中。现在咱们的运用程序可以运用该图画。

「Apple Watch 应用开发系列」初识 Apple Watch App

翻开 watchOS&SwiftUI WatchKit ExtensionContentView.swift,将 body 的内容替换为以下代码,并更新预览,四叶草将展示。

Image("luck_icon")
    .resizable()
    .scaledToFit()

「Apple Watch 应用开发系列」初识 Apple Watch App

增加走运表情

咱们在 watchOS&SwiftUI WatchKit Extension 中,新建一个 SwiftUI 文件并命名为 EmojiModel.swift,将内容进行替换:

import SwiftUI
@MainActor
class EmojiModel: ObservableObject {
    @Published var text = ""
    @Published var emoji = ""
    private let sentences = [
        (text: "Lucky animal", emoji: ""),
        (text: "Lucky drink", emoji: "☕️"),
        (text: "Lucky sport", emoji: "♀️"),
    ]
    private var index = 0
    init() {
        update()
    }
    private func update() {
        text = sentences[index].text
        emoji = sentences[index].emoji
    }
    func next() {
        index += 1
        if index == sentences.count {
            index = 0
        }
        update()
    }
}

简略检查代码,符合 ObservableObject 协议的 EmojiModelMainActor 提供了一些 Published 包装的 textemoji,属性在发生改动时会通知自身的订阅者。

回到 ContentView.swift,在 ContentView 中增加一个新属性,ContentView 实例将持有一个 StateObject 包装的 model,使后续增加的控件可作为 model 的订阅者:

@StateObject private var model: EmojiModel = EmojiModel()

.scaledToFit() 后增加代码:

.overlay {
    Text(model.emoji)
        .font(.title)
        .padding()
        .buttonStyle(.automatic)
}

咱们运用 .overlay 将一个视图叠加到另一个视图之上。这里将表情符号作为文本增加到四叶草之上。然后咱们运用一些修饰符来更改字体大小和方位。更新 Canvas,咱们会看到走运表情:

「Apple Watch 应用开发系列」初识 Apple Watch App

咱们运用 Command + TextText 放入 Vstack 中,并调整代码:

「Apple Watch 应用开发系列」初识 Apple Watch App

更新 Canvas 检查最新样式。

「Apple Watch 应用开发系列」初识 Apple Watch App

最终在 VStack 后增加以下代码来增加点击手势,并运转项目。

.onTapGesture {
    model.next()
 }

「Apple Watch 应用开发系列」初识 Apple Watch App

「Apple Watch 应用开发系列」初识 Apple Watch App

「Apple Watch 应用开发系列」初识 Apple Watch App

现在,我嘛点击走运表情和描绘,将进行替换。

Swift & Storyboard

咱们来了解下怎么运用 WatchKit 开发 watchOS App。

WatchKit 结构包含用于操控咱们在 Storyboard 中布局的用户界面元素。根据 Storyboard 的布局一般需求每个 scene 的 controller。每个 controller 可以办理一个或多个控件和子视图,例如表格、按钮、滑块和其他视觉元素。

由于运用 SwiftUI 构建的运用程序比在故事板中规划的运用程序具有更多的自由、强大和对用户界面的操控,所以在创立 watchOS 运用程序时激烈考虑运用 SwiftUI。相关详细信息请参阅:

  • Building a watchOS App developer.apple.com/documentati…

相关布景

前期,在 WatchOS 时,担任逻辑部分的 WatchKit Extension 将随 iOS app 的主 target 被一同装置到 iPhone 中,而担任界面部分的 WatchKit App 将会在主程序装置后,由 iPhone 检测有没有配对的 Apple Watch,并提示装置到 Apple Watch 中。所以在实践运用时,一切的运算、逻辑以及操控实践上都是在 iPhone 中完成的。在需求界面改写时,由 iPhone 向 Watch 发送指令进行描画并在手表盘面上显现。反过来,用户触摸手表交互时的信息也由手表传回给 iPhone 并进行处理。这个过程 WatchKit 会在幕后为咱们完成,并不需求开发者操心。咱们需求知道的就是,原则上来说,咱们应该将界面相关的内容放在 Watch App 的 target 中,而将一切代码逻辑等放到 Extension 里。

以上在 WWDC19 时迎来了改动。watchOS 6 允许彻底独立的运用程序和专为 Apple Watch 构建的运用程序,并将 App Store 引入 Apple Watch,从而完成全新等级的 watchOS 体验。所以现在 App Store 服务器将在 Apple Watch 上装置它需求装置的一切东西。这意味着 iOS 运用程序不再包含 watchOS App,watchOS App 不再计入咱们的 iOS App 的蜂窝下载约束。

  • 前期 watchOS 的架构的更多信息,可以参阅 onevcat.com/2014/11/wat…

  • 关于 WWDC19 的改动的更多信息,可以参阅developer.apple.com/videos/play…

新项目

挑选 iOS App with Watch App 模板后,咱们输入 Product Name,例如 watchOS&Storyboard。这里,咱们将 Interface 挑选为 Storyboard

「Apple Watch 应用开发系列」初识 Apple Watch App

首要类

WKInterfaceController

WKInterfaceController 像是 WatchKit 中的 UIViewController。每个 WKInterfaceController 或许其子类对应手表上的一个整屏内容。但需求记住整个 WatchKit 是独立于 UIKit,WKInterfaceController 是一个直接继承自 NSObject 的类,没有像 UIKit 中 UIResponser 那样齐备的功用。

「Apple Watch 应用开发系列」初识 Apple Watch App

在生命周期上 UIViewController 也简略许多。每个 WKInterfaceController 目标重要的生命周期办法有五个:

  1. 目标被初始化时的 awake(withContext:) 运用此办法完成界面的初始化。super 办法的完成什么都不做。

developer.apple.com/documentati…

在 iOS 8.2 之前,该 Api 为 init(withContext:) ,现已抛弃。

stackoverflow.com/questions/2…

  1. 内容将于活动状况 willActivate()。该办法让咱们知道界面将变为活动状况。运用该办法履行任何“最终一分钟”的使命,例如检查内容的更新。体系或许会提前调用此办法,以便咱们有时间更新咱们的内容。体系在 WatchKit Extension 的主线程上调用此办法。super 办法的完成什么都不做。

developer.apple.com/documentati…

  1. 内容现在在屏幕上 didAppear()。运用此办法装备动画或其他与界面相关的使命。体系在 WatchKit Extension 的主线程上调用此办法。super 办法的完成什么都不做。

developer.apple.com/documentati…

  1. 内容不再处于活动状况 didDeactivate()。运用此办法使计时器无效或保存任何尚未保存的与运用程序相关的状况信息。咱们运用此办法履行的任何使命都应该很快完成。不活动的内容或许会在今后从头激活,也或许会被 deinit 分配。

在 didDeactivate() 中对视图属性进行设置是无效的,由于当时的 WKInterfaceController 现已非活跃

developer.apple.com/documentati…

  1. 内容现在不在屏幕上 willDisappear()。运用此办法可在停用之前中止动画或履行其他与界面相关的使命。体系在 WatchKit Extension 的主线程上调用此办法。super 办法的完成什么都不做。

developer.apple.com/documentati…

WKInterfaceObject 及其子类

WKInterfaceObject 提供 watchOSApp 中一切界面目标共有的信息的目标,即担任详细的界面目标的设置。包含 WKInterfaceLabelWKInterfaceDateWKInterfaceTimer 等。

developer.apple.com/documentati…

咱们或许一开始会发生幻觉,以为 WKInterfaceObject 应该对应 UIView,但实践上并非如此。

WKInterfaceObject 只是 WatchKit 的实践的 View 的一个在 Watch Extension 的署理,而非 View 本身。Watch App 中实践展示和渲染在屏幕上的 View 关于代码来说是非直接可见的,咱们只能在 Extension target 中经过对应的署理目标对属性进行设置,然后在每个 run loop 改写 UI 时由 WatchKit 进行界面改写。反过来,手表中的实践的 view 想要将用户交互事情传递给 iPhone 也需求经过 WKInterfaceObject 署理进行。

watchOS App 采纳的布局方法和 iOS App 彻底不同。咱们无法自由指定某个视图的详细坐标,也不能运用像 AutoLayout 这样的灵敏的界面布局方案。咱们只能在以“行”为基本单位的一起经过 group 来在行内进行“列”布局。

一切的 WKInterfaceObject 目标都必须由 Storyboard 进行增加,运转时咱们无法再向界面上增加或许移除元素,咱们只能经过设置 setHidden(_:) 来进行界面目标躲藏;此外,WKInterfaceObject 与布局相关的某些属性,比如行高行数等,不可以在运转时进行变更和设定。基本来说在运转时咱们只可以改动视图的内容,以及经过躲藏某些视图元素来到达有限地改动布局。

走运表情

咱们将运用 Storyboard 完成一个简略的 Watch App Demo “走运表情”。

增加图画

咱们将 luck_icon.png 增加到 watchOS&Storyboard WatchKit App 的 Assets 中。

「Apple Watch 应用开发系列」初识 Apple Watch App

翻开 watchOS&Storyboard WatchKit AppInterface.storyboard,点击右上角的“➕”,并将 Image 拖拽到 Interface Controller 上。

「Apple Watch 应用开发系列」初识 Apple Watch App

调整点击右侧“Show the Attributes inspector,并进行如下图所示调整。

「Apple Watch 应用开发系列」初识 Apple Watch App

运转程序,咱们会看到咱们的布景现已增加。

「Apple Watch 应用开发系列」初识 Apple Watch App

增加走运表情

回到 Interface.storyboard,增加一个 Label、一个 Button,并进行相应调整。

「Apple Watch 应用开发系列」初识 Apple Watch App

「Apple Watch 应用开发系列」初识 Apple Watch App

「Apple Watch 应用开发系列」初识 Apple Watch App

将咱们增加控件目标链接到 InterfaceController.swift 上:

「Apple Watch 应用开发系列」初识 Apple Watch App

「Apple Watch 应用开发系列」初识 Apple Watch App

「Apple Watch 应用开发系列」初识 Apple Watch App

「Apple Watch 应用开发系列」初识 Apple Watch App

接着,咱们在 watchOS&Storyboard WatchKit Extension 中,新建一个 Swift 文件并命名为 EmojiModel.swift,将内容进行替换:

import Foundation
class EmojiModel {
    var text = ""
    var emoji = ""
    private let sentences = [
        (text: "Lucky animal", emoji: ""),
        (text: "Lucky drink", emoji: "☕️"),
        (text: "Lucky sport", emoji: ""),
    ]
    private var index = 0
    init() {
        update()
    }
    private func update() {
        text = sentences[index].text
        emoji = sentences[index].emoji
    }
    func next() {
        index += 1
        if index == sentences.count {
            index = 0
        }
        update()
    }
}

并在 InterfaceController.swift 内增加代码:

private let emojiModel = EmojiModel()
override func awake(withContext context: Any?) {
    // Configure interface objects here.
    emoji.setText(emojiModel.emoji)
    text.setTitle(emojiModel.text)
}

运转程序,咱们会看到咱们的 watchOS 现已有了数据。

「Apple Watch 应用开发系列」初识 Apple Watch App

接着,咱们为 Button 增加 Action:

「Apple Watch 应用开发系列」初识 Apple Watch App

「Apple Watch 应用开发系列」初识 Apple Watch App

接着,咱们调整 textAction() 的代码:

@IBAction func textAction() {
    emojiModel.next()
    emoji.setText(emojiModel.emoji)
    text.setTitle(emojiModel.text)
}

运转咱们的 watchOS App。现在,它与咱们之前经过 SwiftUI 开发的项目基本一致:

「Apple Watch 应用开发系列」初识 Apple Watch App

「Apple Watch 应用开发系列」初识 Apple Watch App

「Apple Watch 应用开发系列」初识 Apple Watch App

参阅

  • watchOS With SwiftUI by Tutorials(www.raywenderlich.com/home)

  • onevcat.com/2014/11/wat…