watchconnectivity not working on device - only simulator - ios

I have followed many tutorials online and seen how to connect the watch with the iPhone to be able to send data and have the following code to:
Send:
watchSession.sendMessage(["name":"Maz"], replyHandler: nil) { (error) -> Void in
}
Receive:
func session(session: WCSession, didReceiveMessage message: [String : AnyObject]) {
myLabel.setText(message["name"]! as? String)
//reloadWatchTable()
}
The code works when I use the simulator but not when I'm running on my iPhone and Apple Watch.

Related

Watch can not receive reply from phone with WatchConnectivity

Test with iphone11(14.6) and watch series3(7.5)
In my project, I use WatchConnectivity between phone and watch to communication,
When watch send message with below code, every time run is OK.
wcSession.sendMessage(message as [String : Any], replyHandler: nil)
But when watch send message need reply, it seems error.
wcSession.sendMessage(message) { (reply) in
} errorHandler: { (error) in
}
In Phone with below code to deal with request
func session(_ session: WCSession, didReceiveMessage message: [String : Any]) {
}
func session(_ session: WCSession, didReceiveMessage message: [String : Any], replyHandler: #escaping ([String : Any]) -> Void) {
}
I debug the code, didReceiveMessage with reply data can be called, but watch can not receive the reply. So what’s my problem, Before the mobile and watch update, everything is good, every update will cause problems, how to ensure the stability of the app?Thank you very much.

WC WCSession counterpart app not installed

Making a connection between iOS and iWatch devices, xCode writes [WC] WCSession counterpart app not installed.
After a lot of research, I've found a solution, maybe it will be helpful for someone.
- Check your WatchKit Extention target.
- Uncheck "Supports Running Without iOS App Installation"
- First run iwatch simulator, than run ios simulator with checkmark
I have spent around 3-4 hr to fix this issue, it seems that somehow my Apple watch.app is missing from my Target > Frameworks so after clicking plus icon and adding it back, it doesn't report "WC WCSession counterpart app not installed" anymore
Finally, I made it. For anyone else, who has this problem:
In iOS Target: Make sure in General>Frameworks, Libraries & Embedded Contents> Add YourWatchApp.app if it's not in the list. (For the loop problem, do the next step)
In Watch Target: Go to BuildPhases>Copy Bundle Resources> and remove YouriOSApp.app from the list if exists.
You must set delegate and activate it from both WatchApp and iOSApp as follows:
self.session = WCSession.default
self.session.delegate = self
self.session.activate()
if you are using a helper class, Your class should implement NSObject as well:
class ConnectivityHelper: NSObject, WCSessionDelegate {
Make sure there is some seconds between calling activate method and sending message.
If you are using a reply handler when sending message from Watch, Then you must implement didReceiveMessage method in iOS App which has replyHandler, else replyHandler on the watch returns an error and the iOS app won't receive the message.
Check out this complete code that is working: iOS Part:
import WatchConnectivity
class PhoneConnectivity: NSObject {
override init() {
super.init()
let session = WCSession.default
session.delegate = self
session.activate()
}
}
extension PhoneConnectivity: WCSessionDelegate {
//MARK: Delegate Methodes
func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) {
}
func sessionDidBecomeInactive(_ session: WCSession) {
}
func sessionDidDeactivate(_ session: WCSession) {
}
// Receiver
func session(_ session: WCSession, didReceiveMessage message: [String : Any]) {
//without reply handler
}
func session(_ session: WCSession, didReceiveMessage message: [String : Any], replyHandler: #escaping ([String : Any]) -> Void) {
//with reply handler
}
// end Receiver
}
send message with a test string first like:
WCSession.default.sendMessage(["TEST", "TEST2"], replyHandler: { dictionary in
print(">WC> reply recieved: \(dictionary.first!.value)")
}, errorHandler: { error in
print(">WC> Error on sending Msg: \(error.localizedDescription)")
})
Most developers suggest that make session active ASAP (in iOS using didFinishLaunchingWithOptions in appDelegate of iOSApp & applicationDidFinishLaunching in WKExtensionDelegate of WatchApp)
It only worked for me by installing the Watch App from the watch settings app.
If I install the Watch App from xcode, the iOS app will give me the companion error message.

Apple Watch Kit load data on start up

