Intégrer SiriKit dans votre application

le 31/05/2018 par Jordhan Léoture
Tags: Software Engineering

Une machine qui parle ... ce n’est pas nouveau me direz-vous. En effet le premier Mac le fait depuis 1984. Certes, à l’époque il ne s'agissait “que” d’un synthétiseur vocal. Maintenant on parle d’assistant vocal capable de réaliser des tâches relativement complexes.

Aujourd’hui la voix est une IHM à part entière et le marché des enceintes dotées d’un assistant vocal relance l'intérêt de la commande vocale pour nos applications mobiles.

Faisons les présentations

Dis Siri, qui es-tu?

Au risque d’en décevoir certains, l’assistant vocal d’Apple n’est pas très bavard. Quand je pose cette question à mon iPhone, il me répond “Je suis Siri. Mais je m’égare… Comment puis-je vous aider?". Contrairement à Siri, égarons nous un instant ! Un peu d’histoire ne fait jamais de mal.

En 2007 naît la startup Siri, qui publie en 2010 sur l'App Store l’application du même nom, dotée d’un assistant vocal. Cette même année Apple rachète la startup et intègre Siri dès 2011 dans iOS 5. Ce n’est qu’en 2016 (iOS 10) qu’Apple fournit une API, SiriKit, permettant au développeurs d'intégrer Siri dans leurs applications. Aujourd'hui l’assistant vocal est présent sur tous les devices proposés par Apple et SiriKit est disponible sur iOS et watchOS.

SiriKit

SiriKit permet à votre application de communiquer avec Siri via des Intents. Un Intent est un objet que Siri construit après avoir analysé votre requête vocale. Par exemple lors de la demande “Envoie bonjour à Bob dans l’application MyMessenger”, Siri va créer un Intent INSendMessageIntent, avec “Bonjour” comme content et “Bob” comme recipient, puis le transmettre à l’application MyMessenger.

Les Intents sont regroupés par Domains. Ces derniers se sont étoffés au cours du temps mais restent limités :

  • Lists - Créer et gérer des notes et des to do lists.
  • Visual codes - Afficher un QR Code.
  • Ride booking - Réserver et gérer les réservations de VTC.
  • Messaging - Envoyer des messages.
  • Photo search - Chercher et afficher des photos.
  • Payments - Effectuer et gérer des paiements.
  • VoIP calling - Effectuer des appels téléphoniques.
  • Workouts - Gérer des activités sportives.
  • Car commands - Gérer les portes et l’état d’une voiture.
  • CarPlay - Interagir avec CarPlay intégré dans un véhicule (radio, climatisation, etc).
  • Restaurant reservations - Réserver et gérer les réservations de restaurants.

Messaging et Lists sont pour l’instant les deux seuls Domains compatibles entre l’HomePod et iOS.

SiriKit ne se démarque pas par le nombre de possibilités d’usage mais plutôt par son intégration relativement simple.

Intégrer SiriKit

Préparer son application

SiriKit supporte deux types d’extensions :

  • Intents app extension qui transmet à votre application les requêtes de l'utilisateur sous forme d’Intents.
  • Intents UI app extension qui permet d’afficher et de customiser l’interface de réponse pour l'utilisateur.

Dans cet article nous nous intéresserons uniquement à la première extension.

Avant d’intégrer l’extension, il est préférable de structurer correctement son application. Il faut créer un framework partagé entre votre application et votre extension, qui contiendra les services requis de part et d’autre.

L’App Store exige que Siri soit activé dans les Capabilities pour les applications contenant une Intents app extension. Je tiens à préciser qu’il faut absolument avoir un compte Apple developer pour pouvoir l’activer. Il est possible de vérifier les Capabilities activables en fonction de son type d'enrôlement sur ce site.

Pour permettre l’usage de Siri par l’application il faudra en demander l’accord à l’utilisateur.

Pour cela, la clé NSSiriUsageDescription, dont la valeur correspondra au texte affiché lors de la demande de permission, doit être rajoutée dans le fichier info.plist.

Ensuite, la demande de permission avec la méthode requestSiriAuthorization est effectuée comme ceci :

