0

我创建了一个程序来测试从 iPhone 和 AppleWatch 来回发送数据,反之亦然。我已经设置好了,AppleWatch 上有一个按钮,iPhone 上有一个按钮。当 iPhone 被按下时,它将发送数据并将 AppleWatch 上的按钮重命名为该数据字符串。

然后我为 iPhone 实现了 AppleWatch 的相同代码,但由于某种原因,iPhone 似乎没有接收到数据。这是 iPhone 的代码:

//  ViewController.swift

import UIKit
import Foundation
import WatchConnectivity

class WatchManager: UIViewController, WCSessionDelegate {

    var watchSession: WCSession? {
        didSet {
            if let session = watchSession {
                session.delegate = self
                session.activate()
            }
        }
    }

    override func viewDidLoad(){
        super.viewDidLoad()

        watchSession = WCSession.default

    }

    private func sendDict(_ dict: [String: Any]) {
        do {
            try self.watchSession?.updateApplicationContext(dict)
        } catch {
            print("Error sending dictionary \(dict) to Apple Watch!")
        }
    }

    @IBOutlet weak var transferButton: UIButton!

    @IBAction func dataTransfer(_ sender: Any) {
        sendDict(["DataKey": UUID().uuidString])
        print("sent")
    }

    func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) {
        print("Session activation did complete")
    }

    public func sessionDidBecomeInactive(_ session: WCSession) {
        print("session did become inactive")
    }

    public func sessionDidDeactivate(_ session: WCSession) {
        print("session did deactivate")
    }

    func session(_ session: WCSession, didReceiveApplicationContext applicationContext: [String : Any]) {
        print("phone received app context: ", applicationContext)
        if let temperature = applicationContext["DataKey"] as? String {
            self.transferButton.setTitle(temperature, for: .normal)
        }

    }

}

和苹果手表:

//  InterfaceController.swift

import WatchKit
import Foundation
import WatchConnectivity


class InterfaceController: WKInterfaceController {

    var watchSession: WCSession? {
        didSet {
            if let session = watchSession {
                session.delegate = self
                session.activate()
            }
        }
    }


    @IBOutlet weak var temperatureLabel: WKInterfaceButton!

    private func sendDict(_ dict: [String: Any]) {
        do {
            try self.watchSession?.updateApplicationContext(dict)
        } catch {
            print("Error sending dictionary \(dict) to iPhone!")
        }
    }

    @IBAction func button() {
        let urg = ["DataKey":UUID().uuidString]
        sendDict(urg)
        print("watch sent app context \(urg)")
    }

}

extension InterfaceController: WCSessionDelegate {

    #if os(iOS)
    public func sessionDidBecomeInactive(_ session: WCSession) { }
    public func sessionDidDeactivate(_ session: WCSession) {
        session.activate()
    }
    #endif

    func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) {
        print("Session activation did complete")
    }

    func session(_ session: WCSession, didReceiveApplicationContext applicationContext: [String : Any]) {
        print("watch received app context: ", applicationContext)
        if let temperature = applicationContext["DataKey"] as? String {
            self.temperatureLabel.setTitle(temperature)
        }

    }

    override func willActivate() {
        // This method is called when watch view controller is about to be visible to user
        super.willActivate()

        watchSession = WCSession.default

    }

    override func didDeactivate() {
        // This method is called when watch view controller is no longer visible
        super.didDeactivate()
    }

}

我尝试更改密钥的名称(没有用),我做到了,所以数据值总是在变化(UUID().uuidString)并保持不变。我尝试的其他事情包括创建一个标签并尝试重命名它而不是失败的按钮,最后不是重命名按钮,而是发送一些确认它接收到数据回失败的苹果手表。

任何帮助将不胜感激,我希望这不是一个愚蠢的错误。

4

2 回答 2

1

我认为updateApplicationContext这不是满足您需求的正确方法。来自文档: 当机会出现时,系统会发送上下文数据,目标是在对方醒来时准备好使用数据。 如果您想在两个应用程序都在前台时来回发送数据sendMessage应该可以工作。

最后,您可能需要实现这两种方法的组合。我建议阅读以下文档:https ://developer.apple.com/documentation/watchconnectivity/wcsession

编辑:

为了更清楚地说明“最终您可能需要实现两种方法的组合”这一点,我已经从我的一个应用程序中添加了一些示例代码。

如果手表可访问,该方法_sendData会尝试通过 发送当前数据。sendMessageData如果不是,它会更新应用程序上下文以在手表应用程序启动时提供一些可用的数据。

- (void)_sendCurrentData
{
    if ([WCSession defaultSession].isPaired && [WCSession defaultSession].isWatchAppInstalled)
    {
        if ([WCSession defaultSession].isReachable)
        {
            // Send data to watch
            [[WCSession defaultSession] sendMessageData:self.currentData
                                           replyHandler:nil
                                           errorHandler:^(NSError * _Nonnull error) {
                                               [self _updateApplicationContext];
                                           }];
        }
        else
        {
            [self _updateApplicationContext];
        }
    }
}

- (void)_updateApplicationContext
{
    if ([WCSession defaultSession].isPaired && [WCSession defaultSession].isWatchAppInstalled)
    {
        NSError* error = nil;
        [[WCSession defaultSession] updateApplicationContext:@{@"data": self.currentData}
                                                       error:&error];
        if (error != nil)
        {
            NSLog(@"error while updating application context: %@", error.localizedDescription);
        }
    }
}
于 2019-01-09T08:18:40.367 回答
0
use self.watchSession?.transferUserInfo(dict) instead of self.watchSession?.updateApplicationContext(dict) 
you'll got a call back in:
    func session(_ session: WCSession, didReceiveUserInfo userInfo: [String : Any] = [:]) {
}
于 2019-01-09T08:34:53.473 回答