WCSession transferFile and transferUserInfo problem

The two background delivery methods (transferFile, transferUserInfo) usually stop working on watchOS 2.2 and only a watch restart helps to get them work again. After restarting, they work for a while the way they always should, then stop working again... Other methods (sendMessage, sendMessageData) are ok.

There was not any problems like this on watchOS 2.1.


Has anyone experienced this? Any workoaround?

Replies

Hi. Is this on the non-beta watchOS 2.2 and iOS 9.3? There are new required WCSessionDelegate methods that must be implemented when building against watchOS 2.2 and iOS 9.3. Please see under the heading "Supporting Communication with Multiple Apple Watches" in the WCSession reference: https://developer.apple.com/library/ios/documentation/WatchConnectivity/Reference/WCSession_class/index.html#//apple_ref/occ/cl/WCSession


If you notice undocumented differences between how WatchConnectivity behaves on watchOS 2.1 (& iOS 9.2.1) and on watchOS 2.2 (& iOS 9.3), we would appreciate it if you filed a bug report.


Since you mentioned that you needed to send data in the background, would updateApplicationContext(_:) work for you?

I am also experiencing this issue. sendMessage works just fine for me, but calling transferUserInfo never gets the data to the Apple Watch. Note that these issues are only on a physical device. The simulator seems to work just fine.

We are experiencing a similar issue: sending userInfo from watch to phone does not seem to invoke the delegate callback... sometimes.

Resetting the simulator fixes the issue (as probably restarting the watch).


We implemented the new WCSessionDelegate in ios9.3 watchos2.2 as suggested bu musashi but this does not help with the issue.

prior to ios9.3 and watchos2.2 our callback on transferUserInfo was working fine.


SendMessage and sending context are working ok, the only issue we are having is using the userInfo transfering API.

Implementation of new methods fixed file transfer for me

Also reset watch fix it for some time

- (void)sessionDidBecomeInactive:(WCSession *)session{}

- (void)session:(WCSession *)session activationDidCompleteWithState:(WCSessionActivationState)activationState error:(nullable NSError *)error{}

- (void)sessionDidDeactivate:(WCSession *)session {

[[WCSession defaultSession] activateSession];

}

You mention that there are new required API's, but the docs state "You must implement this method to support asynchronous activation and quick watch switching", but nothing about a requirement to implement these for transferUserInfo to continue working. Can you post what new code is required for us to implement now for transferUserInfo to work in the background?

Hi vitalii,


Looks like those are the new iOS methods. Did you just need to add just those, or did you need to add any to the watchOS side too?

Experiencing the exact same issue on watchOS 2.2 and iOS 9.3 when attempting to send data from the phone to watch using transferUserInfo:.


The WCSessionDelegate on the phone receives a callback to session:didFinishUserInfoTransfer:error, without an error, so it seems that the transfer completed successfully, but session:didRecieveUserInfo: is never invoked on the watch.


Both sendMessage: and updateApplicationContext: seem to work as they did on watchOS 2.1.


Replacing transferUserInfo: with updateApplicationContext: is not an option for us, as our app uses updateApplicationContext: to send a different payload.

At watchOS side add just - (void)session:(WCSession *)session activationDidCompleteWithState:(WCSessionActivationState)activationState error:(nullable NSError *)error{}

sessionDidBecomeInactive and sessionDidDeactivate available only on iOS

I still seem to be experiencing the same issues after implementing the new WCSessionDelegate calls on both iOS and watchOS.

I have implemented the new session delegate methods and have verified that everything is working properly on the iOS side. activationState is .Activated and outstandingUserInfoTransfers.count is 0.


The behavior on the watch side is inconsistent. Occasionally the watch appears to stop receiving any user info at all, and has to be reset. Resetting it completely resolves the issue, and transferred user info is once again promply received. Everything works as expected.


As for triggering the issue, I've been able to reproduce it by making multiple transfers in a short period of time (e.g., 6 or 8 userInfoTransfer objects all within a second or two). The data does get to the watch, but the watch stops delivering it promptly, and starts to stagger delivery. It then only delivers the first queued object once another object has been received and added to the queue.


I was able to interactively step through this issue where four WCSessionUserInfoTransfer objects were received by watchOS, but didn't get received by the extension. Sending a fifth userInfo transfer would cause the first one in the queue to get delivered to the extension. Sending a sixth one, would cause the second one to then get delivered to the extension, and so on.


One fix is to reset the watch or simulator, to clear up the received queue issue.


I'll work on creating a sample project to submit to Apple. If anyone else files an issue in the meantime, please provide your radar. Thanks!

I also am still experiencing this issue after implementing those methods.

Unfortunately implementing the new delegate methods does not help. This problem has came up first in the watchOS 2.2 beta 3 and it is still has been in the current public release.

It turns out that transferUserInfo wasn't actually the cause of my problem, sendMessage's error handler not getting called was. I had been making my sendMessage calls as follows:


if self.session != nil && self.session.paired && self.session.watchAppInstalled {
     self.session.sendMessage(message, replyHandler: nil) { (error) -> Void in 
          self.session.transferUserInfo(message)
     }
}


But, if sendMessage was called while the Apple Watch was not reachable, the error handler was never called. This caused transferUserInfo to never be called, and seemed to clog up future calls to transferUserInfo. This is different behavior than in iOS 9.2 and earlier, where the error handler would always be called if sendMessage failed. To resolve this issue, I implemented the new WCSessionDelegate methods mentioned above and changed how I was transfering data to the Apple Watch like so:


if self.session != nil && self.session.paired && self.session.watchAppInstalled && self.session.activationState == .Activated {
    if self.session.reachable == true {
        self.session.sendMessage(message, replyHandler: nil) { (error) -> Void in 
            self.session.transferUserInfo(message)
        }
    } else {
        self.session.transferUserInfo(message)
    }
}


This is described in more detail here:


http://stackoverflow.com/questions/36286531/wcsessions-transferuserinfo-no-longer-reliably-working-in-watchos-2-2-with-ios/36318723?noredirect=1#comment60309618_36318723

I also discovered this issue yesterday and was a little shocked that Apple did major API changes in a point release, e.g. activateSession() does now execute asynchronously. I've fixed my code and implemented the new delegate methods, but transferUserInfo: still refuses to work reliably. After an hour of testing I had around 200 outstanding userInfo transfers on my iOS device which never came through.


This issue does also affect existing apps. I've tested an old TestFlight build targeting iOS 9.2 / watchOS 2.1, which worked fine before the update. Unfortunately my watch app relies heavily on userInfo transfers, so it's pretty unusable right now. I'm hoping for a quick fix or at least a workaround.

After implementing the new WCSessionDelegate callbacks, everything works fine as long as I never attempt to send data using transferUserInfo when the session is not in WCSessionActivationStateActivated.


Calling transferUserInfo even once when the WCSession is not active seems to break all subsequent requests to transferUserInfo, and requires a Watch restart to fix the issue. Because active is not available in watchOS 2.1, this seems to break existing 2.1 apps that rely on transferUserInfo.