Suppose I'm making an app that a user can install several little interactive experiences (meditations) onto.
For convenience, I'd like my users to be able to start one by saying: “Hey Siri, start Beach Sunset in Meditations.”
Because of reasons, it makes sense for users to perform this action by voice, without ever first having interacted with Beach Sunset in the iOS app. (They may for example already “own” it through my service's web app.)
That is to say: I want a voice action like “Hey Siri, start Beach Sunset in Meditations” to work even without the user setting up a Shortcut for it first, or me “donating” actions for it.
Is that possible? (I feel like many of the default apps expose similar behavior, but maybe they're special.) If not, what is the next best thing I can do?
Are "donations" necessary for Siri to be aware of my app's voice actions, or are they simply a mechanism for hinting and predicting user behavior?
Are "shortcuts" necessary for Siri to be aware of my app's voice actions, or are they simply a mechanism for user phrase customization?
I've never added Siri support to an iOS app, but it seems “parameters” have gotten a lot more powerful in iOS 13. This answer suggests something similar wasn't possible in iOS 12, but I think it's also doing something somewhat different (I want to launch the app; they want to “create an object” presumably just using Intent UI. I don't know if this matters.)
What I've done
I've defined a custom intent in the Start category (LaunchMeditation
) with a single parameter (meditationName
).
I considered the standard Media intents, but the media here is interactive and not strictly audio/video, and I don't want to get in trouble.
I've added an Intents Extension to my app, and written a rudimentary test "handler" that just tries to pass the meditation name on to the app:
@interface IntentHandler () <LaunchMeditationIntentHandling>
@end
@implementation IntentHandler
- (id)handlerForIntent:(INIntent *)intent { return self; }
- (void)handleLaunchMeditation:(nonnull LaunchMeditationIntent *)intent
completion:(nonnull void (^)(LaunchMeditationIntentResponse * _Nonnull))completion {
// XXX: Maybe activity can just be nil?
NSUserActivity *activity = [[NSUserActivity alloc] initWithActivityType:@"com.example.meditations.activity.launch"];
activity.title = [NSString stringWithFormat:@"Launch %@ in Meditations", intent.meditationName]; // Do I need this?
activity.userInfo = @{@"meditationName": intent.meditationName};
completion([[LaunchMeditationIntentResponse alloc] initWithCode:LaunchMeditationIntentResponseCodeContinueInApp
userActivity:activity]);
}
- (void)resolveMeditationNameForLaunchMeditation:(nonnull LaunchMeditationIntent *)intent
withCompletion:(nonnull void (^)(INStringResolutionResult * _Nonnull))completion {
completion([INStringResolutionResult successWithResolvedString:intent.meditationName]);
}
@end
When I test the Intents Extension, I can now make a Shortcut for it in Shortcuts, set its parameter, give it a name (like “Beach time”), and launch it by telling Siri that name — which is everything I don't want users to have to do.
Other than that, Siri responds with
Meditations hasn't added support for that with Siri.
…no matter how I phrase my request to start Beach Sunset. That “hasn't added support” sounds agonizingly much like there's simply something I'm missing.