Instantly share code, notes, and snippets.

Embed
What would you like to do?
WatchConnectivity Singleton Demo
//
// WatchSessionManager.swift
// WatchConnectivityDemo
//
// Created by Natasha Murashev on 9/3/15.
// Copyright © 2015 NatashaTheRobot. All rights reserved.
//
import WatchConnectivity
class WatchSessionManager: NSObject, WCSessionDelegate {
static let sharedManager = WatchSessionManager()
private override init() {
super.init()
}
private let session: WCSession? = WCSession.isSupported() ? WCSession.defaultSession() : nil
private var validSession: WCSession? {
// paired - the user has to have their device paired to the watch
// watchAppInstalled - the user must have your watch app installed
// Note: if the device is paired, but your watch app is not installed
// consider prompting the user to install it for a better experience
if let session = session where session.paired && session.watchAppInstalled {
return session
}
return nil
}
func startSession() {
session?.delegate = self
session?.activateSession()
}
}
// MARK: Application Context
// use when your app needs only the latest information
// if the data was not sent, it will be replaced
extension WatchSessionManager {
// Sender
func updateApplicationContext(applicationContext: [String : AnyObject]) throws {
if let session = validSession {
do {
try session.updateApplicationContext(applicationContext)
} catch let error {
throw error
}
}
}
// Receiver
func session(session: WCSession, didReceiveApplicationContext applicationContext: [String : AnyObject]) {
// handle receiving application context
dispatch_async(dispatch_get_main_queue()) {
// make sure to put on the main queue to update UI!
}
}
}
// MARK: User Info
// use when your app needs all the data
// FIFO queue
extension WatchSessionManager {
// Sender
func transferUserInfo(userInfo: [String : AnyObject]) -> WCSessionUserInfoTransfer? {
return validSession?.transferUserInfo(userInfo)
}
func session(session: WCSession, didFinishUserInfoTransfer userInfoTransfer: WCSessionUserInfoTransfer, error: NSError?) {
// implement this on the sender if you need to confirm that
// the user info did in fact transfer
}
// Receiver
func session(session: WCSession, didReceiveUserInfo userInfo: [String : AnyObject]) {
// handle receiving user info
dispatch_async(dispatch_get_main_queue()) {
// make sure to put on the main queue to update UI!
}
}
}
// MARK: Transfer File
extension WatchSessionManager {
// Sender
func transferFile(file: NSURL, metadata: [String : AnyObject]) -> WCSessionFileTransfer? {
return validSession?.transferFile(file, metadata: metadata)
}
func session(session: WCSession, didFinishFileTransfer fileTransfer: WCSessionFileTransfer, error: NSError?) {
// handle filed transfer completion
}
// Receiver
func session(session: WCSession, didReceiveFile file: WCSessionFile) {
// handle receiving file
dispatch_async(dispatch_get_main_queue()) {
// make sure to put on the main queue to update UI!
}
}
}
// MARK: Interactive Messaging
extension WatchSessionManager {
// Live messaging! App has to be reachable
private var validReachableSession: WCSession? {
if let session = validSession where session.reachable {
return session
}
return nil
}
// Sender
func sendMessage(message: [String : AnyObject],
replyHandler: (([String : AnyObject]) -> Void)? = nil,
errorHandler: ((NSError) -> Void)? = nil)
{
validReachableSession?.sendMessage(message, replyHandler: replyHandler, errorHandler: errorHandler)
}
func sendMessageData(data: NSData,
replyHandler: ((NSData) -> Void)? = nil,
errorHandler: ((NSError) -> Void)? = nil)
{
validReachableSession?.sendMessageData(data, replyHandler: replyHandler, errorHandler: errorHandler)
}
// Receiver
func session(session: WCSession, didReceiveMessage message: [String : AnyObject], replyHandler: ([String : AnyObject]) -> Void) {
// handle receiving message
dispatch_async(dispatch_get_main_queue()) {
// make sure to put on the main queue to update UI!
}
}
func session(session: WCSession, didReceiveMessageData messageData: NSData, replyHandler: (NSData) -> Void) {
// handle receiving message data
dispatch_async(dispatch_get_main_queue()) {
// make sure to put on the main queue to update UI!
}
}
}
@P-A-R-U-S

