【问题标题】:iPhone not receiving applicationContext from AppleWatchiPhone 未从 Apple Watch 接收应用程序上下文
【发布时间】:2019-01-09 08:08:16
【问题描述】:

我创建了一个程序来测试从 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)
        }

    }

}

和 AppleWatch:

//  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)并保持不变。我尝试过的其他事情包括创建一个标签并尝试重命名该标签而不是失败的按钮,最后不是重命名按钮,而是发送一些确认它已将数据发送回失败的 Apple Watch。

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

【问题讨论】:

    标签: ios iphone swift apple-watch wcsession


    【解决方案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);
            }
        }
    }
    

    【讨论】:

    • 在与延迟和userinfo 的挫败作斗争之后,我决定尝试sendMessage,并几乎为它传输数据的速度而哭泣。谢谢。
    【解决方案2】:
    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] = [:]) {
    }
    

    【讨论】:

    • 这只会在我单击 iPhone 按钮后更新 iPhone 按钮文本。因此,我单击手表按钮,并且在单击 iPhone 按钮之前,iPhone 按钮文本不会改变。这是为什么呢?
    • 我通过在 self.transferButton.setTitle(temperature, for: .normal) 周围添加 DispatchQueue.main.async{} 来修复它
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-10
    • 1970-01-01
    相关资源
    最近更新 更多