WatchConnectivity 是 Apple 提供的一个框架,允许 iOS 设备与 Apple Watch 之间进行通信和数据交换。它的主要作用是使得 iOS 应用和 WatchOS 扩展能够互相传递数据和消息。这对于实现 iPhone 和 Apple Watch 之间的同步和交互非常重要,尤其是对于需要双向通信的应用,如健康监测、通知、实时数据等。
首次出现在 iOS 8 和 WatchOS 2 中。它允许 iOS 应用与 WatchOS 应用之间交换数据和消息,例如传输文件、同步数据、发送实时消息等。通过 WatchConnectivity,让两者在设备之间保持通信和同步。
WatchConnectivity 的核心功能
1、即时消息传递:
可以从 iPhone 发送即时消息到 Apple Watch,或反之。适用于实时数据更新或交互。例如,更新界面、发送通知等。
if WCSession.default.isReachable {
WCSession.default.sendMessage(["key": "value"], replyHandler: { response in
// 处理响应
}, errorHandler: { error in
// 处理错误
})
}
2、数据传输:
可以在两个设备之间传输文件或应用数据。比如,将用户数据从 iPhone 同步到 Apple Watch,或将日志、图片等文件传输到另一个设备。
3、应用状态同步:
允许设备间同步应用状态,例如将 iOS 设备上的某个数据同步到 Apple Watch 或将 Watch 上的健康数据、提醒等同步到 iPhone。
4、背景数据传输:
即使应用处于后台,WatchConnectivity 也能传输数据。系统会在后台处理消息和数据同步,前提是设备仍然保持连接。
5、Live Activity 支持:
支持通过 Live Activity 更新实时信息。比如,可以从 iOS 向 Apple Watch 发送实时活动信息,例如计时器、位置等动态数据。
如何使用 WatchConnectivity
使用 WatchConnectivity 进行通信时,主要通过 WCSession 类来管理会话。需要在 iOS 应用 和 WatchOS 扩展中分别实现。
1、初始化 WCSession
在 iOS 和 WatchOS 应用中都需要初始化并激活 WCSession,才能开始通信。
if WCSession.isSupported() {
WCSession.default.delegate = self
WCSession.default.activate()
}
这段初始化代码通常在AppDelegate或App的入口处使用。
如果设备(如 iPhone)支持与 Apple Watch 之间进行数据通信(通过 WatchConnectivity),则返回 true,否则返回 false。
因为并非所有设备都支持 WatchConnectivity,比如没有配对 Apple Watch 的 iPhone,或者某些旧设备。通过检查 isSupported() 可以避免在不支持的设备上尝试建立连接,避免错误。
1)设置 WCSession 的代理
WCSession.default.delegate = self
delegate 是 Swift 中的一种代理模式,代表“让某个对象来负责响应事件”。
iPhone和Apple Watch是两个独立的进程,它们在初始化WCSession的过程中,必须设置delegate,否则这一端就无法接受消息、发送数据和响应连接状态变化。
如果是在某个类内部(如 SomeManager、AppDelegate、或 SomeViewModel)调用它,self 就是那个类的实例。
如果是在入口文件,就需要显式传入一个可以实现WCSessionDelegate的对象:
@main
struct pigletApp: App {
@State private var wcSessionDelegateImpl = WCSessionDelegateImpl()
init() {
if appStorage.isModelConfigManager {
// isModelConfigManager为 true 时,设置为私有iCloud
modelConfigManager.cloudKitMode = .privateDatabase
} else {
// isModelConfigManager为 false 时,设置为空
modelConfigManager.cloudKitMode = .none
}
}
}
或者,在WCSessionDelegate对象内部配置代理模式:
class WCSessionDelegateImpl: NSObject, WCSessionDelegate {
override init() {
super.init()
if WCSession.isSupported() {
print("当前设备支持 WCSession 。")
WCSession.default.delegate = self // 设置 WCSessionDelegate
WCSession.default.activate()
} else {
print("当前设备不支持 WCSession.")
}
}
}
这两种配置方式是一样的,既可以在入口文件中配置代理模式为WCSessionDelegate对象,也可以在WCSessionDelegate对象内部配置代理模式为self。
前提是这个类必须遵循NSObject和WCSessionDelegate 协议。
WCSessionDelegate对象
在iOS和Watch两端都需要配置各自的WCSessionDelegate,因为WCSession是点对点通信桥梁,每端都需要代理来处理会话事件。
iOS端代码示例:
class wcSessionDelegateImpl: NSObject, WCSessionDelegate {
func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: (any Error)?) {
// 会话激活完成
}
func sessionDidBecomeInactive(_ session: WCSession) {
// 收到即时消息
}
func sessionDidDeactivate(_ session: WCSession) {
// 收到异步数据
}
}
在iOS端配置的目的为接收watchOS发送的消息、监听WCSession激活、失活等状态,接收文件、用户信息等等。
在配置WCSessionDelegate时,需要注意上述三个方法是必须实现的,如果不实现则会报错。但在Watch端只有session方法是必须实现的。
Watch端代码示例:
class WCSessionDelegateImpl: NSObject, WCSessionDelegate {
func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: (any Error)?) {
<#code#>
}
}
除了iOS端和Watch端必须实现的方法外,还可以选择性添加didReceiveMessage、didReceiveUserInfo等方法处理消息,在后面的“代理方法”中会提及。
通过设置代理,可以实现一些回调方法,处理 WatchConnectivity 会话的状态变化或接收到的数据。
2)激活 WCSession
WCSession.default.activate()
通过调用 activate() 方法,告诉系统准备好进行 WatchConnectivity 的通信。这是建立连接的关键步骤。
在激活之后,设备可以开始与配对的 Apple Watch 进行数据交换。
2、代理方法
通过代理方法,可以监听连接状态的变化,处理收到的消息,或处理发生的错误。
常见代理方法:
1、会话生命周期相关(必须实现)
func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?)
iOS和watchOS必须实现该代理方法,表示 WatchConnectivity 会话是否激活成功,应该在 App 启动时设置 delegate 并调用 activate() 后等待这个回调。
2、iOS 专有:会话状态管理(仅 iOS 要实现)
func sessionDidBecomeInactive(_ session: WCSession)
当前的会话连接变为非活跃状态(例如用户切换手表)时被调用。
func sessionDidDeactivate(_ session: WCSession)
当旧会话完全被系统停用时调用。通常此时应该再次 activate()。
3、实时通信相关(即时消息)
func session(_ session: WCSession, didReceiveMessage message: [String : Any])
iOS/Watch 双端都可用,用于接收对方通过 sendMessage(…) 发来的数据。实时、立即响应,适合用于用户主动触发的请求,比如同步金额、拉数据等。
可选:带回复的消息
func session(_ session: WCSession, didReceiveMessage message: [String : Any], replyHandler: @escaping ([String : Any]) -> Void)
可以收到一条消息并立即回复(需要 replyHandler),常用于点对点请求/响应通信。
4、异步数据通信(后台同步)
func session(_ session: WCSession, didReceiveUserInfo userInfo: [String : Any])
用于接收对方通过 transferUserInfo(…) 发送的数据,适合延迟/后台传输。不保证立刻收到,但系统会在后台尽量完成传输。
5、文件传输(较少用)
func session(_ session: WCSession, didReceive file: WCSessionFile)
用于接收通过 transferFile(…) 发送的大文件或音频等资源。
代理可以处理来自 Apple Watch 或 iPhone 的信息和事件。通过实现代理方法,可以在设备连接、断开或收到消息时作出响应。
3、发送消息
在应用之间发送消息时,可以使用 sendMessage 或 sendMessageData 方法。这是 WatchConnectivity 发送即时消息的核心功能。
if WCSession.default.isReachable {
WCSession.default.sendMessage(["key": "value"], replyHandler: { response in
// 处理响应
}, errorHandler: { error in
// 处理错误
})
}
WCSession.default.isReachable属性用于检查 iPhone 和 Apple Watch 之间是否有有效的连接,并且 Apple Watch 是否处于可以接收消息的状态。
特点:
1、只在 Watch App 和 iOS App 同时处于前台时才为 true。
2、适用于 sendMessage(…) 和 sendMessageData(…) 这类即时消息发送。
3、如果对方 App 不在前台或没运行,isReachable 会是 false。
WCSession.default.sendMessage是 WatchConnectivity 的核心即时通信方法,用来向 Apple Watch 发送消息。消息内容是一个字典,可以在字典中放入任何需要发送的数据。
replyHandler 在 Apple Watch 成功接收到消息并作出响应时被调用。
errorHandler 用来捕获并处理发送过程中出现的任何错误,比如连接断开等问题。
常用的即时通信方法
1、sendMessageData
sendMessageData(_ data: Data, replyHandler: ((Data) -> Void)?, errorHandler: ((Error) -> Void)?)
与 sendMessage 类似,只是发送的是 Data 类型(如 JSON 编码的结构体)。
2、updateApplicationContext
try updateApplicationContext([String: Any])
发送当前 app 状态数据,只能保存一份,会被后发送的数据覆盖。适合同步当前 UI 状态、设置项等。
特点:
1)没有回调,不保证立即传输。
2)双端可用。
3)非即时,但适合状态同步。
3、transferUserInfo
transferUserInfo([String: Any]) -> WCSessionUserInfoTransfer
异步传输,系统后台保证尽量送达(即使对方没打开 App)。
适合需要后台同步、但不要求实时的情况(如存钱记录、步数同步等)。
多次调用会排队,系统处理完后调用 didReceiveUserInfo。
4、transferFile
transferFile(URL, metadata: [String: Any]?)
用于传输文件,适合较大体积的内容,如图片、音频等。
常见的 WCSession 状态
isReachable:表示设备是否可达。如果 iPhone 和 Apple Watch 之间的连接正常,isReachable 将为 true。如果设备没有连接,或者 WatchOS 不可用,则为 false。
isPaired:表示设备是否已经配对。即 iPhone 是否和 Apple Watch 配对并连接。
isCompanionAppInstalled:表示 iPhone 上的应用是否已安装并可用。
WatchConnectivity 的限制
1、需要设备间连接:iPhone 和 Apple Watch 必须通过蓝牙或 Wi-Fi 连接,才能实现 WatchConnectivity 的功能。如果设备不在同一范围或没有有效连接,则无法进行数据传输。
2、限制于同一 Apple ID:确保两个设备属于同一Apple ID 下,否则无法进行通信。
3、后台限制:即使 WatchConnectivity 支持后台数据传输,但还是会有一些限制。例如,后台传输时,传输的内容可能会被延迟,或者有时需要前台应用的交互才能触发某些操作。
WatchConnectivity 触发的场景
1、应用启动时:当 iOS 或 WatchOS 应用启动时,WCSession 会尝试建立连接并进行初始化。
2、应用之间的数据交换:当用户在 iPhone 或 WatchOS 应用中发起数据交换时(例如发送消息或同步数据)。
3、设备连接或断开时:当 iPhone 与 Apple Watch 之间的连接状态发生变化时,WatchConnectivity 会触发相关代理方法,进行处理。
实际应用
在《存钱猪猪》应用中,需要将存钱罐的数据从iOS传递给WatchOS。具体来说,在iOS主应用中获取存钱罐的数据(存钱罐名称、当前金额等字段),使用WCSession将这些数据发送到Apple Watch。
1、iOS和Watch端配置WatchConnectivity 框架

