如何使用 WatchConnectivity 在我的 iOS 和 Watch 应用程序之间共享信息?

How can I share information between my iOS and Watch apps using WatchConnectivity?

[免责声明:此问题旨在成为一个 wiki 问题,用于回答有关 iOS 和 watchkit 和 [= 下的 watch 应用程序之间发送数据的常见问题12=] 标签。]

我正在开发 Apple Watch 应用程序,想在 iOS 应用程序与其 WatchKit extension 之间发送数据。我看过 WatchConnectivity 框架,但并不真正理解其所有方法之间的区别。

如果我想即使我的应用程序在后台也能发送数据,我应该使用哪个功能?

我应该使用哪个函数向手表发送 UI 更新?

发送大数据应该使用哪个函数?

在撰写此答案时(watchOS3 是当前的稳定版本,watchOS4 处于测试阶段),direct 的唯一选择iOS 应用与其 WatchKit extension 之间的通信是 WatchConnectivity 框架。 (我说的是直接的,因为这个问答不涉及使用CloudKit等云技术从一台设备上传文件到互联网并在另一台设备上下载。

首先,让我们讨论一下WCSession的哪个功能应该用于什么目的。有关代码示例,请向下滚动。

在深入了解细节之前,简要介绍每个功能以及何时使用它们:

  • updateApplicationContext:app之间同步状态,发送数据显示在UI(只用于发送小块数据)
  • transferUserInfo:后台发送数据字典
  • transferFile: 后台发送一个文件
  • sendMessage:发送即时消息至少手表应用程序是运行在前台

详细说明

updateApplicationContext(_:) 如果你想同步你的应用程序(例如保持 UI 更新或发送状态信息,如用户登录等),应该使用。您可以发送数据字典。对该函数的后续调用会替换之前发送的字典,因此对方应用仅接收使用 updateApplicationContext 发送的最后一项。系统会尝试在适当的时间调用此函数,以便在需要时接收数据,同时最大限度地减少功耗。因此,当两个应用程序都不是 运行 在前台时可以调用该函数,但需要激活 WCSession 才能传输成功。尝试使用 updateApplicationContext 传输大量数据的频繁调用可能会失败,因此对于此用法,请改为调用 transferUserInfo

transferUserInfo(:) and transferCurrentComplicationUserInfo(:) 如果你想在后台发送需要被其他应用程序接收的数据,应该使用。对该方法的后续调用将排队,并接收从一个应用程序发送到另一个应用程序的所有信息。 transferCurrentComplicationUserInfo 可用于使用高优先级消息将与并发症相关的数据发送到 WatchKit extension,并在需要时唤醒 WatchKit app。但是,请注意此功能有每日限制,一旦超过,将使用 transferUserInfo 功能传输数据。

transferFile(_:metadata:) 在实现和性质上与 transferUserInfo 相似,但它接受 fileURL 而不是字典作为其输入参数,因此它应该用于将设备本地文件发送到它的对应物。后续呼叫排队。收到的文件必须保存到session(_:didReceive:)方法中的新位置,否则将被删除。

sendMessage(:replyHandler:errorHandler:) and sendMessageData(:replyHandler:errorHandler:) 立即将数据发送到对应的应用程序。在调用此方法之前,必须可以访问对端应用程序。 iOS 应用程序始终被认为是可访问的,并且从您的 Watch 应用程序调用此方法会根据需要在后台唤醒 iOS 应用程序。 Watch 应用程序仅在已安装且 运行 时才被视为可访问。传输必须在前台启动。对该方法的后续调用将排队。

有关详细信息,请参阅 App programming guide for watchOS - Sharing Data

现在一些代码示例:

iOS 应用的 AppDelegate 中设置 WatchConnectivity:

import UIKit
import WatchConnectivity

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        if WCSession.isSupported() {
            let session = WCSession.default()
            session.delegate = self
            session.activate()
        }
        return true
    }
}

extension AppDelegate: WCSessionDelegate {

    func session(_ session: WCSession, didReceiveMessage message: [String : Any]) {
        print("Message received: ",message)
    }

    //below 3 functions are needed to be able to connect to several Watches
    func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) {}

    func sessionDidDeactivate(_ session: WCSession) {}

    func sessionDidBecomeInactive(_ session: WCSession) {}
}

让你的WatchKitclass符合WCSessionDelegate:

extension InterfaceController: WCSessionDelegate {
    func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) {}
}

使用即时通讯功能,sendMessage:

WatchKit app 中,如果您想立即将信息发送到 iOS 应用程序,请使用此代码。

if WCSession.isSupported() {
    print("WCSession supported")
    let session = WCSession.default()
    session.delegate = self
    session.activate()
    if session.isReachable {
        session.sendMessage(["Instant":"Message"], replyHandler: nil, errorHandler: { error in
            print("Error sending message",error)
        })
    }
}