没有触觉反馈

No haptic feedback

我的 watchos 应用依赖于在后台运行的触觉反馈。我在互联网上搜索和搜索了如何执行此操作,但只学会了如何将内容添加到我的 info.plist

我不想使用通知来提醒我的用户,因为它在 UI 方面太麻烦了,因为这样做太频繁了。

我读到有关锻炼课程的信息,但无法让它发挥作用。

如何在手腕放低时允许触觉反馈起作用?最简单的方法就足够了,我不是最先进的 swift 所以请尝试完整解释!

我的代码示例如下。如果我想让背景触觉反馈起作用,请告诉我把它放在哪里:

我的计时器:

 _ = Timer.scheduledTimer(timeInterval: 88, target: self, selector: "action", userInfo: nil, repeats: true)

我的操作:

 func action() {
    print("action")
    WKInterfaceDevice.current().play(.success)
     imageObject.setImageNamed("number2")     
}

这就是我在 HKWorkout 会话中所做的,但完全不知道发生了什么。

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


    }
}

你看我什至不需要心率数据或任何东西,只需要背景中嗡嗡作响的触觉引擎。

这只能使用 HKWorkoutSessions。 Apple 的 App Programming Guide for watchOS 清楚地指定了没有 HKWorkoutSession 和 none 的可用背景模式将允许您在后台触发触觉反馈。

使用 HKWorkoutSession 您可以实现使用应用程序跟踪用户锻炼的应用程序。虽然 HKWorkoutSession 是 运行,但您的应用程序拥有多项特权:

The app continues to run throughout the entire workout session, even when the user lowers their wrist or interacts with a different app. When the user raises their wrist, the app reappears, letting the user quickly and easily check their current progress and performance.

The app can continue to access data from Apple Watch’s sensors in the background, letting you keep the app up to date at all times. For example, a running app can continue to track the user’s heart rate, ensuring that the most recent heart rate data is displayed whenever the user raises their wrist.

The app can alert the user using audio or haptic feedback while running in the background.

要使用 HKWorkoutSession 并提供触觉反馈,您需要将 WKBackgroundModes 键和 UIBackgroundModes 添加到您的 WatchKit 扩展的 Info.plist.

<key>WKBackgroundModes</key>
<array>
    <string>workout-processing</string>
</array>
<key>UIBackgroundModes</key>
<array>
    <string>audio</string>
</array>

对此有几个注意事项:

  • 当另一个 WKWorkoutSession 由另一个应用程序启动时,您的会话将结束
  • 如果您在后台过度使用资源,您的应用可能会被 watchOS 暂停
  • 您的应用可能有助于填充配对 iPhone
  • 上 Activity 应用中的 activity 环
  • 根据您的应用程序类型,当您在 App Store 中发布应用程序时,Apple 可能会拒绝您的应用程序
  • 需要 HealthKit 授权(您可以在 Xcode 的 Capabilities 视图中添加它)

有关如何实施 HKWorkoutSession 的更详细指南,请查看 API Reference

有关如何使用 HKWorkoutSession 的完整示例,请查看 my sample project on GitHub。即使应用程序 运行 在后台,示例应用程序也会每五秒触发一次振动。 HKWorkoutSession 因此该示例仅在使用包含 HealthKit 权利的配置文件对应用进行签名时才有效。请确保将所有三个可用目标的开发团队更改为您自己的团队。 Xcode 将尝试创建所需的配置文件。如果有任何签名问题或您在后台使用通配符配置文件 运行 将无法工作。

作为 的回答,我创建了一个示例项目,展示了如何在后台触发振动:

有关如何使用 HKWorkoutSession 的完整示例,请查看 my sample project on GitHub。即使应用 运行 在后台,示例应用也会每五秒触发一次振动。 HKWorkoutSession 因此该示例仅在使用包含 HealthKit 权利的配置文件对应用程序进行签名时才有效。请确保将所有三个可用目标的开发团队更改为您自己的团队。 Xcode 将尝试创建所需的配置文件。如果有任何签名问题或您在后台使用通配符配置文件 运行 将无法工作。