在Xcode中分别找到iOS应用和Watch应用,在General中找到“Frameworks, Libraries, and Embedded Content”,点击添加按钮。
找到“WatchConnectivity.framework”框架,点击“Add”按钮进行添加。

注意:iOS端和Watch端都需要添加这一框架,Watch端还有一个WatchKit.framework,可能也需要配置上。

2、在iOS中初始化WCSession
首先,在 iOS 主应用中,需要确保 WCSession 已经被初始化并激活。
import WatchConnectivity
@main
struct pigletApp: App {
@State private var wcSessionDelegateImpl = WCSessionDelegateImpl()
init() {
if WCSession.isSupported() {
print("当前设备支持 WCSession 。")
WCSession.default.delegate = wcSessionDelegateImpl // 设置 WCSessionDelegate
WCSession.default.activate()
} else {
print("当前设备不支持 WCSession.")
}
}
var body: some Scene {
WindowGroup {
ContentView()
}
.environment(wcSessionDelegateImpl)
}
}
// 定义 WCSessionDelegateImpl 来处理 WatchConnectivity 的代理方法
@Observable
class WCSessionDelegateImpl: NSObject, WCSessionDelegate {
func session(_ session: WCSession, didReceiveMessage message: [String : Any]) {
print("进入 WCSessionDelegateImpl 的 session 方法")
// 处理从 WatchOS 接收到的消息
if let piggyBanks = message["piggyBanks"] as? [[String: Any]] {
print("接收到 \(piggyBanks.count) 个存钱罐数据")
for bank in piggyBanks {
if let name = bank["name"] as? String {
print("Received piggy bank: \(name)")
}
}
}
}
// 激活完成后的处理
func session(_ session: WCSession, activationDidCompleteWith state: WCSessionActivationState, error: Error?) {
if state == .activated {
print("Watch端 WCSession 激活成功")
} else {
print("Watch端 WCSession 激活失败: \(String(describing: error))")
}
}
func sessionDidBecomeInactive(_ session: WCSession) {
// 会话变为非活跃时的处理
print("WCSession 会话变为非活跃.")
}
func sessionDidDeactivate(_ session: WCSession) {
// 会话被停用时的处理
print("WCSession 会话被停用.")
}
}
WCSessionDelegateImpl 类:
这个类是 WCSessionDelegate 协议的实现,用来处理与 WatchOS 的通信。
3、获取数据并发送到 WatchOS
在主视图中,获取存钱罐数据并将其发送到 WatchOS。可以在视图加载时或者通过某个操作(如按钮点击)来触发数据发送。
import SwiftUI
import WatchConnectivity
struct Home: View {
@Query var allPiggyBank: [PiggyBank]
var body: some View {
VStack {
// 主视图内容,显示存钱罐列表等
Button("Send Data to Watch") {
sendPiggyBankDataToWatch()
}
}
}
// 将 PiggyBank 数据发送到 WatchOS
func sendPiggyBankDataToWatch() {
print("进入:sendPiggyBankDataToWatch")
// 确保 WCSession 激活
// 创建存钱罐数据字典
let piggyBankData: [[String: Any]] = allPiggyBank.map { bank in
return [
"name": bank.name,
"icon": bank.icon,
"amount": bank.amount,
"targetAmount": bank.targetAmount,
"isPrimary": bank.isPrimary
]
}
print("piggyBankData:\(piggyBankData)")
print("发送数据到 WatchOS")
// 将数组包装在字典中
let wcSessionPiggyBanks: [String: Any] = ["piggyBanks": piggyBankData]
WCSession.default.transferUserInfo(wcSessionPiggyBanks)
print("Data sent: \(wcSessionPiggyBanks)")
}
}
在主视图中点击Button后,会将SwiftData中allPiggyBank数组(即所有存钱罐的数据)映射成多个字典,每个字典代表一个存钱罐的数据。
返回的结果:
原始数组 piggyBank 是 [PiggyBank] 类型,即多个 PiggyBank 对象的数组。
每个 PiggyBank 对象会被转换成字典 [String: Any] 类型。
最终 piggyBankData 的类型是 [[String: Any]],即包含多个字典的数组。
transferUserInfo方法用于传输较小的键值对数据(通常是字典格式)。它将包含存钱罐数据的字典发送到 WatchOS。
需要注意的是,transferUserInfo期望传入的是一个字典类型 ( [ String: Any ] ),因此需要将piggyBankData 从数组转换为字典。
let wcSessionPiggyBanks: [String: Any] = ["piggyBanks": piggyBankData]
WCSession.default.transferUserInfo(wcSessionPiggyBanks)
4、在 WatchOS 中接收数据
在 WatchOS 中,确保在 Watch 应用中实现 WCSessionDelegate,并接收来自 iOS 主应用的数据。
import WatchConnectivity
@main
struct BankletWatch_Watch_AppApp: App {
@State private var wcSessionDelegateImpl = WatchSessionDelegate()
init() {
// 激活 WCSession
if WCSession.isSupported() {
print("激活 WCSession")
WCSession.default.delegate = wcSessionDelegateImpl // 设置 WCSession 的代理
WCSession.default.activate() // 激活 WCSession
}
}
var body: some Scene {
WindowGroup {
ContentView()
}
.environment(wcSessionDelegateImpl)
}
}
// 定义 WatchSessionDelegate 来接收 iOS主应用传递的数据
@Observable
class WatchSessionDelegate: NSObject, WCSessionDelegate {
// 存储接收到的数据
var piggyBanks: [PiggyBank] = []
// 处理从 iOS 应用发送过来的消息
func session(_ session: WCSession, didReceiveUserInfo wcSessionPiggyBanks: [String : Any]) {
// 接收到的 userInfo 字典
print("Received user info: \(wcSessionPiggyBanks)")
if let piggyBank = wcSessionPiggyBanks["piggyBanks"] as? [[String: Any]] {
print("piggyBank:\(piggyBank)")
piggyBanks = piggyBank.compactMap {
if let name = $0["name"] as? String,
let icon = $0["icon"] as? String,
let amount = $0["amount"] as? Double,
let targetAmount = $0["targetAmount"] as? Double,
let isPrimary = $0["isPrimary"] as? Bool {
return PiggyBank(name: name, icon: icon, amount: amount, targetAmount: targetAmount, isPrimary: isPrimary)
}
return nil // 如果解包失败,则返回 nil
}
}
print("piggyBanks:\(piggyBanks)")
}
// 激活完成后的处理
func session(_ session: WCSession, activationDidCompleteWith state: WCSessionActivationState, error: Error?) {
if let error = error {
print("Watch端 WCSession 激活失败: \(error)")
} else {
print("Watch端 WCSession 激活成功,状态: \(state.rawValue)") // 输出状态
}
}
}
struct PiggyBank: Codable {
var name: String
var icon: String
var amount: Double
var targetAmount: Double
var isPrimary: Bool
}
WatchSessionDelegate
这是 WatchOS 应用的代理类,负责处理 WCSession 相关的回调。它实现了 WCSessionDelegate 协议,能够处理数据接收、激活和错误等事件。
session(_:didReceiveUserInfo:)
该方法是用来接收从 iOS 应用发送的用户信息数据。在这里,它将从 iOS 传递过来的 piggyBanks 数据解码,并存储到 piggyBanks 数组中。解码使用 compactMap 来确保只有成功解包的 PiggyBank 对象会被存储。
session(_:activationDidCompleteWith:)
当 WCSession 激活完成时,这个回调方法会被调用。在这个方法里,可以检查 WCSession 是否成功激活,并处理可能的错误。
PiggyBank 数据模型
PiggyBank 是用来表示存钱罐的数据模型。它符合 Codable 协议,意味着它可以被序列化为 JSON 格式,并且可以从 JSON 格式反序列化。
5、在WatchOS显示内容
struct Home: View {
@Environment(WatchSessionDelegate.self) var wcSessionDelegateImpl // 从环境中读取 Person
var body: some View {
VStack {
if !wcSessionDelegateImpl.piggyBanks.isEmpty {
Text("\(mainPiggyBank.name)")
.font(.footnote)
} else {
Image("emptyBox")
.resizable()
.scaledToFit()
.frame(width: 100)
}
}
}
}
从Enviroment中通过wcSessionDelegateImpl接收数据,在Text视图中将相关内容显示出来。
总结
WatchConnectivity 是 iOS 和 WatchOS 之间的数据传输桥梁,通过它,可以在这两种设备上实现信息同步、即时消息传递以及背景数据传输等功能。通过正确实现 WCSession,使得 iPhone 和 Apple Watch 应用之间的互动更为流畅和高效。
从WCSession中传递过来的数据仍然需要存储,现在的Watch已经支持SwiftData,因此可以考虑使用iCloud + SwiftData实现数据的传递和存储。
在实际应用的代码示例中,我们使用的是transferUserInfo方法传输数据。
WCSession.default.transferUserInfo(…) 是 iOS 或 watchOS 调用时立即排入传输队列,不需要另一端 App 正在运行。当另一端设备(如 Watch)上线后(即系统检测到设备可用),系统会自动后台启动 App 并触发回调,即使 App 是关闭状态。
如果使用sendMessage方法传递数据,iOS和Watch应用就需要在前台打开,并且还需要依赖isReachable方法,判断是否iOS和Watch应用是否都在前台以及可连接的状态。
if WCSession.default.isReachable {
print("iOS与Watch链接成功")
} else {
print("iOS与Watch链接失败")
}
需要注意的是,WCSession.default.isReachable只有在iOS端和Watch端都打开的情况下,才可以实现数据的传递,因此并不是适用于只打开Watch端的情况下显示数据。
补充知识点(2025年5月14日):经过群友“熊宝”的补充,在Watch和iOS模拟器中使用 isReachable 连接WatchConnectivity时,需要一些使用技巧:
1、在打开Watch模拟器后,需要先点击“返回主见面”按钮。

