问题
I have a functional application for sharing the data between iPhone and Watch (share text) and I want to make it work even when the watch is set on background (send data from iPhone to Watch when Watch is on background). I read a lot about how to make this but nothing seemd to be ok for my application. Please add the code to make application work as I said before. Or give me some source which fit with this app. Thank you!
Code for 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);
}
}
Code for Watch:
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()
}
}
After I changed the method session.sendMessage() with session.updateApplicationContext() it only works once. Any advice?
Code for 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")
}
}
}
Code fore Watch:
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()
}
}
回答1:
In short, you should use the updateApplicationContext
method instead of the sendMessage
to be able to send data from the iPhone app even when the Watch app is in background. For further info, please continue on.
If you look at the documentation, it states that the calling session.sendMessage
doesn't wake the Watch
app if it is running only in the background.
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.
It also states that this function only works if the isReachable
is true
.
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.
For sending data that is used to update the UI, you should use the updateApplicationContext(_:)
method, 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.
For this method to work, the session
only needs to be activated, it doesn't need to be reachable.
来源:https://stackoverflow.com/questions/45462836/swift-how-to-share-data-between-watch-and-iphone-on-background