在 SwiftUI 中使用 WCSession 向 Apple Watch 发送消息
Posted
技术标签:
【中文标题】在 SwiftUI 中使用 WCSession 向 Apple Watch 发送消息【英文标题】:Send Message to Apple Watch using WCSession in SwiftUI 【发布时间】:2020-01-18 19:36:54 【问题描述】:我很久以前做过一个例子,如何使用 Swift 从 iPhone 向 Apple Watch 发送简单的消息:
import UIKit
import WatchConnectivity
class ViewController: UIViewController, WCSessionDelegate
// MARK: Outlets
@IBOutlet weak var textField: UITextField!
// MARK: Variables
var wcSession : WCSession! = nil
// MARK: Overrides
override func viewDidLoad()
super.viewDidLoad()
wcSession = WCSession.default
wcSession.delegate = self
wcSession.activate()
// MARK: Button Actions
@IBAction func sendText(_ sender: Any)
let txt = textField.text!
let message = ["message":txt]
wcSession.sendMessage(message, replyHandler: nil) (error) in
print(error.localizedDescription)
// MARK: WCSession Methods
func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?)
// Code
func sessionDidBecomeInactive(_ session: WCSession)
// Code
func sessionDidDeactivate(_ session: WCSession)
// Code
现在我正在尝试使用 SwiftUI 做同样的事情,但到目前为止没有成功。 谁能帮忙解决这个问题?
我只需要知道如何在 SwiftUI 中使用 WCSession 类和 WCSessionDelegate。
谢谢
【问题讨论】:
【参考方案1】:我刚刚和你有同样的问题,我想通了:
首先你需要实现一个符合WCSessionDelegate
的类。我喜欢为此使用一个单独的类:
import WatchConnectivity
class ConnectivityProvider: NSObject, WCSessionDelegate
private let session: WCSession
init(session: WCSession = .default)
self.session = session
super.init()
self.session.delegate = self
func send(message: [String:Any]) -> Void
session.sendMessage(message, replyHandler: nil) (error) in
print(error.localizedDescription)
func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?)
// code
func sessionDidBecomeInactive(_ session: WCSession)
// code
func sessionDidDeactivate(_ session: WCSession)
// code
现在您需要一个将您的 ConnectivityProvider 作为参数的 ViewModel。 ViewModel 将负责您的 View 和 ConnectivityProvider 的连接。它还保存稍后在您的视图中定义的文本字段的值。
import SwiftUI
final class ViewModel: ObservableObject
private(set) var connectivityProvider: ConnectivityProvider
var textFieldValue: String = ""
init(connectivityProvider: ConnectivityProvider)
self.connectivityProvider = connectivityProvider
func sendMessage() -> Void
let txt = textFieldValue
let message = ["message":txt]
connectivityProvider.send(message: message)
现在您可以构建一个由文本字段和按钮组成的简单视图。您的 View 将依赖于您刚刚定义的 ViewModel。
import SwiftUI
struct ContentView: View
@ObservedObject var viewModel: ViewModel
var body: some View
VStack
TextField("Message Content", text: $viewModel.textFieldValue)
Button(action:
self.viewModel.sendMessage()
)
Text("Send Message")
最后但同样重要的是,您需要在 SceneDelegate 中组合 ConnectivityProvider、ViewModel 和 View:
let viewModel = ViewModel(connectivityProvider: ConnectivityProvider())
let contentView = ContentView(viewModel: viewModel)
...
window.rootViewController = UIHostingController(rootView: contentView)
===================================
更新:如何激活会话?
首先向您的 ConnectivityProvider 添加一个激活会话的新函数:
class ConnectivityProvider: NSObject, WCSessionDelegate
...
func connect()
guard WCSession.isSupported() else
print("WCSession is not supported")
return
session.activate()
...
现在您可以在需要连接 WCSession 时调用 connect 函数。您应该能够在任何地方连接它,例如在您的 SceneDelegate、您的 ViewModel 中,甚至直接在您的 ConnectivityProvider 的 init 中:
ConnectivityProvider 初始化:
class ConnectivityProvider: NSObject, WCSessionDelegate
private let session: WCSession
init(session: WCSession = .default)
self.session = session
super.init()
self.session.delegate = self
self.connect()
...
视图模型:
import SwiftUI
final class ViewModel: ObservableObject
private(set) var connectivityProvider: ConnectivityProvider
var textFieldValue: String = ""
init(connectivityProvider: ConnectivityProvider)
self.connectivityProvider = connectivityProvider
self.connectivityProvider.connect()
func sendMessage() -> Void
let txt = textFieldValue
let message = ["message":txt]
connectivityProvider.send(message: message)
场景代理:
let connectivityProvider = ConnectivityProvider()
connectivityProvider.connect()
let viewModel = ViewModel(connectivityProvider: connectivityProvider)
let contentView = ContentView(viewModel: viewModel)
...
window.rootViewController = UIHostingController(rootView: contentView)
【讨论】:
什么时候激活会话? 我确实向我的 ConnectivityProvider 添加了一个连接函数,并直接在我的 SceneDelegate 中调用它。但是您可以在需要的地方调用它,例如在 ConnectivityProvider 的 init 函数内部。 func connect() guard WCSession.isSupported() else print("WCSession is not supported") return session.activate() 你有使用 swiftUI 的工作代码吗?我一直很难让手表从我的手机接收消息。我可以使用苹果提供的 SimpleWatchConnectivity 项目,但它使用故事板。如果有一个 SwiftUI 的基本起点就好了。感觉这里少了点什么,不是要给手表设置接收功能吗?在上面的代码中,没有关于如何处理手表扩展的方向。 您是仅使用 SwiftUI 还是使用带有 App 和 SceneDelegates 的 SwiftUI? 我终于明白了! ConnectivityProvider 在我的 ios 应用程序中。我与扩展共享了目标成员资格,并在我的 Watch Extension 的 ContentView 中对其进行了初始化。非常棘手,但我相信您的指导,谢谢您的先生。以上是关于在 SwiftUI 中使用 WCSession 向 Apple Watch 发送消息的主要内容,如果未能解决你的问题,请参考以下文章
watchOS 3 在设备和手表之间共享的类中使用 WCSession
Xcode 9.2 Objective-C 与 WCSession 的链接器错误
在 Apple Watch 和 iPhone 之间使用 WCSession 共享数据