2、重新打开WatchApp。

这样才能让iOS和Watch模拟器正确的关联上WatchConnectivity。
扩展知识
Xcode提示Connecting to 方君宇的Apple Watch
如果在连接Watch的过程中,存在提示:
Connecting to 方君宇的Apple Watch
可以参考《Xcode提示Connecting to 方君宇的Apple Watch》。
后台接受远程通知
如果Watch需要执行额外的任务,比如定期在后台获取IOS数据,更新应用内容,可以在Capabilities 中启用 Remote Notifications功能。
在 Xcode 中,确保 iOS Capabilities 配置正确。
打开 iOS 应用的 Target,进入 Signing & Capabilities 选项卡,确保以下内容:

Background Modes:启用 Background fetch 和 Remote notifications(如果需要后台通信)。
Push Notifications:如果需要推送通知,确保启用。


对于 WatchOS 应用,通常不需要额外的 Capabilities 配置。
具体的后台同步内容则需要根据自身的需求进行设计。
transferUserInfo 工作机制
1、调用时:
transferUserInfo 会把数据打包存入一个系统级传输队列(由系统持久化,不会因重启丢失)。
此操作不会立即发送数据,也不需要另一端 App 正在运行或前台。
2、Watch 离线时(关机/未激活 App):
数据将暂存在系统队列中。
3、Watch 回到在线状态时(开机、连上蓝牙/网络等):
系统会后台启动 Watch App(若未运行),并将数据通过 WCSessionDelegate 的 didReceiveUserInfo 方法传递给Watch。
iPhone 端:
WCSession.default.transferUserInfo(["steps": 1000])
即使 Watch 此时:
1、是关机状态。
2、没打开 App。
3、蓝牙暂时断开。
数据会等待 Watch 上线,再由系统传送。
Watch 端:
当 Watch 被系统后台唤醒(什么都没点),就会调用:
func session(_ session: WCSession, didReceiveUserInfo userInfo: [String : Any]) {
print("收到离线数据:", userInfo)
}
尽管系统可靠处理,但不要传输大量数据,推荐用于小量结构化信息(如 JSON 字典)。
不能传自定义类型或对象,要是 plist 类型。
如果需要传文件,请使用 transferFile(_:metadata:)。
相关文章
Xcode提示Connecting to 方君宇的Apple Watch:https://fangjunyu.com/2025/02/19/xcode%e6%8f%90%e7%a4%baconnecting-to-%e6%96%b9%e5%90%9b%e5%ae%87%e7%9a%84apple-watch/