0

I am working on a application which needs accelerometer, gyroscope & pedometer data & also the heart rate. I am transferring this data from iwatch to iPhone then from iPhone I need to sync this data via MQTT protocol. Now my problem is that, once the iwatch window goes disable my application terminated. I am using core motion and live workout session. Can anyone help me on how can I keep the iwatch app active or transfer the above data from inactive mode ?

Naresh
  • 869
  • 8
  • 17

2 Answers2

1

Here is my solution that can help you:

Ref: https://developer.apple.com/documentation/healthkit/workouts_and_activity_rings/running_workout_sessions

  1. Setup HKWorkoutSession and CoreMotion listener
import WatchKit
import Foundation
import CoreMotion
import HealthKit

enum VelocityVector: Int {
    case x, y, z
}

class InterfaceController: WKInterfaceController {

    @IBOutlet weak var labelVelocity: WKInterfaceLabel!
    let coreMotion = CMMotionManager.init()
    let pool = OperationQueue.init()
    let currentSession: HKWorkoutSession?
    let healthKit = HKHealthStore()
    
    override func awake(withContext context: Any?) {
        coreMotion.accelerometerUpdateInterval = 0.1
        coreMotion.startAccelerometerUpdates(to: pool) { data, err in
            guard let _data = data else { return }
            DispatchQueue.main.async {
                self.labelVelocity.setText(String.init(format: "G-Force (x:y:z) %.3f:%.3f:%.3f", arguments: [_data.acceleration.x, _data.acceleration.y, _data.acceleration.z]))
            }
        }
        
        let config = HKWorkoutConfiguration.init()
        config.activityType = .other
        config.locationType = .unknown
        
        do {
            self.currentSession = try HKWorkoutSession.init(healthStore: self.healthKit, configuration: config)
            self.currentSession?.startActivity(with: Date())
        } catch error {
            print(error?.localizedDescription)
        }        
    }

    private func stopHKWorkoutSession() {
        self.currentSession?.stopActivity(with: Date())
        self.currentSession?.end()
    }
    
    override func willActivate() {
        // This method is called when watch view controller is about to be visible to user
    }
    
    override func didDeactivate() {
        // This method is called when watch view controller is no longer visible
    }

}
  1. Enable "Workout processing" in Background Mode: enter image description here
Neklas
  • 504
  • 1
  • 9
  • Thanks for sharing your answer @Neklas, I did this already but somehow the session got ended after sometime. – Naresh Sep 06 '22 at 17:08
  • @Naresh Please check your crash log or something that can help you to know what happens during app runs. Because I am developing a Health tracking app too. It has Sleep Tracking with Body motion detection. It can run constantly in the background for 8-10 hours. You can get workout error event by implementing its delegate: https://developer.apple.com/documentation/healthkit/hkworkoutsessiondelegate/1627951-workoutsession Ex: func workoutSession(_ workoutSession: HKWorkoutSession, didFailWithError error: Error) – Neklas Sep 06 '22 at 21:27
  • as per apple developer we can have one workout session in the iwatch, so did you did something with default activity and workout app ? – Naresh Sep 07 '22 at 05:31
  • 1
    From doc: "Apple Watch runs one workout session at a time. If a second workout starts while your workout is running, your HKWorkoutSessionDelegate object receives an HKError.Code.errorAnotherWorkoutSessionStarted error, and your session ends." If you run new HKWorkoutSession, the current will be stopped. So you need to control this too. Or, you can use WKExtendedRuntimeSession, but the maximum background time that app can run is 1 hour for [Physical Therapy] type. Ref: https://developer.apple.com/documentation/watchkit/using_extended_runtime_sessions. – Neklas Sep 07 '22 at 05:35
  • If you don't need HR constantly updating, you can start a Background Location updating. It will keep your app run in the background to continue executing code. Call startUpdatingLocation() after set accuracy to Low (like 1000 meters) and distanceFilter to 3000 meters, to reduce battery consumption. – Neklas Sep 07 '22 at 05:36
  • Is it possible to make this data transfer real-time with latency up to a few second? – Sam Jun 06 '23 at 15:18
0

An addition to good answer of Neklas, should open capability of Healhkit and add permission of healthkit to info plist of watchos project like below images. Otherwise, you may encounter an error.

enter image description here

enter image description here

Okan TEL
  • 26
  • 3