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