Нет тактильной обратной связи
Мое приложение watchos опирается на тактильные отзывы, работающие в фоновом режиме. Я искал и искал в интернете, как это сделать, и только научился добавлять вещи в мой info.plist.
Я не хочу использовать уведомления, чтобы предупредить моего пользователя о его громоздкости с точки зрения пользовательского интерфейса, потому что это будет происходить слишком часто.
Я читал о тренировках, но не могу заставить это работать.
Как мне разрешить тактильную обратную связь, когда запястье опущено? Достаточно самого простого способа, и я не самый продвинутый в использовании 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)
}) }
}
}
Слушай, мне даже не нужны данные о частоте сердечных сокращений или что-то еще, кроме гудящего двигателя на фоне.
2 ответа
В дополнение к моему предыдущему ответу я создал пример проекта, который показывает, как вызывать вибрации в фоновом режиме:
Для полного примера о том, как использовать HKWorkoutSession
посмотрите мой пример проекта на GitHub. Пример приложения будет вызывать вибрацию каждые пять секунд, даже если приложение работает в фоновом режиме. HKWorkoutSession
и, таким образом, образец работает только тогда, когда приложение было подписано с помощью профиля обеспечения, содержащего HealthKit
право. Обязательно измените команду разработчиков на свою собственную команду для всех трех доступных целей. Xcode попытается создать необходимые профили обеспечения. Если есть какие-либо проблемы с подписанием или вы используете профиль подстановочного знака, работающий в фоновом режиме, работать не будет.
Это возможно только при использовании HKWorkoutSessions
, Руководство по программированию приложений Apple для watchOS четко определяет доступные фоновые режимы без HKWorkoutSession
и ни один из них не позволит вам вызвать тактильную обратную связь в фоновом режиме.
С помощью HKWorkoutSession
Вы можете реализовать приложения, которые отслеживают тренировки пользователей, используя приложение. В то время как HKWorkoutSession
работает ваше приложение имеет несколько привилегий:
Приложение продолжает работать в течение всего сеанса тренировки, даже когда пользователь опускает запястье или взаимодействует с другим приложением. Когда пользователь поднимает запястье, приложение появляется снова, позволяя пользователю быстро и легко проверить свой текущий прогресс и производительность.
Приложение может продолжать получать доступ к данным с датчиков Apple Watch в фоновом режиме, что позволяет постоянно обновлять приложение. Например, работающее приложение может продолжать отслеживать частоту сердечных сокращений пользователя, обеспечивая отображение самых последних данных о частоте сердечных сокращений каждый раз, когда пользователь поднимает запястье.
Приложение может предупредить пользователя, используя звуковую или тактильную обратную связь при работе в фоновом режиме.
Чтобы использовать HKWorkoutSession
и предоставить тактильный отзыв, вам нужно будет добавить WKBackgroundModes
ключ и UIBackgroundModes
в Info.plist вашего расширения WatchKit.
<key>WKBackgroundModes</key>
<array>
<string>workout-processing</string>
</array>
<key>UIBackgroundModes</key>
<array>
<string>audio</string>
</array>
Есть несколько предостережений к этому:
- Когда другой
WKWorkoutSession
запускается другим приложением, ваша сессия будет завершена - Если вы используете ресурсы чрезмерно в фоновом режиме, ваше приложение может быть приостановлено watchOS
- Ваше приложение может способствовать заполнению колец активности в приложении Activity на сопряженном iPhone
- В зависимости от типа вашего приложения Apple может отклонить ваше приложение при публикации в App Store
-
HealthKit
право необходимо (вы можете добавить его в представлении Capabilities в Xcode)
Для более подробного руководства о том, как реализовать HKWorkoutSession
Проверьте Справочник по API.
Для полного примера о том, как использовать HKWorkoutSession
посмотрите мой пример проекта на GitHub. Пример приложения будет вызывать вибрацию каждые пять секунд, даже если приложение работает в фоновом режиме. HKWorkoutSession
и, таким образом, образец работает только тогда, когда приложение было подписано с помощью профиля обеспечения, содержащего HealthKit
право. Обязательно измените команду разработчиков на свою собственную команду для всех трех доступных целей. Xcode попытается создать необходимые профили обеспечения. Если есть какие-либо проблемы с подписанием или вы используете профиль подстановочного знака, работающий в фоновом режиме, работать не будет.