This comment has been minimized.

P-A-R-U-S commented Apr 1, 2016

If you replace line 28-31 with this - it will be easy to use singleton both for iOS and WatchOS.

`#if os(iOS)

    if let s = session where s.watchAppInstalled && s.paired {
        return s
    }

    return nil

else

    return session

endif`

@adamsmaka

This comment has been minimized.

adamsmaka commented Oct 2, 2016

Swift 3.0

//
//  WatchSessionManager.swift
//  WatchConnectivityDemo
//
//  Created by Natasha Murashev on 9/3/15.
//  Copyright © 2015 NatashaTheRobot. All rights reserved.
//

import WatchConnectivity

class WatchSessionManager: NSObject, WCSessionDelegate {

    static let sharedManager = WatchSessionManager()
    private override init() {
        super.init()
    }

    private let session: WCSession? = WCSession.isSupported() ? WCSession.default() : nil

    @available(iOS 9.3, *)
    func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) {
    }

    func sessionDidBecomeInactive(_ session: WCSession) {
    }

    func sessionDidDeactivate(_ session: WCSession) {
    }

    var validSession: WCSession? {

        // paired - the user has to have their device paired to the watch
        // watchAppInstalled - the user must have your watch app installed

        // Note: if the device is paired, but your watch app is not installed
        // consider prompting the user to install it for a better experience

        #if os(iOS)
        if let session = session, session.isPaired && session.isWatchAppInstalled {
            return session
        }
        #elseif os(watchOS)
        return session
        #endif
        return nil
    }

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

// MARK: Application Context
// use when your app needs only the latest information
// if the data was not sent, it will be replaced
extension WatchSessionManager {

    // Sender
    func updateApplicationContext(applicationContext: [String : AnyObject]) throws {
        if let session = validSession {
            do {
                try session.updateApplicationContext(applicationContext)
            } catch let error {
                throw error
            }
        }
    }

    // Receiver
    func session(_ session: WCSession, didReceiveApplicationContext applicationContext: [String : Any]) {
        // handle receiving application context

        DispatchQueue.main.async {
            // make sure to put on the main queue to update UI!
        }
    }
}

// MARK: User Info
// use when your app needs all the data
// FIFO queue
extension WatchSessionManager {

    // Sender
    func transferUserInfo(userInfo: [String : AnyObject]) -> WCSessionUserInfoTransfer? {
        return validSession?.transferUserInfo(userInfo)
    }

    func session(_ session: WCSession, didFinish userInfoTransfer: WCSessionUserInfoTransfer, error: Error?) {
        // implement this on the sender if you need to confirm that
        // the user info did in fact transfer
    }

    // Receiver
    func session(_ session: WCSession, didReceiveUserInfo userInfo: [String : Any] = [:]) {
        // handle receiving user info
        DispatchQueue.main.async {
            // make sure to put on the main queue to update UI!
        }
    }

}

// MARK: Transfer File
extension WatchSessionManager {

    // Sender
    func transferFile(file: NSURL, metadata: [String : AnyObject]) -> WCSessionFileTransfer? {
        return validSession?.transferFile(file as URL, metadata: metadata)
    }

    func session(_ session: WCSession, didFinish fileTransfer: WCSessionFileTransfer, error: Error?) {
        // handle filed transfer completion
    }

    // Receiver
    func session(_ session: WCSession, didReceive file: WCSessionFile) {
        // handle receiving file
        DispatchQueue.main.async {
            // make sure to put on the main queue to update UI!
        }
    }
}


// MARK: Interactive Messaging
extension WatchSessionManager {

    // Live messaging! App has to be reachable
    private var validReachableSession: WCSession? {
        if let session = validSession , session.isReachable {
            return session
        }
        return nil
    }

