
L'une des fonctionnalités utiles (à mon avis) d'iOS 12 introduites lors de la WWDC 2018 est Siri Shortcuts .
Raccourci ( raccourci ) - une commande rapide, un moyen rapide d'effectuer toute action en contournant le script standard.
Dans vos applications, vous pouvez créer des raccourcis pour certaines actions. Apprenant comment et quand l'utilisateur les met en œuvre, Siri commence intelligemment, au bon moment et au bon endroit, pour lui offrir ces raccourcis et, mieux encore, l'utilisateur peut les appeler avec des phrases qu'il leur attachera! Sous le chat plus.
Comment ça marche
Nous utilisons des applications qui, avec certaines actions, créent et fournissent des raccourcis au système.
Vous pouvez afficher ces raccourcis dans Paramètres → Siri et Rechercher .

La capture d'écran ci-dessus montre les trois derniers raccourcis que le système a détectés dans différentes applications. Si nous cliquons sur le bouton «Plus de raccourcis», nous verrons tous les raccourcis fournis au système par chaque application.
Avec certains paramètres dans le code de création de raccourci, Siri offrira ces raccourcis à l'utilisateur sur l'écran verrouillé, dans le centre de notification et de recherche, en se concentrant sur la fréquence à laquelle nous utilisons ces actions, à quelle heure, sur quels jours de la semaine et où à d'autres facteurs.
Par exemple, si le vendredi soir vous cherchez habituellement des distributeurs automatiques de billets, après vous être entraîné, Siri vous proposera un raccourci avec cette action le vendredi soir.

Nous pouvons ajouter notre commande vocale à chaque raccourci en cliquant sur l'icône " + ".
Nous disons une commande vocale, appuyez sur "Terminé", et maintenant nous pouvons effectuer l'action derrière le raccourci en utilisant la voix via Siri. Il s'avère que l'utilisateur pourra exécuter les fonctionnalités de votre application via Siri sans ouvrir l'application elle-même. Le raccourci avec la phrase est conservé dans "Mes raccourcis".
Création de raccourcis
Pour le développement, nous aurons besoin de Xcode 10 et iOS 12. Au moment de la rédaction, les deux sont au stade bêta .
Un raccourci peut être créé via NSUserActivity
ou via Intent
.
Le premier cas:
L'utilisateur clique sur le raccourci, qui transmet la commande avec les paramètres ( NSUserActivity
) à notre application, et il décide comment cette commande doit être traitée (ouvrez la fenêtre du taux USD actuel, ou la fenêtre de commande de notre pizza préférée). C'est le bon vieux raccourci Spotlight que nous connaissons tous, mais intelligemment proposé par Siri.
Deuxième cas:
Les raccourcis créés via Intent
plus intéressants - ils vous permettent d'exécuter une commande immédiatement dans l'interface Siri sans lancer votre application. Auparavant, l'ensemble des Intent
était difficile pour Apple: transférer de l'argent, envoyer des messages et autres . Maintenant, nous, les développeurs, avons la possibilité de créer nos Intent
!
Quelle que soit la façon dont le raccourci a été créé, il passe par 3 étapes du cycle de vie:
- Annonce ( définir )
- Livraison au système ( Faire un don )
- Traitement par application ( Handle )

