watchOS непрерывное считывание основных данных о движении

#swift #watchkit #watchos #core-motion

Вопрос:

Я пытаюсь считывать основные данные о движении (ускорение, гироскоп) и сохранять их с помощью своего iWatch 6 в течение длительного периода времени (около 14 дней). Итак, я понимаю, что мое заявление перестает отвечать на запросы. Я изучил это и думаю, что сторожевой пес убивает мое приложение, потому что я постоянно пишу что-то в OperationQueue.current! .Чтобы извлечь данные из этой очереди, мне нужно получить передний план. Поэтому я подумал, что лучше всего было бы запланировать задание и звонить каждые ~30 минут, чтобы сделать это за меня. Но когда я планирую задачу, это происходит первые пару раз, а затем становится очень спорадическим (возможно, каждые 10 часов вместо 30 минут). Итак, я просто ищу способ выполнить такую ЛЕГКУЮ задачу.

Поскольку я не смог использовать scheduleBackgroundRefresh, я использую locationmanager в качестве альтернативы (как и таймер), поскольку он может работать в фоновом режиме. Я знаю, что это не лучшая практика, но я не мог найти другого способа обойти это. Чтобы сэкономить заряд батареи, я использовал пониженную точность, которая собирает местоположение каждые 15 минут или около того. Это отлично работает до 8 часов. Затем это снова становится спорадическим! Я не знаю, что с этим делать.

 //
// 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)
  }
}