xmpp_messenger_ios Swift MUC swift - swift

I am trying to do a MUC on iOS using xmpp_messenger_ios & XMPPFramework
Here is the code to join the room.
func createOrJoinRoomOnXMPP(){
// location has named array of lat and long
NSLog("Creating room on XMPP")
let roomJID: XMPPJID = XMPPJID.jidWithString(self.roomID + "#conference.ip-172-31-41-100")
let roomData: XMPPRoomCoreDataStorage = XMPPRoomCoreDataStorage.sharedInstance()
let chatRoom = XMPPRoom.init(roomStorage: roomData, jid: roomJID, dispatchQueue: dispatch_get_main_queue())
chatRoom.activate(OneChat.sharedInstance.xmppStream)
chatRoom.addDelegate(self, delegateQueue: dispatch_get_main_queue())
// let history = DDXMLElement.elementWithName("history")
// // Get lst messegs of the room
// history.addAttributeWithName("maxstanzas", stringValue: "10")
chatRoom.joinRoomUsingNickname(OneChat.sharedInstance.xmppStream!.myJID.user, history: nil)
}
as soon as this block executes I get an error in this code:
extension OneMessage: XMPPStreamDelegate {
public func xmppStream(sender: XMPPStream, didSendMessage message: XMPPMessage) {
if let completion = OneMessage.sharedInstance.didSendMessageCompletionBlock {
completion(stream: sender, message: message)
}
//OneMessage.sharedInstance.didSendMessageCompletionBlock!(stream: sender, message: message)
}
public func xmppStream(sender: XMPPStream, didReceiveMessage message: XMPPMessage) {
let user = OneChat.sharedInstance.xmppRosterStorage.userForJID(message.from(), xmppStream: OneChat.sharedInstance.xmppStream, managedObjectContext: OneRoster.sharedInstance.managedObjectContext_roster())
if !OneChats.knownUserForJid(jidStr: user.jidStr) { // <<< ERROR LINE
OneChats.addUserToChatList(jidStr: user.jidStr)
}
if message.isChatMessageWithBody() {
OneMessage.sharedInstance.delegate?.oneStream(sender, didReceiveMessage: message, from: user)
} else {
//was composing
if let _ = message.elementForName("composing") {
OneMessage.sharedInstance.delegate?.oneStream(sender, userIsComposing: user)
}
}
}
}
fatal error: unexpectedly found nil while unwrapping an Optional value
I have noticed that as soon as the connection is made to chat room it fetches previous messages, and thus the above code is executed.
Please help me out is doing a MUC for room chat on ios. I have searched and have not found any solution.
thanks

I solved this by this temporary solution.
extension OneMessage: XMPPStreamDelegate {
public func xmppStream(sender: XMPPStream, didSendMessage message: XMPPMessage) {
if let completion = OneMessage.sharedInstance.didSendMessageCompletionBlock {
completion(stream: sender, message: message)
}
//OneMessage.sharedInstance.didSendMessageCompletionBlock!(stream: sender, message: message)
}
public func xmppStream(sender: XMPPStream, didReceiveMessage message: XMPPMessage) {
NSLog("This is blocked")
// let user = OneChat.sharedInstance.xmppRosterStorage.userForJID(message.from(), xmppStream: OneChat.sharedInstance.xmppStream, managedObjectContext: OneRoster.sharedInstance.managedObjectContext_roster())
//
// if !OneChats.knownUserForJid(jidStr: user.jidStr) {
// OneChats.addUserToChatList(jidStr: user.jidStr)
// }
//
// if message.isChatMessageWithBody() {
// OneMessage.sharedInstance.delegate?.oneStream(sender, didReceiveMessage: message, from: user)
// } else {
// //was composing
// if let _ = message.elementForName("composing") {
// OneMessage.sharedInstance.delegate?.oneStream(sender, userIsComposing: user)
// }
// }
}
}
Blocking the OneMessage.swift code.
and handling the incoming messages in my ViewController.
This is not the right way to do it. but until ProcessOne give support for MUC this can be done.

