Нет тактильной обратной связи

Мое приложение 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 попытается создать необходимые профили обеспечения. Если есть какие-либо проблемы с подписанием или вы используете профиль подстановочного знака, работающий в фоновом режиме, работать не будет.

Другие вопросы по тегам