Swift 无触觉反馈
我的watchos应用程序依赖于在后台工作的触觉反馈。我在互联网上搜索了一个又一个如何做到这一点,只学会了如何在我的info.plist中添加内容 我不想使用通知提醒我的用户,因为它在UI方面很麻烦,因为这样做太频繁了 我读了一些关于锻炼的文章,但没法让它发挥作用 当手腕降低时,我如何允许触觉反馈工作?最简单的方法就足够了,我不是swift最先进的,所以请尝试充分解释 下面是我的代码示例。如果我想让背景触觉反馈发挥作用,请告诉我该放在哪里: 我的计时器:Swift 无触觉反馈,swift,watchos-3,haptic-feedback,Swift,Watchos 3,Haptic Feedback,我的watchos应用程序依赖于在后台工作的触觉反馈。我在互联网上搜索了一个又一个如何做到这一点,只学会了如何在我的info.plist中添加内容 我不想使用通知提醒我的用户,因为它在UI方面很麻烦,因为这样做太频繁了 我读了一些关于锻炼的文章,但没法让它发挥作用 当手腕降低时,我如何允许触觉反馈工作?最简单的方法就足够了,我不是swift最先进的,所以请尝试充分解释 下面是我的代码示例。如果我想让背景触觉反馈发挥作用,请告诉我该放在哪里: 我的计时器: _ = Timer.scheduled
_ = Timer.scheduledTimer(timeInterval: 88, target: self, selector: "action", userInfo: nil, repeats: true)
我的行动:
func action() {
print("action")
WKInterfaceDevice.current().play(.success)
imageObject.setImageNamed("number2")
}
这就是我正在进行的香港健身训练,但我完全不知道发生了什么
func workoutSession(_ workoutSession: HKWorkoutSession, didChangeTo toState: HKWorkoutSessionState, from fromState: HKWorkoutSessionState, date: Date) {
switch toState {
case .running:
workoutDidStart(date)
case .ended:
workoutDidEnd(date)
default:
print("Unexpected state \(toState)")
}
}
func workoutSession(_ workoutSession: HKWorkoutSession, didFailWithError error: Error) {
// Do nothing for now
print("Workout error")
}
func workoutDidStart(_ date : Date) {
if let query = createHeartRateStreamingQuery(date) {
self.currenQuery = query
healthStore.execute(query)
} else {
label.setText("cannot start")
}
}
func workoutDidEnd(_ date : Date) {
healthStore.stop(self.currenQuery!)
label.setText("---")
session = nil
}
// MARK: - Actions
@IBAction func startBtnTapped() {
if (self.workoutActive) {
//finish the current workout
self.workoutActive = false
self.startStopButton.setTitle("Start")
if let workout = self.session {
healthStore.end(workout)
}
} else {
//start a new workout
self.workoutActive = true
self.startStopButton.setTitle("Stop")
_ = Timer.scheduledTimer(timeInterval: 5, target: self, selector: "firsts", userInfo: nil, repeats: false)
startWorkout()
}
}
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 = .crossTraining
workoutConfiguration.locationType = .indoor
do {
session = try HKWorkoutSession(configuration: workoutConfiguration)
session?.delegate = self
} catch {
fatalError("Unable to create the workout session!")
}
healthStore.start(self.session!)
}
func createHeartRateStreamingQuery(_ workoutStartDate: Date) -> HKQuery? {
guard let quantityType = HKObjectType.quantityType(forIdentifier: HKQuantityTypeIdentifier.heartRate) else { return nil }
let datePredicate = HKQuery.predicateForSamples(withStart: workoutStartDate, end: nil, options: .strictEndDate )
//let devicePredicate = HKQuery.predicateForObjects(from: [HKDevice.local()])
let predicate = NSCompoundPredicate(andPredicateWithSubpredicates:[datePredicate])
let heartRateQuery = HKAnchoredObjectQuery(type: quantityType, predicate: predicate, anchor: nil, limit: Int(HKObjectQueryNoLimit)) { (query, sampleObjects, deletedObjects, newAnchor, error) -> Void in
//guard let newAnchor = newAnchor else {return}
//self.anchor = newAnchor
self.updateHeartRate(sampleObjects)
}
heartRateQuery.updateHandler = {(query, samples, deleteObjects, newAnchor, error) -> Void in
//self.anchor = newAnchor!
self.updateHeartRate(samples)
}
return heartRateQuery
}
func updateHeartRate(_ samples: [HKSample]?) {
guard let heartRateSamples = samples as? [HKQuantitySample] else {return}
DispatchQueue.main.async {
guard let sample = heartRateSamples.first else{return}
let value = sample.quantity.doubleValue(for: self.heartRateUnit)
self.label.setText(String(UInt16(value)))
// retrieve source from sample
let name = sample.sourceRevision.source.name
self.updateDeviceName(name)
self.animateHeart()
}
}
func updateDeviceName(_ deviceName: String) {
deviceLabel.setText(deviceName)
}
func animateHeart() {
self.animate(withDuration: 0.5) {
self.heart.setWidth(60)
self.heart.setHeight(90)
}
let when = DispatchTime.now() + Double(Int64(0.5 * double_t(NSEC_PER_SEC))) / Double(NSEC_PER_SEC)
DispatchQueue.global(qos: .default).async {
DispatchQueue.main.asyncAfter(deadline: when) {
self.animate(withDuration: 0.5, animations: {
self.heart.setWidth(50)
self.heart.setHeight(80)
}) }
}
}
听着,我甚至不需要心率数据或任何东西,只需要背景中嗡嗡作响的taptic引擎 这只能通过使用
HKWorkoutSessions
实现。苹果明确规定了可用的背景模式,没有HKWorkoutSession
,它们都不允许您在背景中触发触觉反馈
使用HKWorkoutSession
您可以使用应用程序实现跟踪用户训练的应用程序。当HKWorkoutSession
正在运行时,您的应用程序具有多个权限:
该应用程序在整个训练过程中持续运行,甚至
当用户降低手腕或与其他应用程序交互时。
当用户抬起手腕时,应用程序会重新出现,让用户
快速方便地检查其当前进度和性能
该应用程序可以继续访问苹果手表传感器中的数据
背景,让您随时更新应用程序。对于
例如,跑步应用程序可以继续跟踪用户的心率,
确保随时显示最新的心率数据
用户抬起手腕
该应用程序可以在运行时使用音频或触觉反馈提醒用户
在后台运行
要使用HKWorkoutSession
并提供触觉反馈,您需要将WKBackgroundModes
键和UIBackgroundModes
添加到WatchKit分机的Info.plist中
<key>WKBackgroundModes</key>
<array>
<string>workout-processing</string>
</array>
<key>UIBackgroundModes</key>
<array>
<string>audio</string>
</array>
WKBackgroundModes
有关如何使用HKWorkoutSession
的完整示例,请查看。即使应用程序在后台运行,示例应用程序也会每五秒钟触发一次振动。
HKWorkoutSession
因此,只有当应用程序使用包含HealthKit
权限的配置文件签名时,该示例才起作用。确保为所有三个可用目标将开发团队更改为您自己的团队。Xcode将尝试创建所需的配置文件。如果存在任何签名问题或您使用在后台运行的通配符配置文件将不起作用。作为回答,我创建了一个示例项目,演示如何在后台触发振动:
有关如何使用HKWorkoutSession
的完整示例,请查看。即使应用程序在后台运行,示例应用程序也会每五秒钟触发一次振动。
HKWorkoutSession
因此,只有当应用程序使用包含HealthKit
权限的配置文件签名时,该示例才起作用。确保为所有三个可用目标将开发团队更改为您自己的团队。Xcode将尝试创建所需的配置文件。如果存在任何签名问题或您使用的是在后台运行的通配符配置文件,则该配置文件将不起作用。我已尝试过此方法,但无法使其起作用。有没有人可以给我发一个训练的例子,在背景中除了触觉反馈什么都不做?你使用HKWorkoutSession
的代码在哪里?你的例子并不表明你尝试了我在回答中所概述的东西。您是否尝试使用HKWorkoutSession
?任何想法Naglerri更新了我的答案,并在我的GitHub上链接了一个完整的示例项目。非常感谢您花时间创建此项目并帮助我。享受你的赏金吧!不过我有几个问题。使用应用程序时是否可以禁用心率传感器?你如何结束训练?再次感谢你的帮助。我有一个更重要的问题,希望你能回答。在这种情况下使用私有函数和文件私有函数的意义是什么?如果扩展委托:func applicationWillResignActive()是一个私有函数,如何停止它中的计时器?这只是一个示例。这些方法不需要是private
或fileprivate
。