11

How can I transfer an UIImage over WatchConnecitivity from the iPhone to the Apple Watch with no user interaction on the phone, and only loads because the watch calls for it programmatically. I need this because the image processing to create the UIImage uses logic unavailable in the Watchkit API, so it must be created from the phone. I have seem some examples of Watch Connectivity using:

func startSession() {
    session?.delegate = self
    session?.activateSession()
}

However, I am new to watch kit and am confused on how to use this session manager, particularly to go from the watch to the device instead of the other way around like I see in apple documentation. Can someone please provide an example of how to do this on both the watch and the phone to call for a UIImage on the phone from the watch?

modesitt
  • 7,052
  • 2
  • 34
  • 64

3 Answers3

14

To transfer files between your iPhone and your Apple Watch you should use Watch Connectivity, using WCSession to handle the communication properly. You can send an UIImage as NSData using the didReceiveMessageData delegate method of the WCSessionDelegate.

The first thing you should know is convert your UIImage to NSData and viceversa. You can use for this the following code:

If PNG images

let image = UIImage(named: "nameOfYourImage.jpg")
let data = UIImagePNGRepresentation(image)

If JPG images

let image = UIImage(named: "nameOfYourImage.jpg")
let data = UIImageJPEGRepresentation(image, 1.0)

Then you can use the WCSession to send the message like in the following way:

ViewController.swift

class ViewController: UIViewController, WCSessionDelegate {

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

       if WCSession.isSupported() {
           WCSession.defaultSession().delegate = self
           WCSession.defaultSession().activateSession()
       }

       let image = UIImage(named: "index.jpg")!

       let data = UIImageJPEGRepresentation(image, 1.0)

       WCSession.defaultSession().sendMessageData(data!, replyHandler: { (data) -> Void in
           // handle the response from the device

        }) { (error) -> Void in
              print("error: \(error.localizedDescription)")

       }
   }

   override func didReceiveMemoryWarning() {
       super.didReceiveMemoryWarning()
       // Dispose of any resources that can be recreated.
   }
}

InterfaceController.swift

import WatchKit
import Foundation
import WatchConnectivity


class InterfaceController: WKInterfaceController, WCSessionDelegate {

   override func awakeWithContext(context: AnyObject?) {
       super.awakeWithContext(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() {
           WCSession.defaultSession().delegate = self
           WCSession.defaultSession().activateSession()
       } 
   }

   override func didDeactivate() {
       // This method is called when watch view controller is no longer visible
       super.didDeactivate()
   }

   func session(session: WCSession, didReceiveMessageData messageData: NSData, replyHandler: (NSData) -> Void) {

       guard let image = UIImage(data: messageData) else {
           return
       }

       // throw to the main queue to upate properly
       dispatch_async(dispatch_get_main_queue()) { [weak self] in
           // update your UI here
       }

      replyHandler(messageData)
   }
}

In the above code when you open the ViewController it sends the UIImage, the above example is only for learning purposes, you have to handle it in a more proper way regarding the complexity of your project.

I hope this help you.

Victor Sigler
  • 23,243
  • 14
  • 88
  • 105
  • 1
    `sendMessageData` from the phone to the watch will only work if the watch app is active on the watch. If the watch app is not running, the data will be lost. It would be more safe to use `tranferUserInfo`, which will queue the data and be read by the watch app the next time it is made active. If you only are interested in the latest image you have sent to the watch, use 'updateApplicationContext'. Also, these two means of communication occur in the background, which may be desirable if you are transmitting a large amount of data. – Drewf Oct 14 '15 at 02:53
  • Yes @Drewf you're right `transferUserInfo` is more properly in case when the Apple Watch is not reachable because the package is delivered in background but has the inconvenient of the replacement in the background queue when it's sent several times. Nevertheless I'll update the answer with more info for each case. – Victor Sigler Oct 14 '15 at 13:38
  • 2
    Worth experimenting with compressionQuality < 1.0 for JPEG if you can get away with it to reduce the amount of traffic goingg over the wire. – Mike Pollard Oct 19 '15 at 13:12
0

you have to transfer your image as NSData and then decode it on watch's side. You can have a look at my blog post where I covered similar case. http://eluss.github.io/AppleWatch_iPhone_data_transfer/

This is not the way of doing it with session as I was not aware of it back then, but maybe it will help you get the whole logic.

Eluss
  • 512
  • 3
  • 5
0

In InterfaceController, if you use WCSessionDelegate, remember to extend method activationDidCompleteWith:

func session(_ session: WCSession, activationDidCompleteWith  
  activationState: WCSessionActivationState, error: Error?) {

  }
Alessandro Mattiuzzi
  • 2,309
  • 2
  • 18
  • 24