Mes recherches ont montré qu'une application ne peut pas fournir plus de 20 raccourcis au système.
De plus, nous examinerons comment donner à notre application la possibilité de créer des raccourcis et comment travailler avec eux à l'intérieur.
Création de raccourcis via NSUserActivity
Analysons le premier type simple de raccourcis qui s'ouvrent via NSUserActivity
.
Par exemple, dans l'application de banque mobile, nous avons un écran de recherche de guichets automatiques et je les cherche souvent. Pour accéder à l'écran avec une carte ATM, je dois lancer l'application, aller dans l'onglet «Plus» de l'onglet, sélectionner la section «Info» et cliquer sur le bouton «ATM».
Si nous créons un raccourci qui mène immédiatement à cet écran, l'utilisateur pourra y accéder d'une seule touche lorsque Siri le lui proposera, par exemple, sur un écran verrouillé.
Déclarer un raccourci
La première étape consiste à déclarer un type comme notre NSUserActivity
(on peut dire que c'est son identifiant) dans info.playlist :
<key>NSUserActivityTypes</key> <array> <string>ru.tinkoff.demo.show-cashMachine</string> </array>
Annoncé.
Fournir le raccourci vers le système (faire un don)
Après la déclaration, nous pouvons créer NSUserActivity
dans le code de notre application avec le type que nous avons défini ci-dessus dans info.playlist :
let activity = NSUserActivity(activityType: "ru.tinkoff.demo.show-cashMachine")
Pour que l'activité entre dans la liste des raccourcis du système, elle doit être définie sur title
et définir la propriété isEligibleForSearch
sur true
. D'autres propriétés ne sont pas nécessaires pour l'ajout aux raccourcis, mais leur présence rend le raccourci plus lisible et convivial.
Feu! NSUserActivity
est, pour le livrer au système, il reste à faire la dernière étape.
ViewConroller
possède une propriété userActivity
, à laquelle nous devons affecter l' activity
créée ci-dessus:
self.userActivity = activity
Dès que cette ligne est exécutée, un raccourci sera créé à partir de cette activité. Il sera livré au système et affiché dans les paramètres Siri ( Paramètres → Siri et Rechercher ). Siri pourra alors l'offrir à l'utilisateur, et l'utilisateur pourra lui attribuer sa commande vocale.
Remarque : la documentation Apple indique qu'au lieu d'affecter une activité au contrôleur de vue, il suffit d'appeler la méthode becomeCurrent()
sur l' becomeCurrent()
. Cependant, cette action n'a pas fourni d'activité à mon système et le raccourci n'apparaissait pas dans la liste
Ensuite, appelez la méthode becomeCurrent()
sur l'objet d'activité utilisateur pour le marquer comme courant, ce qui donne l'activité à Siri. Vous pouvez également attacher l'objet à un objet UIViewController ou UIResponder, qui marque également l'activité comme actuelle.
Pour vérifier que tout a fonctionné, ouvrez Paramètres> Siri et recherchez - le raccourci basé sur notre activité devrait être dans la liste.
Traitement des raccourcis par application (poignée)
Lorsqu'un utilisateur navigue dans le raccourci depuis le centre de notifications ou l'active par la voix, l'application démarre et nous devons traiter ce raccourci.
activity
lancée dans AppDelegate
'une méthode:
func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool { if userActivity.activityType == "ru.tinkoff.demo.show-cashMachine" {
Total
Un NSUserActivity
NSUserActivity est créé comme suit:
- Déclarez le type (identifiant) de
NSUserActivity
dans NSUserActivity
. - Nous créons
NSUserActivity
dans le code et nous configurons viewController'
.
Création de commandes vocales à partir d'une application
Ainsi, si l'utilisateur ouvre Paramètres> Siri et recherche , il verra une liste de ses raccourcis, qui ont été créés par diverses applications, dont la nôtre. En cliquant sur le « + », l'utilisateur peut créer n'importe quelle commande vocale et l'associer au raccourci sélectionné. Cependant, chaque fois que la saisie des paramètres est gênante pour l'utilisateur, beaucoup ne réalisent même pas cette possibilité.
C'est cool que vous puissiez attacher une commande vocale à une action spécifique directement dans l'application.
Supposons qu'un utilisateur effectue une action, qu'elle soit livrée au système, il veut la sauvegarder. Nous pouvons ajouter le bouton « ajouter une action à Siri » (vous pouvez nommer et dessiner le bouton comme vous le souhaitez) sur l'écran de notre application, puis l'utilisateur, en cliquant dessus, pourra associer cette action à une commande vocale depuis l'application sans entrer dans les paramètres.
En cliquant sur le bouton, vous devez ouvrir de façon modale l'écran pour ajouter une commande vocale à un raccourci dans Siri INUIAddVoiceShortcutViewController
, ou l'écran pour modifier une commande vocale INUIEditVoiceShortcutViewController
, s'il en a déjà été créé un. L' action
n'ayant pas réagi action
un tel bouton sera approximativement la suivante:
@IBAction func addToSiriAction() { // 1. , INVoiceShortcutCenter.shared.getAllVoiceShortcuts { (shortcuts, error) in guard error == nil, let shortcuts = shortcuts else { // TODO: Handle error return } // 2. , let donatedShortcut: INVoiceShortcut? = shortcuts.first(where: { (shorcut) -> Bool in return shorcut.__shortcut.userActivity?.activityType == "com.ba" }) if let shortcut = donatedShortcut { // 3. - . // let editVoiceShortcutViewController = INUIEditVoiceShortcutViewController(voiceShortcut: shortcut) editVoiceShortcutViewController.delegate = self self.present(editVoiceShortcutViewController, animated: true, completion: nil) } else { // 4. let shortcut = INShortcut(userActivity: self.userActivity!) let addVoiceShortcutViewController = INUIAddVoiceShortcutViewController(shortcut: shortcut) addVoiceShortcutViewController.delegate = self } } }
Ainsi, les écrans pour ajouter et modifier une commande vocale pour le raccourci Siri ressemblent:

Nous devons également implémenter les méthodes déléguées de ces viewControllers, dans lesquelles ils doivent masquer le dismiss(animated: true, completion: nil)
et, si nécessaire, mettre à jour l'écran actuel. Par exemple, s'il y avait un bouton «ajouter une commande vocale» sur l'écran plus tôt, alors après avoir ajouté une commande vocale, ce bouton devrait soit disparaître, soit passer à «modifier la commande vocale».
Raccourcis d'intention
Jusqu'à présent, nous n'avons parlé que de raccourcis qui ouvrent une application et y transmettent NSUserActivity
données à NSUserActivity
.
Mais revenons aux raccourcis créés via Intent
, qui vous permettent d'effectuer certaines actions sans ouvrir l'application. Ici, le plaisir commence.
Imaginez qu'un utilisateur commande sa pizza préférée. Il le commandera plusieurs fois quand il le voudra, et il a même ajouté une commande vocale au raccourci de cette pizza - et cela lui simplifie la vie. Mais nous pouvons faire plus pour lui - nous pouvons nous assurer qu'en donnant la commande vocale Siri, le système ne la jette pas dans l'application, mais affiche immédiatement les informations de commande et les commandes de pizza dans l'interface Siri! C'est juste le cas lorsque l'utilisateur n'a pas besoin d'ouvrir l'application elle-même pour effectuer une action.
Tout d'abord, accédez aux paramètres du projet, sélectionnez la cible principale, l'onglet Capabilities
et activez l'accès à Siri.
Notre application peut interagir avec Siri, mais cela ne se produit pas dans le code principal de l'application, mais dans une extension cible distincte Intents Extensions
Pour commencer, cette cible doit être créée: Fichier → Nouveau → Cible , sélectionnez Intentions Extensions . Xcode vous proposera de créer une autre extension cible pour la fenêtre affichant vos actions dans Siri, si cela est nécessaire, nous sommes d'accord.

Déclarer un raccourci
La principale innovation de SiriKit dans iOS 12 est la possibilité de créer vos Inetnts
, à ceux qui étaient plus tôt.

Pour ce faire, créez un nouveau fichier: Fichier → Nouveau → Fichier , en sélectionnant Fichier de définition d'intention SiriKit dans la section Ressources .

En conséquence, un fichier avec l'extension .intentdefinition apparaît , dans lequel vous pouvez créer vos propres Intents
. Nous ouvrons le fichier, et là où il est dit " Pas d'intention " en bas, il y a une icône " + " - cliquez dessus. " Nouvelle intention ". Une intention apparaîtra dans la liste à laquelle vous pouvez ajouter des paramètres. Dans le cas d'une commande de pizza, vous pouvez ajouter le nombre de pizzas et le type de pizza à commander comme paramètres. Pour la quantité, nous choisissons le type Integer
et pour le type de pizza, nous sélectionnons le type Custom
, qui dans le code sera représenté par la classe INObject
.
Maintenant quelques lignes de frustration:
L'utilisateur ne pourra pas transmettre différents paramètres à la même commande vocale enregistrée. Hélas!

Quels sont les paramètres pour:
Supposons que vous créez une entité "Show rate %currency
", où la currency
est un paramètre d'entité. Cela ne signifie pas que l'utilisateur peut dire les phrases "Afficher le taux de change du dollar", "Afficher le taux de change Bitcoin", etc. Hors de la boîte, cela ne fonctionnera pas comme ça. Mais cela signifie que si l'utilisateur a regardé le taux de change du dollar, le raccourci "Afficher le taux USD" a été créé, puis lorsqu'il a regardé le taux de change Bitcoin, le raccourci "Afficher le taux BTC" a été créé, etc. En d'autres termes, il peut avoir plusieurs shorkatas basés sur la même intention, mais avec des paramètres différents. Chacun des raccourcis, l'utilisateur pourra demander sa commande vocale.
Eh bien, en créant une intention dans le fichier .intentdefinition , Xcode générera automatiquement une classe pour cette intention (remarque: elle n'apparaîtra pas dans les fichiers de projet, mais sera disponible pour utilisation). Ce fichier généré automatiquement ne se trouvera que dans les cibles qui ont le fichier .intentdefinition .
Après avoir créé l'intention dans le fichier .intentdefinition , nous pouvons créer nos intentions dans le code.
let intent = OrderPizzaIntent()
Fournir le raccourci vers le système (faire un don)
Pour que cette entité soit incluse dans la liste des raccourcis, vous devez l'intégrer. Pour ce faire, un objet INInteraction
est créé avec une instance de votre intention et la méthode .donate est appelée sur cette .donate
let intent = OrderPizzaIntentf() // ... let interaction = INInteraction(intent: intent, response: nil) interaction.donate { (error) in // ... / }
Après avoir exécuté ce code, le raccourci basé sur l'intention sera fourni au système et affiché dans les paramètres Siri.
Nous traitons l'application de raccourci (Handle)
L'étape suivante consiste à traiter l'intention lorsque l'utilisateur clique dessus dans le sirjest du Siri ou l'appelle avec une commande vocale.
Nous avons déjà créé une extension cible pour Siri et elle a une classe IntentHandler pré-créée, qui a une seule méthode - `` gérer (pour l'intention) ''
class IntentHandler: INExtension { override func handler(for intent: INIntent) -> Any { guard intent is OrderPizzaIntent else { fatalError("Unhandled intent type: \(intent)") } return OrderPizzaIntentHandler() } }
Remarque: Si le compilateur ne voit pas la classe de votre intention, vous n'avez pas ajouté le fichier d'extension cible .intentdefinition pour Siri.
Dans cette méthode, nous déterminons le type d'intention entrante et pour chaque type, nous créons un objet gestionnaire qui traitera cette intention. Créez un gestionnaire pour notre OrderPizzaIntent
et implémentez-y le protocole OrderPizzaIntentHandling
, qui est déjà généré automatiquement après la création de votre intention dans .intentdefinition .
Le protocole contient deux méthodes de confirm
et de handle
. Tout d'abord, confirm
est appelé où toutes les données sont vérifiées et la disponibilité de l'action est vérifiée. Ensuite, la handle
fonctionnera en une courte action à effectuer.
public class OrderPizzaIntentHandler: NSObject, OrderPizzaIntentHandling { public func confirm(intent: OrderPizzaIntent, completion: @escaping (OrderPizzaIntentResponse) -> Void) {
Ces deux méthodes doivent définitivement appeler la completion
avec la réponse OrderPizzaIntentResponse
(elle est également générée automatiquement), sinon Siri attendra juste longtemps et donnera une erreur.
Des réponses plus détaillées de Siri
Il existe un ensemble standard de codes de réponse générés automatiquement - enum OrderPizzaIntentResponseCode
, mais ils peuvent ne pas être suffisants pour une interface conviviale. Par exemple, au stade de la confirm
, plusieurs erreurs différentes peuvent se produire - la pizza est épuisée, la pizzeria ne fonctionne pas pour le moment, etc. et l'utilisateur doit se renseigner sur ces faits, au lieu du message standard "Erreur d'application". N'oubliez pas que nous avons créé Intent
dans le fichier .intentdefinition ? Avec l'intention elle-même, sa Response
dans laquelle vous pouvez ajouter vos propres options d'erreurs et de réponses réussies, et les configurer avec les paramètres:

Maintenant, nous pouvons dire à l'utilisateur des erreurs et des réponses plus informatives:
public func confirm(intent: OrderPizzaIntent, completion: @escaping (OrderPizzaIntentResponse) -> Void) { guard let pizzaKindId = intent.kind?.identifier else { // - completion(OrderPizzaIntentResponse(code: .failure, userActivity: nil)) return } if pizzeriaManager.isPizzeriaClosed == true { /// - completion(OrderPizzaIntentResponse(code: .failurePizzeriaClosed, userActivity: nil)) return } else if pizzeriaManager.menu.isPizzaUnavailable(identifier: pizzaKindId) { /// - completion(OrderPizzaIntentResponse(code: .failurePizzaUnavailable(kind: intent.kind), userActivity: nil)) return } // - completion(OrderPizzaIntentResponse(code: .ready, userActivity: nil)) }
Rendu Intent
Si nous avons créé une extension cible d' interface utilisateur d'extension d'intention , nous pouvons dessiner une vue personnalisée dans Siri pour les intentions dont nous avons besoin. Nous avons MainInterface.storyboard
et IntentViewController
dans lesquels nous pouvons esquisser leur conception. Ce contrôleur de vue implémente le protocole INUIHostedViewControlling et la vue est configureView
dans la méthode configureView
// Prepare your view controller for the interaction to handle. func configureView(for parameters: Set<INParameter>, of interaction: INInteraction, interactiveBehavior: INUIInteractiveBehavior, context: INUIHostedViewContext, completion: @escaping (Bool, Set<INParameter>, CGSize) -> Void) { // Do configuration here, including preparing views and calculating a desired size for presentation. completion(true, parameters, self.desiredSize) } var desiredSize: CGSize { return self.extensionContext!.hostedViewMaximumAllowedSize }
Pour que cette méthode soit appelée, vous devez ajouter le nom de notre intention au tableau NSExtension
-> NSExtensionAttributes
-> IntentsSupported
, qui fait référence à l'interface utilisateur Intents cible de l'extension
<key>NSExtension</key> <dict> <key>NSExtensionAttributes</key> <dict> <key>IntentsSupported</key> <array> <string>OrderPizzaIntent</string> </array> </dict>
Selon la conception de votre vue dans Siri et l' interaction.intent
qui a été intégrée à la méthode, vous pouvez dessiner cette vue comme vous le souhaitez. Voici des captures d'écran de l'apparence de notre intention dans Siri, dans la recherche et sur un écran verrouillé.

Il convient de noter que l'utilisateur ne pourra pas interagir avec les boutons, le défilement et d'autres contrôles de votre vue, car la méthode est appelée avec le paramètre interactiveBehavior = .none
, cela impose certainement un certain nombre de limitations.
Total
Un raccourci basé sur l' Intent
peut s'afficher dans l'interface siri ou dans le centre de notifications et effectuer une action sans ouvrir l'application. Pour le créer, vous avez besoin de:
- Activer les capacités pour utiliser Siri
- Créer des extensions d' intentions et une interface d'extensions d'intentions
- Créer un fichier de définition d'intention SiriKit
- Nous créons notre
Intent
dans ce fichier et nous lui attribuons des paramètres. - Créer un
IntentHandler
dans lequel nous implémentons les hanlde
et hanlde
Recommandations
Code générique dans la cible d'extension Siri et l'application principale
Si vous avez du code utilisé à la fois dans la cible pour Siri et dans la cible du projet principal - il existe 2 façons de résoudre ce problème:
- Mettez en surbrillance les classes communes et ajoutez-les aux deux cibles. ( Affichage → Utilitaires → Afficher l'inspecteur de fichiers ', dans la section Appartenance à la cible , ajoutez des coches aux cibles qui ont besoin d'accéder au fichier sélectionné)
- Créez un ou plusieurs frameworks cibles et prenez le code général là-bas.
Cette dernière méthode est préférable, car vous pouvez ensuite utiliser ces cadres dans d'autres extensions et projets. Il convient également de noter que pour ces frameworks, il est conseillé de définir l'indicateur Allow app extension API only
, puis, lors du développement du framework, le compilateur jurera si vous essayez d'utiliser une API qui est illégale dans le développement d'extensions (par exemple, UIApplication
).
Les ressources partagées peuvent être recherchées entre les cibles via des groupes d'applications
Débogage
Tester les raccourcis vous aidera à:
- Paramètres du téléphone Paramètres → Développeur : afficher les raccourcis récents et afficher les dons sur les commutateurs de l' écran de verrouillage :

- Pour tester Intens, vous pouvez immédiatement lancer l'extension cible en spécifiant dans Xcode la phrase avec laquelle Siri s'ouvre. Pour ce faire, sélectionnez le schéma de l'extension cible Siri

Cliquez sur cette cible, cliquez sur Modifier le schéma ...

Dans le champ Siri Intent Query , entrez une phrase avec laquelle Siri commencera déjà, comme si vous l'aviez déjà dit.
Total
Je propose d'arrêter et de résumer ce que nous avons fait:
- Les raccourcis peuvent être créés via
NSUserActivity
ou via INIntent
- Les raccourcis doivent être déclarés (déclarer), signalés au système (don) et traités (gérer).
- Vous pouvez ajouter le bouton " Ajouter à Siri " à l'application, en cliquant sur lequel l'utilisateur peut ajouter une phrase pour l'action et l'appeler ensuite avec sa voix.
- Vous pouvez créer vos propres
Intents
en plus de la fonction intégrée. - Grâce aux
Intents
basés sur Intents Intents
vous pouvez créer des actions qui seront effectuées via l'interface Siri (sur un écran verrouillé ou en recherche) sans avoir à ouvrir l'application elle-même.
Dans la documentation Apple, il y a un lien vers le projet Demo , qui est utile pour le télécharger et se concentrer dessus pendant le développement.
Je tiens à souligner qu'au moment de la rédaction de cet article, il s'agit d'une API au stade beta
. Et j'attrape souvent des problèmes et des bugs. Pendant le travail, je rencontrais périodiquement les éléments suivants:
- , Intent Siri, .
- Siri .
- Siri.
Les références
- WWDC 2018, session 211: Introduction to Siri Shortcuts
- WWDC 2018, session 214: Building for Voice with Siri Shortcuts
- Apple Developer: SiriKit
- Apple Developer: INUIHostedViewControlling
- Demo Soup Chef Apple