Voir le lien github

Maintenant que l’application est correctement structurée et respecte les prérequis pour l’App Store, l’Intents App Extension peut être ajoutée.

Ajout et paramétrage de l’extension

Afin d’ajouter une Intents App Extension, une nouvelle target doit être créée en sélectionnant Intents Extension.

Une fois la target créée, le fichier info.plist de l’extension doit renseigner les clés :

  • IntentsSupported : les intents qui seront supportés par l’application.
  • IntentsResctrictedWhileLocked : les intents qui requièrent que le device soit déverrouillé avant d’être transmis à l’application.

Pour la suite j’ai choisi de prendre comme exemple une application de gestion de tâches. Cette application, nommée DoIt, sera capable de répondre à deux types de requêtes:

  • Afficher l’ensemble de mes listes de tâches.

    • Requête 1 : “Montre moi mes listes de tâches dans DoIt”
  • Afficher uniquement une liste spécifique de tâches.

    • Requête 2 : “Montre moi les tâches de ma liste importante dans DoIt”

Ces deux requêtes seront utilisées afin de pouvoir tester l’intégration de l’extension. Afin que l’application puisse les prendre en compte, INSearchForNotebookItemsIntent doit être supporté.

Traitement des intents

Handler

Voir le lien github

Le point d’entrée de l’extension est l’IntentHandler. A chaque fois que Siri transmet un Intent à l’application, il le fait via la méthode handler. Ici, seuls les Intents de type INSearchForNotebookItemsIntent sont traités. Chaque type d’Intent attend en retour un handler conforme au protocol associé.

Par exemple, INSearchForNotebookItemsIntent requiert en retour un objet conforme au protocol INSearchForNotebookItemsIntentHandling.

Je préciserai un peu plus tard le rôle de SearchForNotebookItemsIntentHandler (conforme à INSearchForNotebookItemsIntentHandling).

Afin de simplifier la phase de debug, il est possible de spécifier la requête à effectuer après un Run comme ceci :

Cycle de vie d’un Intent

Voir le lien github

INSearchForNotebookItemsIntent possède plusieurs paramètres, visibles ci-dessus. En fonction des requêtes de l’utilisateur, Siri sera en mesure de compléter (ou non) ces paramètres. Par exemple :

  • Pour la requête 1 “Montre moi mes listes de tâches dans DoIt”
    • ItemType aura pour valeur taskList
    • status, locationSearchType et dateSearchType auront pour valeur unknown
    • title, content, location, dateTime seront nil
  • Pour la requête 2 “Montre moi les tâches de ma liste importante dans DoIt”
    • ItemType aura pour valeur task
    • title aura pour valeur importante
    • status, locationSearchType et dateSearchType auront pour valeur unknown
    • content, location, dateTime seront nil

Les paramètres itemType et title permettent de distinguer ces deux types de requêtes. Cependant il se peut que des requêtes soient moins précises, Siri pourrait alors ne pas être capable de remplir l’Intent correctement. C’est là que SearchForNotebookItemsIntentHandler entre en jeu.

SearchForNotebookItemsIntentHandler implémente les 3 étapes que va subir l’Intent : la résolution, la confirmation et la manipulation.

Etape 1 : résolution

Cette première étape consiste à aider Siri à comprendre les valeurs fournies par l’utilisateur et d’influencer son comportement ainsi que de proposer des valeurs de réponses déduites.

Pour chaque paramètre de l’Intent une méthode resolve est associée. Par exemple pour résoudre itemType il faut implémenter la méthode resolveItemType.

Voir le lien github

Voir le lien github

Chacune de ces méthodes prennent en paramètre l’Intent concerné et un bloc de complétion. Siri exécutera une première méthode resolve et attendra que le bloc de complétion soit exécuté. Ensuite il passera à la méthode de résolution suivante ou interagira avec l’utilisateur en fonction de l’argument passé au completion.

