I am trying to read core motion data (accel, gyro) and store them using my iWatch 6 for an extended amount of time (about 14 days). So, I realize that my application becomes unresponsive. I looked into it and I think that the watchdog kills my application because I am constantly writing stuff in OperationQueue.current! .To extract data from this queue, I need to get the foreground. So, I thought that my best bet would be to schedule a task and call it every ~30 min to do that for me. But when I schedule a task, it keeps happening for the first couple of times and then becomes very sporadic (maybe every 10 hours instead of 30 min). So, I am just looking for a way to do such an EASY task.
Since I was not able to use the scheduleBackgroundRefresh, I am using the locationmanager as an alternative (just like a timer) as it can run in the background. I know that it is not the best practice but I could not find any other way around this. To save the battery, I used the reduced accuracy which collects the location every 15 minutes or so. This runs great up until 8 hours. Then it becomes sporadic again! I am not sure what to do with that.
//
// ExtensionDelegate.swift
// STMITest WatchKit Extension
import WatchKit
import CoreMotion
class ExtensionDelegate: NSObject, WKExtensionDelegate, CLLocationManagerDelegate {
let motionManagerDelegate = CMMotionManager()
let locationManager:CLLocationManager = CLLocationManager()
var sensorTime=[Double]()
var sensorRx=[Double]()
var sensorRy=[Double]()
var sensorRz=[Double]()
var offsetTime=0.0
var offsetTimeFlag=true
var lastSyncedDate=Date()
var locationStartDate=Date()
func applicationDidFinishLaunching() {
print("Delegate:App finished lunching")
locationConfig()
locationStarter()
lastSyncedDate=Date()
locationStartDate=Date()
}
func locationConfig(){
print("LocationConfig Func")
locationManager.delegate=self
locationManager.desiredAccuracy = kCLLocationAccuracyReduced
locationManager.allowsBackgroundLocationUpdates=true
locationManager.activityType = .fitness
}
func locationStarter(){
if locationManager.authorizationStatus == .authorizedWhenInUse || locationManager.authorizationStatus == .authorizedAlways{
print("-------------initiation-authority is ok")
locationManager.startUpdatingLocation()
}
else{
print("-------------initiation-authority is changing")
locationManager.requestWhenInUseAuthorization()
}
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
if locations.first != nil {
print("location:: \(locations)")
}
startQueuedMotionUpdates()
var timeInterval=Date().timeIntervalSince(lastSyncedDate)
if timeInterval > 1 * 60{
binaryWriter("GPSSuccess")
lastSyncedDate=Date()
}
timeInterval=Date().timeIntervalSince(locationStartDate)
if timeInterval > 3 * 60 * 60{
locationManager.stopUpdatingLocation()
locationManager.startUpdatingLocation()
}
}
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error ) {
print("Error in location manager")
startQueuedMotionUpdates()
var timeInterval=Date().timeIntervalSince(lastSyncedDate)
if timeInterval > 1 * 60{
binaryWriter("GPSError")
lastSyncedDate=Date()
}
timeInterval=Date().timeIntervalSince(locationStartDate)
if timeInterval > 3 * 60 * 60{
locationManager.stopUpdatingLocation()
locationManager.startUpdatingLocation()
}
}
func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) {
print("authority should change",self.locationManager.authorizationStatus)
switch manager.authorizationStatus {
case .restricted, .denied, .notDetermined:
print("restricted, denied or notDetermined")
locationManager.requestWhenInUseAuthorization()
break
case .authorizedAlways:
print("always on")
break
case .authorizedWhenInUse:
print("only when it is in use")
locationManager.startUpdatingLocation()
}
}
// func taskScheduler(){
// let fireDate=Date(timeIntervalSinceNow: 60*60)
// let wkExt = WKExtension.shared()
// let info: NSDictionary = ["Caller": "to update motion"]
// wkExt.scheduleBackgroundRefresh(withPreferredDate: fireDate,userInfo:info) { (error: Error?) in if (error != nil) {
// print("background refresh could not be scheduled.")
// }
// else{
// print("successfully scheduled")
// }
// }
//
// }
func startQueuedMotionUpdates() {
if self.motionManagerDelegate.isDeviceMotionAvailable {
if !motionManagerDelegate.isDeviceMotionActive{
motionManagerDelegate.deviceMotionUpdateInterval = 30.0 / 60.0
motionManagerDelegate.showsDeviceMovementDisplay = true
}
motionManagerDelegate.startDeviceMotionUpdates(using: .xMagneticNorthZVertical, to: OperationQueue.current!, withHandler: { (data, error) in
if let validData = data {
let rX = validData.rotationRate.x
let rY = validData.rotationRate.y
let rZ = validData.rotationRate.z
let aX = validData.userAcceleration.x
let aY = validData.userAcceleration.y
let aZ = validData.userAcceleration.z
let timeStamp=validData.timestamp
if self.offsetTimeFlag{
self.offsetTime = 0.0-timeStamp
self.offsetTimeFlag=false
}
// self.sensorTime.append(contentsOf: [timeStamp+self.offsetTime])
self.sensorTime.append(contentsOf: [timeStamp+self.offsetTime,rX,rY,rZ,aX,aY,aZ])
}
})
}
else {
fatalError("The motion data is not avaialable")
}
}
func binaryWriter(_ extensionName: String) {
var myDate = Date()
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "dd-HH:mm:ss"
var currentTime = dateFormatter.string(from: myDate)
var fileName = currentTime+extensionName
print("Writing Start========================",fileName)
if let dir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first {
do {
fileName = currentTime+extensionName+"Time"
var fileURL = dir.appendingPathComponent(fileName)
try (self.sensorTime as NSArray).write(to: fileURL,atomically: true)
self.sensorTime.removeAll()
}
catch{
print("Error in the binaryWriter Function")
}
}
myDate = Date()
currentTime = dateFormatter.string(from: myDate)
print("Writing End========================",currentTime)
}
}