Let's say I've defined a custom intent, called FooIntent
, in an .intentdefinition
file.
It has a single parameter, bar
, of type Decimal
, for which:
- User can supply value in Siri and Shortcuts app
is active.
- Default Value
is 0
.
Its autogenerated class definition now looks like this:
public class FooIntent: INIntent {
@NSManaged public var bar: NSNumber?
}
If I construct a FooIntent
, set bar
to nil
, and pass it into a INUIAddVoiceShortcutViewController
:
let intent = FooIntent()
intent.bar = nil
intent.suggestedInvocationPhrase = "Do foo"
let shortcut = INShortcut(intent: intent)
let viewController = INUIAddVoiceShortcutViewController(shortcut: shortcut!)
viewController.delegate = self
window?.rootViewController?.present(viewController, animated: true, completion: nil)
the Add to Siri
modal appears with the bar
parameter filled in with 0
, its default value.
If, in the Add to Siri
UI, I then change bar
to Ask Each Time
and press Add to Siri
, the resulting delegate method call produces an INVoiceShortcut
object that contains a nil
value for bar
:
func addVoiceShortcutViewController(_ controller: INUIAddVoiceShortcutViewController, didFinishWith shortcut: INVoiceShortcut?, error: Error?) {
if let intent = shortcut?.shortcut.intent as? FooIntent {
print(intent.bar) // nil
}
controller.dismiss(animated: true, completion: nil)
}
The same is true if I set bar
to Clipboard
in the UI.
If I set it to a value, e.g. 42
, then intent.bar
correctly returns 42
.
Since nil
seems to represent multiple concepts for a parameter, where is the concept of Ask Each Time
stored in the shortcut or intent objects?
Is there anything I can pass into INUIAddVoiceShortcutViewController
such that intent.bar = <Ask Each Time>
?
Usually you control the behavior (of whether or not to continue asking for user input for a particular param) in your IntentHanlder. For example I achieved to do it this way:
FooIntentHandler: NSObject, FooIntentHandling {
func resolveBar(for intent: FooIntent, with completion: @escaping (FooBarResolutionResult) -> Void) {
if let bar = intent.bar as? NSNumber {
var everythingIsFine = false
// Any logic here.
// You can even assign an invalid magic number in your INUIAddVoiceShortcutViewController
// so that your compare it here to see if the user has input anything different.
if everythingIsFine {
completion(FooBarResolutionResult.success(with: bar))
} else {
// With .needsValue() Siri will always ask for user input.
completion(FooBarResolutionResult.needsValue())
}
} else {
completion(FooBarResolutionResult.needsValue())
}
}
}
You can also assign a valid value as the initial one, in which case Siri will accept the param value (without asking for user input) as long as you call FooBarResolutionResult.success()
in your resolve method as shown above.
In short, Siri calls this resolveBar()
to decide whether or not asking for user input.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With