首页 > 解决方案 > WatchOS 6.0、Swift 5.0:无背景触觉

问题描述

当应用程序在后台时,我试图获得触觉反馈。本质上,当某个值超过阈值时,应该有触觉反馈。据我所见,我已经正确设置了所有内容;当超过阈值时我正在调用的函数我知道正在被调用,因为我可以在日志中看到它,但是没有声音或振动发生。所以我不确定我做错了什么。当应用程序显示在屏幕上时,它可以正常工作,但不能在后台显示。

这是使用较旧的 Apple 示例代码(我知道折旧的项目)。我的最终目标是拥有一个棒球投球分析应用程序,其触觉是加强学习的肌肉记忆,有点像与狗一起训练的答题器。

这是引入 CoreMotion 的 MotionManager。

import Foundation
import CoreMotion
import WatchKit
import os.log

protocol MotionManagerDelegate: class {
    func didUpdateMotion(_ manager: MotionManager, gravityStr: String, rotationRateStr: String, userAccelStr: String, attitudeStr: String, rollInt: Double)
}

extension Date {
    var millisecondsSince1970:Int64 {
        return Int64((self.timeIntervalSince1970 * 1000.0).rounded())
    }
}

class MotionManager {
// MARK: Properties

let motionManager = CMMotionManager()
let queue = OperationQueue()
let wristLocationIsLeft = WKInterfaceDevice.current().wristLocation == .left

// MARK: Application Specific Constants

// The app is using 50hz data and the buffer is going to hold 1s worth of data.
let sampleInterval = 1.0 / 50
let rateAlongGravityBuffer = RunningBuffer(size: 50)

weak var delegate: MotionManagerDelegate?

var gravityStr = ""
var rotationRateStr = ""
var userAccelStr = ""
var attitudeStr = ""
var rollInt = 0.0

var recentDetection = false

// MARK: Initialization

init() {
    // Serial queue for sample handling and calculations.
    queue.maxConcurrentOperationCount = 1
    queue.name = "MotionManagerQueue"
}

// MARK: Motion Manager

func startUpdates() {
    if !motionManager.isDeviceMotionAvailable {
        print("Device Motion is not available.")
        return
    }

    os_log("Start Updates");

    motionManager.deviceMotionUpdateInterval = sampleInterval
    motionManager.startDeviceMotionUpdates(to: queue) { (deviceMotion: CMDeviceMotion?, error: Error?) in
        if error != nil {
            print("Encountered error: \(error!)")
        }

        if deviceMotion != nil {
            self.processDeviceMotion(deviceMotion!)
        }
    }
}

func stopUpdates() {
    if motionManager.isDeviceMotionAvailable {
        motionManager.stopDeviceMotionUpdates()
    }
}

// MARK: Motion Processing

func processDeviceMotion(_ deviceMotion: CMDeviceMotion) {
    gravityStr = String(format: "X: %.1f Y: %.1f Z: %.1f" ,
                        deviceMotion.gravity.x,
                        deviceMotion.gravity.y,
                        deviceMotion.gravity.z)
    userAccelStr = String(format: "X: %.1f Y: %.1f Z: %.1f" ,
                       deviceMotion.userAcceleration.x,
                       deviceMotion.userAcceleration.y,
                       deviceMotion.userAcceleration.z)
    rotationRateStr = String(format: "X: %.1f Y: %.1f Z: %.1f" ,
                          deviceMotion.rotationRate.x,
                          deviceMotion.rotationRate.y,
                          deviceMotion.rotationRate.z)
    attitudeStr = String(format: "r: %.1f p: %.1f y: %.1f" ,
                             deviceMotion.attitude.roll,
                             deviceMotion.attitude.pitch,
                             deviceMotion.attitude.yaw)

    rollInt = deviceMotion.attitude.roll

    let timestamp = Date().millisecondsSince1970

    os_log("Motion: %@, %@, %@, %@, %@, %@, %@, %@, %@, %@, %@, %@, %@",
           String(timestamp),
           String(deviceMotion.gravity.x),
           String(deviceMotion.gravity.y),
           String(deviceMotion.gravity.z),
           String(deviceMotion.userAcceleration.x),
           String(deviceMotion.userAcceleration.y),
           String(deviceMotion.userAcceleration.z),
           String(deviceMotion.rotationRate.x),
           String(deviceMotion.rotationRate.y),
           String(deviceMotion.rotationRate.z),
           String(deviceMotion.attitude.roll),
           String(deviceMotion.attitude.pitch),
           String(deviceMotion.attitude.yaw))

    updateMetricsDelegate();
}

// MARK: Data and Delegate Management

func updateMetricsDelegate() {
    delegate?.didUpdateMotion(self,gravityStr:gravityStr, rotationRateStr: rotationRateStr, userAccelStr: userAccelStr, attitudeStr: attitudeStr, rollInt: rollInt)
}
}

这是我的 WorkOutMangager 控制锻炼会话的地方。我正在调用的函数在最后。它从 MotionManagerDelagate 中提取值。

import Foundation
import HealthKit
import WatchKit
import os.log

protocol WorkoutManagerDelegate: class {
    func didUpdateMotion(_ manager: WorkoutManager, gravityStr: String, rotationRateStr: String, userAccelStr: String, attitudeStr: String)
}

class WorkoutManager: MotionManagerDelegate {
    // MARK: Properties
    let motionManager = MotionManager()
    let healthStore = HKHealthStore()

var rollInt = 0.0

weak var delegate: WorkoutManagerDelegate?
var session: HKWorkoutSession?

// MARK: Initialization

init() {
    motionManager.delegate = self
}

// MARK: WorkoutManager

func startWorkout() {
    // If we have already started the workout, then do nothing.
    if (session != nil) {
        return
    }

    // Configure the workout session.
    let workoutConfiguration = HKWorkoutConfiguration()
    workoutConfiguration.activityType = .tennis
    workoutConfiguration.locationType = .outdoor

    do {
        session = try HKWorkoutSession(configuration: workoutConfiguration)
    } catch {
        fatalError("Unable to create the workout session!")
    }

    // Start the workout session andKAKAHA.watchWatch.watchkitapp device motion updates.
    healthStore.start(session!)
    motionManager.startUpdates()

    if(rollInt < -0.9){
        WKInterfaceDevice.current().play(.failure)
        os_log("ALERT!!!")
    }
}

func stopWorkout() {
    // If we have already stopped the workout, then do nothing.
    if (session == nil) {
        return
    }

    // Stop the device motion updates and workout session.
    motionManager.stopUpdates()
    healthStore.end(session!)

    // Clear the workout session.
    session = nil
}

// MARK: MotionManagerDelegate

func didUpdateMotion(_ manager: MotionManager, gravityStr: String, rotationRateStr: String, userAccelStr: String, attitudeStr: String, rollInt: Double) {

    delegate?.didUpdateMotion(self, gravityStr: gravityStr, rotationRateStr: rotationRateStr, userAccelStr: userAccelStr, attitudeStr: attitudeStr)

    self.rollInt = rollInt
    rollAlert()
}

@objc fileprivate func rollAlert(){
    if (rollInt < -0.9) {
        WKInterfaceDevice.current().play(.failure)
        os_log("TOO CLOSE TO FACE!!!")
    }
   }
}

标签: swiftxcodeswift5watchoswatchos-6

解决方案


我觉得我好笨。我没有选择“音频”作为背景模式。


推荐阅读