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