Unwrapping that causes nil happens on:
user (return value of userForJID method is XMPPUserCoreDataStorageObject! )
jidStr (the type is String!)
Investigate which one happens to be nil.
Possible causes of user to be nil
- Nil value of jid or managedObjectContext is used in userForJID(:xmppStream:managedObjectContext)`
To find out which one is nil, simply do this:
guard let user = OneChat.sharedInstance.xmppRosterStorage.userForJID(message.from(), xmppStream: OneChat.sharedInstance.xmppStream, managedObjectContext: OneRoster.sharedInstance.managedObjectContext_roster())
else { fatalError("user is nil") }
guard let userJIDStr = user.jidStr
else { fatalError("jidStr is nil") }

I think you need to understand XMPP MUC first, read this doc.
When you send a message to MUCRoom, the serve will broadcast the message to all the members, including yourself.
And here message.from() = room.jid BUT NOT user.jid.
That's why the user you tried to get from roster is nil.

Related

Can't connect players in GameKit using GKMatchmaker.shared().findMatch

I'm trying to connect two players with each other using GameKit in a very simple game. I want to use GKMatchmaker.shared().findMatch as I don't want to show any GameCenter related view controllers. (to keep it simple)
Problem:
Even though GameKit creates a match after finding two players, an error occurs that prevents either player from sending any message to the others.
Current Situation:
The basic code is as follows (based on the docs described here: https://developer.apple.com/documentation/gamekit/finding_multiple_players_for_a_game)
print("Requesting multiplayer match")
let request = GKMatchRequest()
request.minPlayers = 2
request.maxPlayers = 2
request.recipientResponseHandler = {(player: GKPlayer, respnse: GKInviteRecipientResponse) -> Void in
print("new player about to join")
print(player.alias)
print(respnse)
}
GKMatchmaker.shared().findMatch(for: request, withCompletionHandler: {
(match: GKMatch?, error: Error?) -> Void in
if error != nil {
// Handle the error that occurred finding a match.
print("error during matchmaking")
print(error as Any)
} else if match != nil {
guard let match = match else { return }
print("connected to \(match.players.count) players")
// load the multiplayer data handler
let handler = MultiMatchHandler()
match.delegate = handler
// load the multiplayer service
let service = MultiMatchService(match: match)
service.sendMessageToAll(text: "Hello from the other side")
// finish the match making
GKMatchmaker.shared().finishMatchmaking(for: match)
// Start the game with the players in the match.
self.view?.presentScene(GameScene.newScene(multiplayer: service))
}
})
The output of that is
Requesting multiplayer match
2022-01-05 01:19:16.554959+0100 Grapefruit[38300:10026027] [Match] cannot set connecting state for players: (
"<GKPlayer: 0x282add280>(alias:... gamePlayerID:... teamPlayerID:... name:... status:(null) friendBiDirectional:0 friendPlayedWith:1 friendPlayedNearby:0 acceptedGameInviteFromThisFriend:0 initiatedGameInviteToThisFriend:0 automatchedTogether:1)"
), as there is no inviteDelegate set yet. The state might directly change to Ready when we set the inviteDelegate later and call sendQueuedStatesAndPackets.
2022-01-05 01:19:16.557002+0100 Grapefruit[38300:10026027] [Match] syncPlayers failed to loadPlayersForLegacyIdentifiers: (
"..."
)
connected to 0 players
sending text Hello from the other side failed
Findings:
minPlayers is set to 2. As the completion handler is called this means that at least one more player was found. But the number of players returned in match.players.count is 0
The matcher shows an error saying that cannot set connecting state for players ... as there is no inviteDelegate set yet. I can't find any info about this invite delegate.
Actual Question:
What is an inviteDelegate? Do I really need to implement such (if yes, then how?)? (I don't think so as the docs state that the match only starts after the invites are accepted).
How can I resolve this issue?
here is a working example for you. open on two machines, make sure both are authenticated, press "findMatch()" on both machines (and wait for confirmation), then ping baby ping
i believe the "no inviteDelegate set yet" error doesn't mean the match making necessary failed, and can safely be ignored, as mentioned here
you'll want to implement more of the GKMatchDelegate protocol, but this is a skeleton for demonstration purposes
import SwiftUI
import GameKit
import SpriteKit
class MyGameScene: SKScene, GKMatchDelegate {
override func didMove(to view: SKView) {
self.backgroundColor = .yellow
}
//GKMatchDelegate protocol
func match(_ match: GKMatch, didReceive data: Data, forRecipient recipient: GKPlayer, fromRemotePlayer player: GKPlayer) {
print("\(Self.self) \(#function) -- ping received")
}
}
struct Matchmaker: View {
#State var isAuthenticated:Bool = false
#State var scene = MyGameScene()
#State var match:GKMatch? = nil
var body: some View {
ZStack {
Color.clear
SpriteView(scene: scene)
VStack(alignment: .leading, spacing: 20) {
Text("1) authenticate() \(Image(systemName: isAuthenticated ? "checkmark.icloud" : "xmark.icloud"))")
Button { findMatch() } label: {
Text("2) findMatch() \(Image(systemName: (match != nil) ? "person.fill.checkmark" : "person.fill.xmark"))")
}
Button { ping() } label: {
Text("3) ping()")
}
}
}
.onAppear() {
authenticate()
}
}
func authenticate() {
GKLocalPlayer.local.authenticateHandler = { viewController, error in
if let error = error { print(error) }
isAuthenticated = (error == nil)
}
}
func findMatch() {
guard isAuthenticated else { return }
let request = GKMatchRequest()
request.minPlayers = 2
request.maxPlayers = 2
request.playerAttributes = 0xFFFFFFFF //mask for "i'll match with anyone"
GKMatchmaker.shared().findMatch (for: request) { match, error in
if let error = error { print(error) }
self.match = match
self.match?.delegate = scene
}
}
func ping() {
let players = match?.players ?? [];
let data = Data()
do {
try match?.send(data, to: players, dataMode: .reliable)
} catch {
print("Sending failed")
}
}
}

CLSLogv logs are not coming in Crashlytics

Its an Ionic app with some code written in native. Its uses cordova-plugin-firebase that for logging Crashlytics.
In the native part for iOS as well, we are trying to use Crashlytics to enable logging. However no matter what I try logs sent using CLSLogv aren't visible in dashboard.
Here is my code.
#objc(ImageUpload) class ImageUpload : CDVPlugin {
var backgroundTask: UIBackgroundTaskIdentifier = UIBackgroundTaskInvalid
//https://docs.fabric.io/apple/crashlytics/enhanced-reports.html#custom-logging-in-swift
private func sendErrorToCrashlytics(error: String) {
NSLog("Error in send error function is \(error)")
CLSLogv("%#", getVaList([error]))
}
#objc(imageUpload:)
func imageUpload(command: CDVInvokedUrlCommand) {
registerBackgroundTask()
func execute() {
let db = SQLiteDatabase()
var recToUpLoad: PayloadModel? = nil
while(toCheck) {
do {
let record = try db.readValues() // THIS METHOD THROWS EXCEPTION
} catch Exceptions.SQLiteError(let error) {
self.sendErrorToCrashlytics(error: error) // IT COMES HERE AFTER EXCEPTION
}
}
}
DispatchQueue(label: "imageUploadPlugin",qos: .background).async
{
execute()
}
}
}
However CLSLogv is not visible at all in Crashlytics. However when I do Crashlytics.sharedInstance().throwException()
, I can see it in the dashboard.
Exceptions is enum
enum Exceptions: Error {
case SQLiteError(message: String)
case JSONError(message: String)
}
Hoping it may help someone. Somehow I couldn't get CLSLogv to work. I ended up creating an NSError object and log that in Crashlytics in catch block.
catch Exceptions.SQLiteError(let error) {
let userInfo = [NSLocalizedDescriptionKey: error.message, "query": error.query]
let errorObj = NSError(domain: "sqlite", code: 400, userInfo: userInfo)
Crashlytics.sharedInstance().recordError(errorObj)
}

Should perform segue on request

i'm starting with Swift3 and i'm having a recurrent problem due to the asynchronism. But until now, i always find a solution with callback.
I have a textField and a button, when i click on the button, i check on the API if there is a existing user named as in the textField.
Using shouldPerformSegue, i return the value if the users exist or no.
I have a separated class for handling calls on the Api
class Api {
static let urlApi = "https://XXXXXXXXXXXXX"
private let CUSTOMER_ID = "XXXXXXXX"
private let CUSTOMER_SECRET = "XXXXXXXX"
private var access_token : String? = nil
private var userInfo : User?
init() {
self.connect()
}
func connect() {
// Do the connect...
}
func get(user: String, callback: #escaping (_ status: Bool) -> Void) {
Alamofire.request(URL(string: "\(Api.urlApi)/v2/users/\(user)")!,
method: .get,
parameters: nil,
encoding: URLEncoding.default,
headers: ["Authorization": "Bearer \(self.access_token!)"])
.responseJSON(completionHandler: { response in
if response.result.isFailure {
print("ERROR: GET USER", response)
callback(false)
} else {
print("SUCCESS Getting user ", user)
callback(true)
}
})
}
}
And in my shouldPerformSegue
override func shouldPerformSegue(withIdentifier identifier: String, sender: Any?) -> Bool {
var userExist : Bool? = nil
let dispatchQueue = DispatchQueue(label: "getUser")
let semaphore = DispatchSemaphore(value: 1)
dispatchQueue.sync {
self.api?.get(user: self.userTextField.text!, callback: { status in
userExist = status
print("1 USEREXIST", userExist)
})
}
semaphore.wait()
print("2 USEREXIST", userExist)
return userExist ?? false // always false because userExist == nil
}
Sorry for the function mess, i don't really find the right way to do my DispachQueue and my Semaphore .. All googling answer look that i need those
The proper way to handle this scenario would be to make the request when the user taps on the button. If there is an error, you would present some error that says the username already exists. Then they would try again.
If the request is successful and that username has not been taken, then you would call performSegueWithIdentifier. The link below shows a good demonstration of the steps to take after this. Your current implementation isn't necessary.
https://stackoverflow.com/a/37823730/653839

NSNotificationCenter Notification Not Being Received When Posted in a Closure

What I am trying to accomplish is posting a notification through NSNotificationCenter's default center. This is being done within a closure block after making a network call using Alamofire. The problem I am having is that a class that should be responding to a posted notification isn't receiving such notification.
My ViewController simply creates a First object that get's things moving:
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let first = First()
}
}
My First class creates and instance of a Second class and adds itself as an observer to my NSNotificationCenter. This is the class that can't seem to get the notification when the notification is posted.
class First : NSObject {
let second = Second()
override init(){
super.init()
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(First.gotDownloadNotification(_:)), name: "test", object: nil)
second.sendRequest()
}
// NOT REACHING THIS CODE
func gotDownloadNotification(notification: NSNotification){
print("Successfully received download notification from Second")
}
}
My Second class is what makes the network call through my NetworkService class and posts a notification in a closure once the request is successful and complete.
class Second : NSObject {
func sendRequest(){
let networkService = NetworkService()
networkService.downloadFile() { statusCode in
if let statusCode = statusCode {
print("Successfully got a status code")
// Post notification
NSNotificationCenter.defaultCenter().postNotificationName("test", object: nil)
}
}
}
}
Finally, my NetworkService class is what makes a network call using Alamofire and returns the status code from the response through a closure.
class NetworkService : NSObject {
func downloadFile(completionHandler: (Int?) -> ()){
Alamofire.download(.GET, "https://www.google.com") { temporaryURL, response in
let fileManager = NSFileManager.defaultManager()
let directoryURL = fileManager.URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)[0]
let pathComponent = response.suggestedFilename
return directoryURL.URLByAppendingPathComponent(pathComponent!)
}
.response { (request, response, _, error) in
if let error = error {
print("File download failed with error: \(error.localizedDescription)")
completionHandler(nil)
} else if let response = response{
print("File downloaded successfully")
// Pass status code through completionHandler to Second
completionHandler(response.statusCode)
}
}
}
}
The output after execution is:
File downloaded successfully
Successfully got a status code
From this output I know the download was successful and Second got the status code from the closure and posted a notification right after.
I believe that I have tried resolving most other suggestions on Stack Overflow related to not receiving notifications such as objects not being instantiated before notification is posted or syntax of either adding an observer or posting a notification.
Does anyone have any idea why the posted notification is not being received in the First class?
Since there is a direct relationship between First and Second the protocol/delegate pattern is the better way to notify. Even better with this pattern and you don't have to take care of unregistering the observer. NSNotificationCenter is supposed to be used only if there is no relationship between sender and receiver.
And basically the thread doesn't matter either.
protocol SecondDelegate {
func gotDownloadNotification()
}
class Second : NSObject {
var delegate : SecondDelegate?
init(delegate : SecondDelegate?) {
self.delegate = delegate
}
func sendRequest(){
let networkService = NetworkService()
networkService.downloadFile() { statusCode in
if let statusCode = statusCode {
print("Successfully got a status code")
// Post notification
self.delegate?.gotDownloadNotification()
}
}
}
}
class First : NSObject, SecondDelegate {
let second : Second
override init(){
super.init()
second = Second(delegate:self)
second.sendRequest()
}
func gotDownloadNotification(){
print("Successfully received download notification from Second")
}
}

Debugging advice for WatchOS2

I've been going through the examples in WatchOS 2 By Tutorial book by the team over at RayWenderlich, specifically chapter 18. They all work fine. In my own App, I am trying to send a button press from the watch to fire a button on the iPhone App. Here's the relevant code in Swift from the Watch and the Phone:
Watch:
//
// InterfaceController.swift
// Wasted Time Extension
//
// Created by Michael Rowe on 7/21/15.
// Copyright © 2010-2015 Michael Rowe. All rights reserved.
//
import WatchKit
import WatchConnectivity
import Foundation
class InterfaceController: WKInterfaceController,WCSessionDelegate {
#IBOutlet var wasteLabel: WKInterfaceLabel!
#IBOutlet var costLabel: WKInterfaceLabel!
#IBOutlet var counter: WKInterfaceLabel!
#IBOutlet var statusButton: WKInterfaceButton!
// our watchconnective session
var session : WCSession?
override func awakeWithContext(context: AnyObject?) {
super.awakeWithContext(context)
}
override func willActivate() {
// This method is called when watch view controller is about to be visible to user
super.willActivate()
if(WCSession.isSupported()){
session = WCSession.defaultSession()
session!.delegate = self
session!.activateSession()
}
}
override func didDeactivate() {
// This method is called when watch view controller is no longer visible
super.didDeactivate()
}
func session(session: WCSession, didReceiveMessage message: [String: AnyObject], replyHandler: [String: AnyObject] -> Void) {
print("Did receive message Watch \(message)")
}
#IBAction func addButtonPressed() {
// Pull values from the Phone for current meeting cost, waste costs, and people in meeting
let prefs:NSUserDefaults = NSUserDefaults(suiteName: "a.b.c")!
var counterd = prefs.doubleForKey("keyPeopleInMeeting")
counterd++
counter.setText(String(format:"%9.0f", counterd))
// Sending data to iPhone via Interactive Messaging
if WCSession.isSupported(){
// we have a watch supporting iPhone
let session = WCSession.defaultSession()
// we can reach the watch
if session.reachable {
let message = ["add": "1"]
print("Message \(message)")
session.transferUserInfo(message)
print("Send Message Add - People \(counterd)")
}
}
if WCSession.isSupported() {
let session = WCSession.defaultSession()
if session.reachable {
let message = ["add":"1"]
session.sendMessage(message, replyHandler: { ( reply: [String: AnyObject]) -> Void in
print("Reply: \(reply)")
}, errorHandler: { (error: NSError) -> Void in
print("ERROR Watch: \(error.localizedDescription)")
})
} else { // reachable
self.showReachabilityError()
}
}
print("Watch Add Button Pressed \(counterd)")
}
#IBAction func minusButtonPressed() {
// Pull values from the Phone for current meeting cost, waste costs, and people in meeting
let prefs:NSUserDefaults = NSUserDefaults(suiteName: "a.b.c")!
var counterd = prefs.doubleForKey("keyPeopleInMeeting")
counterd--
if (counterd <= 1) {
counterd = 1
}
counter.setText(String(format:"%9.0f", counterd))
if WCSession.isSupported() {
let session = WCSession.defaultSession()
if session.reachable {
let message = ["minus":"1"]
session.sendMessage(message, replyHandler: { ( reply: [String: AnyObject]) -> Void in
print("Reply: \(reply)")
}, errorHandler: { (error: NSError) -> Void in
print("ERROR Watch: \(error.localizedDescription)")
})
} else { // reachable
self.showReachabilityError()
}
}
print("Watch Minus Button Pressed \(counterd)")
}
func statusButtonPressed() {
// Pull values from the Phone for current meeting cost, waste costs, and people in meeting
let prefs:NSUserDefaults = NSUserDefaults(suiteName: "a.b.c")!
let status = statusButton.description
if WCSession.isSupported() {
let session = WCSession.defaultSession()
if session.reachable {
let message = ["status":status]
session.sendMessage(message, replyHandler: { ( reply: [String: AnyObject]) -> Void in
print("Reply: \(reply)")
}, errorHandler: { (error: NSError) -> Void in
print("ERROR Watch: \(error.localizedDescription)")
})
} else { // reachable
self.showReachabilityError()
}
}
print("Watch Status Button Pressed - Status \(statusButton)")
}
func session(session: WCSession, didReceiveApplicationContext applicationContext: [String : AnyObject]){
let prefs:NSUserDefaults = NSUserDefaults(suiteName: "a.b.c")!
if let waste = applicationContext["waste"] as? Float {
print("Watch Receive - Waste \(waste)")
}
if let cost = applicationContext["cost"] as? Float {
print("Watch Receive - Cost \(cost)")
}
if let counternum = applicationContext["counter"] as? Float {
print("Watch Receive - Counter \(counternum)")
}
if let status = applicationContext["status"] as? String {
print("Watch Receive - Status \(status)")
statusButton.setTitle(status)
}
}
private func showReachabilityError() {
let tryAgain = WKAlertAction(title: "Try Again", style: .Default, handler: { () -> Void in })
let cancel = WKAlertAction(title: "Cancel", style: .Cancel, handler: { () -> Void in })
self.presentAlertControllerWithTitle("Your iPhone is not reachable.", message: "You cannot adjust the status or number of attendees Watch is not currently connected to your iPhone. Please ensure your iPhone is on and within range of your Watch.", preferredStyle: WKAlertControllerStyle.Alert, actions:[tryAgain, cancel])
}
func session(session: WCSession, didFinishUserInfoTransfer userInfoTransfer: WCSessionUserInfoTransfer, error: NSError?) {
print("Transfer User Info Error watch: \(error)")
}
}
And the receiving code on the
iPhone:CODE:
func session(session: WCSession,
didReceiveMessage message: [String : AnyObject],
replyHandler: ([String : AnyObject]) -> Void) {
if let counterd = message["add"] as? Float {
let reply = ["add":counterd]
print("iPhone Receive Add \(counterd)")
addButtonPressed(self)
replyHandler(reply)
}
if let counterd = message["minus"] as? Float {
let reply = ["minus":counterd]
print("iPhone Receive minus \(counterd)")
removeButtonPressed(self)
replyHandler(reply)
}
if let status = message["status"] as? String {
if status == "Start" {
let reply = ["status":"Quorum"]
meetingStartedButtonPressed(self)
replyHandler(reply)
}
if status == "Quorum" {
let reply = ["status": "Finish"]
quorumButtonPressed(self)
replyHandler(reply)
}
if status == "Finish" {
let reply = ["status": "Reset"]
meetingEndedButtonPressed(self)
replyHandler(reply)
}
if status == "Reset" {
let reply = ["status": "Start"]
resetButtonPressed(self)
replyHandler(reply)
}
print("iPhone Received Status Button \(status)")
}
}
I get the messages firing fine on the Watch and see them in the debug log... But they do not seem to fire on the Phone. The phone is successfully sending its messages to the watch.
I have tested this code both in the simulator and on my own watch and iPhone. Note that the messages from the iPhone to the Watch are done using the via updateApplicationContext vs. the send message I am trying to use to send messages from the watch to the iPhone. Here's a sample of the iPhone code for sending context:
if WCSession.isSupported() {
if session.watchAppInstalled {
let UserInfo = ["waste":Float((wastedAmount.text! as NSString).floatValue), "cost":Float((totalAmount.text! as NSString).floatValue), "counter":Float((peopleInMeeting.text! as NSString).floatValue), "status":"Start"]
do {
try session.updateApplicationContext(UserInfo as! [String : AnyObject])
} catch {
print("Updating the context failed: ")
}
}
}
More information is needed regarding specifically what you're actually seeing on the Watch, when you say:
I get the messages firing fine on the Watch and see them in the debug log... But they do not seem to fire on the Phone. The phone is successfully sending its messages to the watch.
However, one common occurrence is that the iPhone code is actually working correctly, and the only thing you are not seeing is the debug statements printed to the console. This seems likely to be the case since you say you are seeing the expected Watch messages, presumably including those from print("Reply: \(reply)"). This indicates the message is being handled by the iPhone.
When that's the case, it's often simply that you are expecting to see debug console messages from both the Watch and iOS simulator processes at the same time, but in fact you're only connected to one or the other. There are (at least) two things you can do here:
Run the WatchKit app from Xcode, but then change to attach to the iPhone process instead. In Xcode, go Debug > Attach to Process... and select the iPhone app under "Likely Targets".
Start by running the iPhone app, which will mean you are already attached to that process. In the Apple Watch simulator, run the Watch app. You'll then be able to debug the iPhone side of the communication.
To debug in Watch-OS while running iPhone app and vice versa in Xcode-8.1. Required running Process need to be attached .
Visually:-