swiftuiwatchkitapple-watchwatchos

Is it possible to start an extendedRuntimeSession in background


I have a Companion Watch App for my iPhone App and communicate via the messages and applicationContext between the watch and the phone. If I start an Event at my iPhone and my watch is turned on the extendedRuntimeSession starts as it should. But as soon as my Watches Display is off or Im not in the App I can't start the extendedRuntimeSession, even though I receive it trough the applicationContext and I get the following errorMessage when trying to start the session in the background.

-[CSLSSessionService startSession:completionWithExpirationDate:]_block_invoke session A76273B7-3E01-4333-920C-0614C1FAC5B0 encountered error Error Domain=com.apple.CarouselServices.SessionErrorDomain Code=12 "app not in required app state" UserInfo={NSLocalizedDescription=app not in required app state}
Is Running is true
Timer started/continuend
-[SPApplicationDelegate appBeginWorkout:]_block_invoke:1334: Asked to start a workout, but WKExtensionDelegate <SwiftUI.ExtensionDelegate: 0x15d7c500> doesn't implement handleWorkoutConfiguration:
Extended runtime session invalidated with reason: WKExtendedRuntimeSessionInvalidationReason(rawValue: -1), error: Optional(Error Domain=WKExtendedRuntimeSessionErrorDomain Code=3 "The app must be active and before applicationWillResignActive to start or schedule a WKExtendedRuntimeSession." UserInfo={NSLocalizedDescription=The app must be active and before applicationWillResignActive to start or schedule a WKExtendedRuntimeSession..})

I control and manage my session like this:

class WatchViewModel: NSObject, ObservableObject {
    static let shared = WatchViewModel()
    var session: WCSession
    var extendedRuntimeSessionManager: ExtendedRuntimeSessionManager
    var lastMessage: [String: Any] = ["method": "none"]
    
    @Published var iOSIsReachable = false
  
    @Published var dataFromMessages = DataFromMessages()
    @Published var flextailCoordinates: FlextailCoordinates?
    
    
    init(session: WCSession = .default, extendedRuntimeSessionManager: ExtendedRuntimeSessionManager = ExtendedRuntimeSessionManager()) {
        NSLog("init start")
        self.session = session
        self.extendedRuntimeSessionManager = extendedRuntimeSessionManager
        
        super.init()
        self.session.delegate = self
        session.activate()
        NSLog("init done")
    }
}

class ExtendedRuntimeSessionManager: NSObject, WKExtendedRuntimeSessionDelegate, ObservableObject{
    var extendedRuntimeSession: WKExtendedRuntimeSession?
    @Published var sessionIsActive = false

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

    func setupExtendedRuntimeSession() {
        extendedRuntimeSession = WKExtendedRuntimeSession()
        extendedRuntimeSession?.delegate = self
    }

    func startExtendedRuntimeSession() {
        if sessionIsActive == false{
            extendedRuntimeSession?.start()
        } else{
            print("Already running extendedRuntimeSession")
        }
    }

    func stopExtendedRuntimeSession() {
        extendedRuntimeSession?.invalidate()
        sessionIsActive = false
        setupExtendedRuntimeSession()
    }

    // WKExtendedRuntimeSessionDelegate methods
    func extendedRuntimeSessionDidStart(_ extendedRuntimeSession: WKExtendedRuntimeSession) {
        print("Extended runtime session started")
        sessionIsActive = true
        
    }

    func extendedRuntimeSessionWillExpire(_ extendedRuntimeSession: WKExtendedRuntimeSession) {
        print("Extended runtime session will expire soon")
    }

    func extendedRuntimeSession(_ extendedRuntimeSession: WKExtendedRuntimeSession, didInvalidateWith reason: WKExtendedRuntimeSessionInvalidationReason, error: Error?) {
        print("Extended runtime session invalidated with reason: \(reason), error: \(String(describing: error))")
        sessionIsActive = false
        setupExtendedRuntimeSession()
        
    }
    
    
}

I tried sending it through the applicationContext but that didn't work, even though the message gets received and parsed as I want. The error specifically seems to be in the starting of an extendedRuntimeSession in the background.


Solution

  • Unfortunately this is not possible currently. The Apple documentation specifically states "You must always start or schedule the extended runtime session when your app state is in the WKApplicationState.active state."

    See Using extended runtime sessions