Pour resolveItemType le bloc de complétion attend un INNotebookItemTypeResolutionResult. Plusieurs valeurs sont possibles, Siri agira en fonction de chacune de ces valeurs :

  • needValue : L’utilisateur sera invité à préciser la valeur.
  • notRequired : La valeur ne sera pas prise en compte, Siri passera à la prochaine méthode resolve.
  • unsupported : Siri indiquera que la requête n’est pas supportée.
  • confirmationRequired : L’utilisateur devra valider la valeur que l’application lui aura transmise.
  • disambiguation : L’utilisateur devra choisir une valeur parmis les valeurs que l’application lui aura transmise.
  • success : la valeur renseignée à été correctement prise en compte, Siri passera à la prochaine méthode resolve.

Etape 2 : confirmation

Lors de la confirmation, la cohérence des paramètres de l’Intent et la disponibilité des services sont vérifiées. Par exemple : l’utilisateur a-t-il un compte ? Ici, l’action relative à la requête ne doit pas encore être traitée.

Voir le lien github

Dans l’exemple ci-dessus, la confirmation vérifie que la requête ne soit pas effectuée le week-end. Dans le cas contraire, elle renvoie une erreur.

La réponse est un objet INSearchForNotebookItemsIntentResponse dans lequel on renseigne un code  INSearchForNotebookItemsIntentResponseCode et un NSUserActivity. Elle est ensuite transmise à Siri via le bloc de complétion.

Le code de la réponse à cette étape peut être :

  • unspecified : pas de code spécifique.
  • ready : la prochaine étape, la manipulation, peut être effectuée.
  • failure : la recherche ne peut pas être effectuée.
  • failureRequiringAppLaunch: la recherche nécessite d’ouvrir l’application.

Le userActivity permet à l’application d’adapter son comportement si elle est amené à être lancé par Siri. Je ne détaillerai pas cette objet dans cette article mais vous pouvez toujours vous référer à sa documentation.

Etape 3 : manipulation

Lors de cette dernière étape, l’action relative à l’intent doit être traitée. Elle s’effectue par la méthode handle.

Voir le lien github

Dans le cas présent, l’action est une recherche d'éléments, des tasks de type INTask ou des tasksLists de type INTaskList. Ces éléments sont affectés,  en fonction du type de l’itemType, à une réponse INSearchForNotebookItemsIntentResponse.

A cette étape le code de la réponse peut être :

  • inProgress : la recherche est en cours.
  • failure : la recherche ne peut pas être effectuée.
  • success : la recherche est finie avec succès.

Désormais, le handler est capable de distinguer la recherche d’une liste spécifique ou l’ensemble des listes de tâches et d’agir en conséquent. Les résultats obtenus sont les suivants :

    

Sécurité

Certaines fonctionnalités peuvent nécessiter plus de sécurité qu’un simple déverrouillage du device. En ajoutant le framework Local Authentication, l’application pourra demander à l’utilisateur de s’authentifier grâce à son mot de passe ou son code biométrique (TouchId, FaceId).

Voir le lien github

Conclusion

L’intégration de SiriKit est relativement simple. En effet, Apple a pris le parti de ne laisser au développeur que le traitement des Intents et de confier l'interprétation des requêtes à Siri. Mais parfois l’assistant vocal ne peut tout simplement pas comprendre certains termes spécifiques à l’application. C’est à ce moment qu’intervient la notion de Vocabulaire. De plus, l’UI de Siri peut ne pas être adapté au contenu à afficher. L’Intents UI app extension permet de corriger cela.

Enfin, Siri est relativement limité dans les actions qu’il peut effectuer. Cependant, après l'avancée de ses concurrents sur le marché, on peut espérer une réelle évolution de Siri pour la keynote de juin.

Le code de l’application est disponible sur le repo Github.

Références

Introducing SiriKit : https://developer.apple.com/videos/play/wwdc2016/217/

Extending Your Apps with SiriKit : https://developer.apple.com/videos/play/wwdc2016/225/

What’s New in SiriKit : https://developer.apple.com/videos/play/wwdc2017/214/

Making Great SiriKit Experiences : https://developer.apple.com/videos/play/wwdc2017/228/

Documentation : https://developer.apple.com/documentation/sirikit