【问题标题】:Send Message to Apple Watch using WCSession in SwiftUI在 SwiftUI 中使用 WCSession 向 Apple Watch 发送消息
【发布时间】: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。

谢谢

【问题讨论】:

    标签: swiftui watchos


    【解决方案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 中对其进行了初始化。非常棘手,但我相信您的指导,谢谢您的先生。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多