swift 如何在 Watch 和后台 iPhone 之间共享数据

swift how to share data between Watch and iPhone on background

我有一个功能性应用程序可以在 iPhone 和 Watch 之间共享数据(共享文本),我想让它即使在手表设置为后台时也能正常工作(从 iPhone 发送数据在 Watch 处于后台时观看)。我阅读了很多有关如何制作此内容的文章,但似乎对我的应用程序没有任何好处。请添加代码以使应用程序像我之前所说的那样工作。或者给我一些适合这个应用程序的资源。谢谢!

iPhone的代码:

    import UIKit
    import WatchConnectivity
    class ViewController: UIViewController, WCSessionDelegate {

    @IBOutlet weak var iPhoneLabel: UILabel!
    var session : WCSession!;

    func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) {

    }

    func sessionDidBecomeInactive(_ session: WCSession) {

    }

    func sessionDidDeactivate(_ session: WCSession) {

    }

    func session(_ session: WCSession, didReceiveMessage message: [String : Any]) {
        let msg = message["b"] as? String;
        self.iPhoneLabel.text = msg;

    }



    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.

        if(WCSession.isSupported()){
            self.session = WCSession.default;
            self.session.delegate = self;
            self.session.activate();
        }
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }


    @IBAction func sendMessage(_ sender: Any) {
         session.sendMessage(["a" : "Hello"], replyHandler: nil, errorHandler: nil);
    }
}

手表代码:

    import WatchKit
    import Foundation
    import WatchConnectivity
    import UIKit

    class InterfaceController: WKInterfaceController, WCSessionDelegate {

    func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) {

    }


    @IBOutlet var WatchLabel: WKInterfaceLabel!
    var session: WCSession!;

    func session(_ session: WCSession, didReceiveMessage message: [String : Any]) {
        //self.label.setText(message["a"]! as? String)


        let msg = message["a"] as? String;
        WatchLabel.setText(msg);
        sendMessage();



    }

    func sendMessage(){
         session.sendMessage(["b":"goodbye"], replyHandler: nil, errorHandler: nil);
    }


    override func awake(withContext context: Any?) {
        super.awake(withContext: context)

        // Configure interface objects here.
    }

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

        if(WCSession.isSupported()){
            self.session = WCSession.default;
            self.session.delegate = self;
            self.session.activate();
        }
    }

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

在我将方法 session.sendMessage() 更改为 session.updateApplicationContext() 之后,它只有效一次。有什么建议吗?

iPhone的代码:

import UIKit

import WatchConnectivity


class ViewController: UIViewController, WCSessionDelegate {


@IBOutlet weak var iPhoneLabel: UILabel!

var session : WCSession!;



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

func sessionDidBecomeInactive(_ session: WCSession) {
}


 func sessionDidDeactivate(_ session: WCSession) {
}




 func session(_ session: WCSession, didReceiveApplicationContext applicationContext: [String : Any]) {



let msg = applicationContext["b"] as? String

//Use this to update the UI instantaneously (otherwise, takes a little while)
DispatchQueue.main.async() {
    self.iPhoneLabel.text = msg;
}

}



override func viewDidLoad() {
super.viewDidLoad()


if(WCSession.isSupported()){
    self.session = WCSession.default;
    self.session.delegate = self;
    self.session.activate();
}
}


override func didReceiveMemoryWarning() {

super.didReceiveMemoryWarning()

}


@IBAction func sendMessage(_ sender: Any) {



let applicationDict = ["a":"Hello"];
do {
    try session.updateApplicationContext(applicationDict)
} catch {
    print("error")
}
}

}

观看代码:

import WatchKit

import Foundation

import WatchConnectivity

import UIKit


class InterfaceController: WKInterfaceController, WCSessionDelegate {


func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) {

}


@IBOutlet var WatchLabel: WKInterfaceLabel!
var session: WCSession!;



func session(_ session: WCSession, didReceiveApplicationContext applicationContext: [String : Any]) {
    print("Watch message received")

    let msg = applicationContext["a"] as? String
    DispatchQueue.main.async() {
        self.WatchLabel.setText(msg);
    }
    sendMessage();
}

func sendMessage(){


    print("Watch send message");
    let applicationDict = ["b":"goodbye"];
    do {
        try session.updateApplicationContext(applicationDict)
    } catch {
        print("error")
    }
}


override func awake(withContext context: Any?) {
    super.awake(withContext: context)

    // Configure interface objects here.
}

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

    if(WCSession.isSupported()){
        self.session = WCSession.default;
        self.session.delegate = self;
        self.session.activate();
    }
}

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

}

简而言之,您应该使用 updateApplicationContext 方法而不是 sendMessage 方法,以便能够从 iPhone 应用程序发送数据,即使 Watch 应用程序在后台也是如此。更多信息,请继续。

如果您查看 documentation,它表明调用 session.sendMessage 不会唤醒 Watch 应用程序,如果它 运行 仅在后台运行。

Calling this method from your WatchKit extension while it is active and running wakes up the corresponding iOS app in the background and makes it reachable. Calling this method from your iOS app does not wake up the corresponding WatchKit extension. If you call this method and the counterpart is unreachable (or becomes unreachable before the message is delivered), the errorHandler block is executed with an appropriate error.

它还声明此功能仅在 isReachabletrue 时有效。

Use the sendMessage(:replyHandler:errorHandler:) or sendMessageData(:replyHandler:errorHandler:) method to transfer data to a reachable counterpart. These methods are intended for immediate communication between your iOS app and WatchKit extension. The isReachable property must currently be true for these methods to succeed.

要发送用于更新 UI 的数据,您应该使用 updateApplicationContext(_:) 方法,using which

The system sends context data when the opportunity arises, with the goal of having the data ready to use by the time the counterpart wakes up.

要使此方法起作用,session 只需激活,不需要可达。