Search code examples
iosios-simulatorapple-watch

transferUserInfo between AppleWatch simulator and iPhone simulator stop working from Xcode 11


I have a dependent watch app that use to work fine in simulation for Xcode 10.2.1, but when I update to Xcode 11.x.x, it seem like the transfer data does not work anymore.

In Xcode 10.x.x the target for WatchKit App always trigger both iOS and Watch App. But since Xcode 11, it only triggers the Apple Watch simulator. I already double-check to use corrected pair simulators (corrected paired iPhone + Apple Watch simulators). Already checked all the WCSesssionActivationState to be activated, WCSession.default.isReachable to be true, session didFinish userInfoTransfer get called for the same target, but in the other target session didReceiveUserInfo does not get called at all.

Is there any configuration I need to do in addition? Anyone having the same issue? Any help is greatly appreciated!

This is the code in main App ViewController

import UIKit
import WatchConnectivity

class ViewController: UIViewController, WCSessionDelegate {

    @IBOutlet weak var textFieldMessage : UITextField!
    @IBOutlet weak var buttonSend : UIButton!
    var wcSession : WCSession!

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

        wcSession = WCSession.default
        wcSession.delegate = self
        wcSession.activate()
    }

    //MARK: - Button Actions

    @IBAction func clickSendMessage(_ sender : UIButton) {

        let message = ["message" : textFieldMessage.text!]
        do {
            try wcSession.updateApplicationContext(message)

            if wcSession.activationState == .activated {
                if wcSession.isReachable {
                    let data = ["text": "User info from the iphone"]
                    wcSession.transferUserInfo(data)
                }
            }
        } catch {
            print("Something went wrong")
        }
    }

    // MARK: - WCSessionDelegate

    func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) {
        NSLog("%@", "activationDidCompleteWith activationState:\(activationState) error:\(String(describing: error))")
    }

    func sessionDidBecomeInactive(_ session: WCSession) {
        print("%@", "sessionDidBecomeInactive: \(session)")
    }

    func sessionDidDeactivate(_ session: WCSession) {
        print("%@", "sessionDidDeactivate: \(session)")
    }

    func sessionWatchStateDidChange(_ session: WCSession) {
        print("%@", "sessionWatchStateDidChange: \(session)")
    }

    func session(_ session: WCSession, didFinish userInfoTransfer: WCSessionUserInfoTransfer, error: Error?) {
        DispatchQueue.main.async {
            if session.isReachable {
                print("Transfered data")
            }
        }
    }
}

And InterfaceController in WatchKit Extension

import WatchKit
import Foundation
import WatchConnectivity

class InterfaceController: WKInterfaceController, WCSessionDelegate {

    var session : WCSession?
    @IBOutlet weak var sessionLabel : WKInterfaceLabel!

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

        session = WCSession.default
        session?.delegate = self
        session?.activate()
    }

    // MARK: - WCSessionDelegate

    func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) {
        NSLog("%@", "activationDidCompleteWith activationState:\(activationState) error:\(String(describing: error))")
    }

    func session(_ session: WCSession, didReceiveApplicationContext applicationContext: [String : Any]) {
        NSLog("didReceiveApplicationContext : %@", applicationContext)
        sessionLabel.setText(applicationContext["message"] as? String)
    }

    func session(_ session: WCSession, didReceiveUserInfo userInfo: [String : Any] = [:]) {
        print("9. InterfaceController: ", "didReceiveUserInfo")
        DispatchQueue.main.async {
            if let text = userInfo["text"] as? String {
                print(text)
            }
        }
    }
}

It is weird that the wcSession.updateApplicationContext(message) works fine but the wcSession.transferUserInfo(data) does not send data to apple watch, even the code went inside print("Transfered data") for ViewController


Solution

  • For those who face the same issue. I am still not able to send data with wcSession.transferUserInfo but it works with another api wcSession.sendMessage. Seem like migrating logic to use sendMessage is the workaround for now.

    Reference: https://forums.developer.apple.com/thread/127460