How to quickly load data on Apple Watch? UserDefaults doesn't work since watchOS 2, so we can only use WCSessionDelegate, right?
Now, on Watch App start I call wcSession?.sendMessage(someThing, replyHandler: someFunc, errorHandler: otherFunc), then on iPhone app I send back some data in
func session(_ session: WCSession, didReceiveMessage message: [String : Any], replyHandler: #escaping ([String : Any]) -> Void)
And finally receive it on watch app in func session(_ session: WCSession, didReceiveMessage message: [String : Any]), but that takes like 3 seconds.
What would be better way to get data on start up?
You could try using the reply Handler function instead of initiating a new message. It should work faster.
Call this from watch:
func sendRequest() {
if session.activationState == .activated && session.isReachable {
session.sendMessage(["Watch Message" : "Request"], replyHandler: { (reply) in
// Handle reply here
}, errorHandler: { (error) in
print("***** Error Did Occur: \(error) *****")
})
}
}
Handle and Respond on Phone:
func session(_ session: WCSession, didReceiveMessage message: [String : Any], replyHandler: #escaping ([String : Any]) -> Void) {
if let messageFromWatch = message["Watch Message"] {
let messageData = messageFromWatch as! String
// Message From Watch to Activate Watch Connectivity Session
if messageData == "Request" {
replyHandler(["Response" : data])
}
}
}

Error in Sending message From Watch To Iphone

I'm working on a watch app. I have to send data from the mobile to watch.
This is working properly.
The main problem occurs when I'm sending message from watch to mobile app because I want that the communication to be initiated by watch app. I have implemented the method to send data from watch to mobile app but always getting this
"WCErrorDomain Code=7014 "Payload could not be delivered." error.
I'm using xcode 7.3 and watchOS version is 2.0.
One more thing: is it possible that the sendMessage method opens the mobile app in background using watch connectivity framework?? Or if anyone knows any other way to open the mobile app in background then please suggest me. Thanks in advance.
session.sendMessage(message, replyHandler: { reply in
}, errorHandler: { error in
print("error: \(error)")
})
EDIT
In AppDelegate and ExtensionDelegate:
override init() {
super.init()
setupWatchConnectivity()
}
private func setupWatchConnectivity() {
if WCSession.isSupported() {
let session = WCSession.defaultSession()
session.delegate = self
session.activateSession()
}
}
In ExtensionDelegate:
func sendMessage(){
let session = WCSession.defaultSession()
let applicationData:[String:AnyObject] = ["text":"test", "badgeValue": 100 ]
WatchSessionManager.sharedManager.sendMessage(applicationData, replyHandler: {replyMessage in
print("reply received from iphone")
}, errorHandler: {(error ) -> Void in
// catch any errors here
print("no reply message from phone")
})
}
In AppDelegate:
func session(session: WCSession, didReceiveMessage message: [String : AnyObject], replyHandler: ([String : AnyObject]) -> Void) {
let text = message["text"] as! String
let badgeValue = message["badgeValue"] as! Int
dispatch_async(dispatch_get_main_queue()) { () -> Void in
print("iphone received message from watch App")
self.sendNotification(text, badgeValue: badgeValue)
let applicationDict = ["wake": "nowAwake"]
replyHandler(applicationDict as [String : String])
}
}
In watchSessionManager :
func sendMessage(message: [String : AnyObject], replyHandler: (([String : AnyObject]) -> Void)?, errorHandler: ((NSError) -> Void)? = nil){
session.sendMessage(message, replyHandler: { reply in
}, errorHandler: { error in
print("error: \(error)")
})
print("mesage %#",message)
}

Trigger a segue from Watch in iPhone

Is it possible to trigger a segue in the iPhone app from the Watch code? I have been looking into OS2 and it says that data can be transferred while both apps are active, but want to know if it is possible to call code within the iPhone app from the Watch code.
You can not push segue from WatchApp(Child Application) to iPhone App (Parent Application), but you can surely send data from Watch to iPhone and according to that data you can perform segue on iPhone Application.
To Send update from Apple Watch to iPhone App you have to implement openParentApplication in WatchKit Extension.
class func openParentApplication(userInfo: [NSObject : AnyObject], reply: (([NSObject : AnyObject], NSError?) -> Void)?) -> Bool
Create NSDictionary and pass that data using below code :
func updateInformationToParentApp(emergencyInfo : [NSObject : AnyObject]!){
// Call the parent application from Apple Watch
WKInterfaceController.openParentApplication(emergencyInfo) { (returnUpdate, error) -> Void in
if((error) == nil){
print("Data send successfully");
} else {
print("Error : \(error?.localizedDescription)");
}
}
}
Implement below method in AppDelegate to handle WatchApp update.
func application(application: UIApplication, handleWatchKitExtensionRequest userInfo: [NSObject : AnyObject]?, reply: ([NSObject : AnyObject]?) -> Void){
NSLog("Handler Apple Watch Event ");
watchEvent(userInfo, reply: reply);
}
func watchEvent(userInfo: [NSObject : AnyObject]!, reply: (([NSObject : AnyObject]!) ->Void)!) {
let dic = userInfo as NSDictionary;
NSLog("dic %#", dic);
// retrieved parameters from Apple Watch
print(userInfo["Key"])
//Perform Segue from Here according to Dictionary Info
//Pass back values to Apple Watch
var returnUpdate = Dictionary<String,AnyObject>()
let watchAppMessage = "Meesage Back To Apple Watch" as NSString;
returnUpdate["message"] = NSKeyedArchiver.archivedDataWithRootObject(watchAppMessage);
reply(returnUpdate)
}
You can see iPhone and iWatch contains different storyboards and different user interfaces, so segue from watch to iPhone is surely not possible but you can manage something like that with notifications as if in iWatch some button is pressed, you can send notification to iPhone environment and it can trigger some action.

Resources