    // Sender
    func sendMessage(message: [String : AnyObject],
                     replyHandler: (([String : Any]) -> Void)? = nil,
                     errorHandler: ((Error) -> Void)? = nil)
    {
        validReachableSession?.sendMessage(message, replyHandler: replyHandler, errorHandler: errorHandler)
    }

    func sendMessageData(data: Data,
                         replyHandler: ((Data) -> Void)? = nil,
                         errorHandler: ((Error) -> Void)? = nil)
    {
        validReachableSession?.sendMessageData(data, replyHandler: replyHandler, errorHandler: errorHandler)
    }

    // Receiver
    func session(_ session: WCSession, didReceiveMessage message: [String : Any], replyHandler: @escaping ([String : Any]) -> Void) {
        // handle receiving message
        DispatchQueue.main.async {
            // make sure to put on the main queue to update UI!
        }
    }

    func session(_ session: WCSession, didReceiveMessageData messageData: Data) {
        // handle receiving message data
        DispatchQueue.main.async {
            // make sure to put on the main queue to update UI!
        }
    }
}
@cschep

This comment has been minimized.

cschep commented Dec 18, 2016

i had to also wrap

#if os(iOS)
func sessionDidBecomeInactive(_ session: WCSession) {
}

func sessionDidDeactivate(_ session: WCSession) {
}
#endif
@adilanchian

This comment has been minimized.

adilanchian commented Jan 10, 2017

This is awesome. Thank you for this!

@skuske

This comment has been minimized.

skuske commented Feb 15, 2017

Objective-C version, please! :) TIA.

@kayoslab

This comment has been minimized.

kayoslab commented Feb 27, 2017

Swift 3.0 Version:

//
//  WatchSessionManager.swift
//  WatchConnectivityDemo
//
//  Created by Natasha Murashev on 9/3/15.
//  Copyright © 2015 NatashaTheRobot. All rights reserved.
//  Updated by Simon Krüger on 2/27/17.
//  Changes © 2017 Kayoslab.
//

import WatchKit
import WatchConnectivity

class WatchSessionManager: NSObject, WCSessionDelegate {

    static let sharedManager = WatchSessionManager()
    fileprivate let session: WCSession? = WCSession.isSupported() ? WCSession.default() : nil
    fileprivate var validSession: WCSession? {
        // paired - the user has to have their device paired to the watch
        // watchAppInstalled - the user must have your watch app installed

        // Note: if the device is paired, but your watch app is not installed
        // consider prompting the user to install it for a better experience
        if let session = session, session.isPaired && session.isWatchAppInstalled {
            return session
        }
        return nil
    }

    private override init() {
        super.init()
    }

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

    /** 
     * Called when the session has completed activation. 
     * If session state is WCSessionActivationStateNotActivated there will be an error with more details. 
     */
    func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) {

    }

    /** 
     * Called when the session can no longer be used to modify or add any new transfers and, 
     * all interactive messages will be cancelled, but delegate callbacks for background transfers can still occur. 
     * This will happen when the selected watch is being changed. 
     */
    func sessionDidBecomeInactive(_ session: WCSession) {

    }
    /** 
     * Called when all delegate callbacks for the previously selected watch has occurred.
     * The session can be re-activated for the now selected watch using activateSession.
     */
    func sessionDidDeactivate(_ session: WCSession) {

    }
}

// MARK: Application Context
// use when your app needs only the latest information
// if the data was not sent, it will be replaced
extension WatchSessionManager {

    // Sender
    func updateApplicationContext(applicationContext: [String : AnyObject]) throws {
        if let session = validSession {
            do {
                try session.updateApplicationContext(applicationContext)
            } catch let error {
                throw error
            }
        }
    }

    // Receiver
    func session(session: WCSession, didReceiveApplicationContext applicationContext: [String : AnyObject]) {
        // handle receiving application context
        DispatchQueue.main.async() {
            // make sure to put on the main queue to update UI!
        }
    }
}

