mawus
mawus

Reputation: 1198

SiriKit Intents Extension: Avoid / auto resolve parameter when values are provided dynamically

I am building an app that uses Intents Extension to track various metrics, like weight, steps, hearth rate, etc. I want to offer to the user units of measurement to pick from, based on the metric he wants to track. For example, if the user tracks drinked water, she can choose between liter, fluid ounces, mililiters or cups and I will present her the units. If the user tracks steps, the only unit used is "steps" and it doesn't make sense to provide a disambiguation or dynamic options for it. I noticed that when using Dynamic Options, the generated provideUnitOptions function for it will be called every time, even when in the resolve function I send a notRequired resolution result.

Here are the functions from my intent handler:

func resolveMetric(for intent: MeasurementIntent, with completion: @escaping (INStringResolutionResult) -> Void) {
    let requestedMetric = intent.metric
    if requestedMetric == nil {
        completion(INStringResolutionResult.needsValue())
    } else {
        metricService.retrieveUserMetrics { (success) in
            let metricNames = self.metricService.metricNamesMap.keys
            if metricNames.contains(requestedMetric!){
                completion(.success(with: requestedMetric!))
            } else {
                completion(.disambiguation(with: Array(metricNames)))
            }
        }
    }
}

func provideMetricOptions(for intent: MeasurementIntent, with completion: @escaping ([String]?, Error?) -> Void) {
    metricService.retrieveUserMetrics { (success) in
        let metricNames = self.metricService.metricNamesMap.keys
        completion(Array(metricNames), nil)
    }
}

func resolveUnit(for intent: MeasurementIntent, with completion: @escaping (INStringResolutionResult) -> Void) {
    let metric = self.metricService.metricNamesMap[intent.metric!]!
    let units = metric.units.getSystemUnits(defaultUnit: metric.defaultUnit).map { $0.name }
    if units.count == 1 {
        completion(.notRequired())
    } else if intent.unit == nil {
        completion(.disambiguation(with: units))
    } else {
        completion(.success(with: intent.unit!))
    }
}

//This is called even if in resolveUnit I sent .notRequired resolution. Same for .success
func provideUnitOptions(for intent: MeasurementIntent, with completion: @escaping ([String]?, Error?) -> Void) {
    let metric = self.metricService.metricNamesMap[intent.metric!]!
    let units = metric.units.getSystemUnits(defaultUnit: metric.defaultUnit).map { $0.name }
    completion(units, nil)
}

The resolveUnit function is called both before and after provideUnitOptions I can disable Dynamic Options but in this case the user won't have the possibility to use predefined units from a Shortcut. How do you think I should proceed? Am I missing something? Thank you!

Upvotes: 0

Views: 992

Answers (1)

mawus
mawus

Reputation: 1198

Found a work around that helped me overcome this issue. So provideOptions will be called, at least first time for resolution completions like success and notRequired but not from disambiguation or confirmationRequired. Disambiguation won't help here but if I use confirmationRequired I can automatically pass my only option. In the confirmation prompt I don't have to include the field value, anything works.

if units.count == 1 {
        completion(.confirmationRequired(with: units[0]))
}

Hopefully will have an even more dynamic way for handling user parameters in a later iOS update, but this is good enough for now

Upvotes: 0

Related Questions