【问题标题】:No haptic feedback没有触觉反馈
【发布时间】:2017-07-10 02:45:22
【问题描述】:

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

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

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

如何在手腕降低时让触觉反馈起作用?最简单的方法就够了,我不是最先进的,所以请尝试充分解释!

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

我的计时器:

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


    }
}

看,我什至不需要心率数据或其他任何东西,只需要在后台嗡嗡作响的 Taptic 引擎。

【问题讨论】:

    标签: swift watchos-3 haptic-feedback


    【解决方案1】:

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

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

    【讨论】:

    • 非常感谢您抽出时间来创建这个并帮助我。享受你的赏金!不过我有几个问题。是否可以在使用应用程序时禁用心率传感器?你如何结束锻炼?再次感谢您的帮助。
    • 我有一个更重要的问题,希望你能回答。在这种情况下使用私有和文件私有函数有什么意义?如果它是私有函数,我将如何停止扩展委托中的计时器:func applicationWillResignActive()?
    • 这只是一个例子。方法不必是privatefileprivate
    【解决方案2】:

    这只能使用HKWorkoutSessions。 Apple 的App Programming Guide for watchOS 明确指定了没有HKWorkoutSession 的可用背景模式,并且它们都不允许您在后台触发触觉反馈。

    使用HKWorkoutSession,您可以实现应用程序来跟踪用户使用应用程序的锻炼情况。当HKWorkoutSession 运行您的应用程序时,您的应用程序有几个权限:

    该应用程序会在整个锻炼过程中继续运行,即使 当用户放下手腕或与不同的应用程序交互时。 当用户抬起手腕时,应用重新出现,让用户 快速轻松地检查他们当前的进度和表现。

    应用程序可以继续访问 Apple Watch 传感器中的数据 背景,让您始终保持应用程序最新。为了 例如,一个正在运行的应用程序可以继续跟踪用户的心率, 确保随时显示最新的心率数据 用户抬起手腕。

    应用程序可以使用音频或触觉反馈提醒用户,同时 在后台运行。

    要使用 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 应用中的活动环
    • 根据您的应用程序类型,Apple 在 App Store 中发布时可能会拒绝您的应用程序
    • 需要HealthKit 授权(您可以在 Xcode 的 Capabilities 视图中添加它)

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

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

    【讨论】:

    • 我已经尝试过了,但无法让它工作。是否有人可以向我发送一个锻炼示例,该锻炼仅在后台提供触觉反馈?
    • 你的代码在哪里使用HKWorkoutSession?您的示例并未表明您尝试了我在回答中概述的内容。你试过使用HKWorkoutSession吗?
    • 任何想法 naglerrr
    • 我更新了我的答案,并在我的 GitHub 上提供了一个完整示例项目的链接。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-18
    • 2012-03-05
    相关资源
    最近更新 更多