// MARK: User Info
// use when your app needs all the data
// FIFO queue
extension WatchSessionManager {

    // Sender
    func transferUserInfo(userInfo: [String : AnyObject]) -> WCSessionUserInfoTransfer? {
        return validSession?.transferUserInfo(userInfo)
    }

    func session(session: WCSession, didFinishUserInfoTransfer userInfoTransfer: WCSessionUserInfoTransfer, error: Error?) {
        // implement this on the sender if you need to confirm that
        // the user info did in fact transfer
    }

    // Receiver
    func session(session: WCSession, didReceiveUserInfo userInfo: [String : AnyObject]) {
        // handle receiving user info
        DispatchQueue.main.async() {
            // make sure to put on the main queue to update UI!
        }
    }

}

// MARK: Transfer File
extension WatchSessionManager {

    // Sender
    func transferFile(file: NSURL, metadata: [String : AnyObject]) -> WCSessionFileTransfer? {
        return validSession?.transferFile(file as URL, metadata: metadata)
    }

    func session(session: WCSession, didFinishFileTransfer fileTransfer: WCSessionFileTransfer, error: Error?) {
        // handle filed transfer completion
    }

    // Receiver
    func session(session: WCSession, didReceiveFile file: WCSessionFile) {
        // handle receiving file
        DispatchQueue.main.async() {
            // make sure to put on the main queue to update UI!
        }
    }
}


// MARK: Interactive Messaging
extension WatchSessionManager {

    // Live messaging! App has to be reachable
    private var validReachableSession: WCSession? {
        if let session = validSession, session.isReachable {
            return session
        }
        return nil
    }

    // Sender
    func sendMessage(message: [String : AnyObject], replyHandler: (([String : Any]) -> Void)? = nil, errorHandler: ((Error) -> Void)? = nil) {
        validReachableSession?.sendMessage(message, replyHandler: replyHandler, errorHandler: errorHandler)
    }

    func sendMessageData(data: Data, replyHandler: ((Data) -> Void)? = nil, errorHandler: ((Error) -> Void)? = nil) {
        validReachableSession?.sendMessageData(data, replyHandler: replyHandler, errorHandler: errorHandler)
    }

    // Receiver
    func session(session: WCSession, didReceiveMessage message: [String : AnyObject], replyHandler: ([String : AnyObject]) -> Void) {
        // handle receiving message
        DispatchQueue.main.async() {
            // make sure to put on the main queue to update UI!
        }
    }

    func session(session: WCSession, didReceiveMessageData messageData: NSData, replyHandler: (NSData) -> Void) {
        // handle receiving message data
        DispatchQueue.main.async() {
            // make sure to put on the main queue to update UI!
        }
    }
}
@vivekguptaraw

This comment has been minimized.

vivekguptaraw commented Nov 30, 2017

I had the same file on both side (i.e. WatchApp, IPhone App)
class WatchSessionManager: NSObject, WCSessionDelegate {
}

And i am getting sendmessage functionality working as expected. But transferUserInfo not working. I am not receiving userInfo at IPhone app side in didReceiveUserInfo delegate method after sending from WatchApp side. Can you please help.

Or I Have to put only one WatchSessionManager file with target membership at both app (watch, iphone) ?

Please help me.

Thanks

@demosten

This comment has been minimized.

demosten commented Jan 24, 2018

If you are using @kayoslab version it has some wrong method names e.g.
func session(session: WCSession, didReceiveUserInfo userInfo: [String : AnyObject])
should be
func session(_ session: WCSession, didReceiveUserInfo userInfo: [String : Any] = [:]) for example

The easiest way to find such problems is to make Watch app call these and then run iOS App in debug. WCSession on phone often prints in console if there is something wrong. You can clearly see if you miss a delegate method. WCSession on watch app does not do it.

@smargo-zfs

This comment has been minimized.

smargo-zfs commented May 30, 2018

// handle receiving message data
DispatchQueue.main.async() {
// make sure to put on the main queue to update UI!
}

if this is on the watch side, how to access UI elements from here? Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment