Compartir a través de


Implementación de SiriKit en Xamarin.iOS

En este artículo se describen los pasos necesarios para implementar la compatibilidad con SiriKit en aplicaciones de Xamarin.iOS.

Novedad de iOS 10, SiriKit permite que una aplicación Xamarin.iOS proporcione servicios accesibles para el usuario mediante Siri y la aplicación Maps en un dispositivo iOS. En este artículo se describen los pasos necesarios para implementar la compatibilidad con SiriKit en las aplicaciones de Xamarin.iOS agregando las extensiones de intenciones necesarias, extensiones de interfaz de usuario de intenciones y vocabulario.

Siri funciona con el concepto de Dominios, grupos de acciones de conocimiento para tareas relacionadas. Cada interacción de la aplicación con Siri debe incluirse en uno de sus dominios de servicio de la siguiente manera:

  • Llamadas de audio o vídeo.
  • Reservar un viaje.
  • Administrar entrenamientos.
  • Mensajería.
  • Buscar fotos.
  • Enviar o recibir pagos.

Cuando el usuario realiza una solicitud de Siri que implica uno de los servicios de la extensión de aplicación, SiriKit envía a la extensión un objeto Intent que describe la solicitud del usuario junto con los datos auxiliares. A continuación, la extensión de aplicación genera el objeto Response adecuado para laIntención dado, que detalla cómo la extensión puede controlar la solicitud.

En esta guía se presenta un ejemplo rápido de cómo incluir compatibilidad con SiriKit en una aplicación existente. Para este ejemplo, usaremos la aplicación MonkeyChat falsa:

Icono de MonkeyChat

MonkeyChat mantiene su propio libro de contactos de los amigos del usuario, cada uno asociado a un nombre de pantalla (como Bobo, por ejemplo), y permite al usuario enviar chats de texto a cada amigo por su nombre de pantalla.

Extensión de la aplicación con SiriKit

Como se muestra en la guía de Descripción de los conceptos de SiriKit, hay tres partes principales implicadas en la extensión de una aplicación con SiriKit:

Ampliación de la aplicación con el diagrama SiriKit

Entre ellas se incluyen las siguientes:

  1. Extensión Intents: Comprueba las respuestas de los usuarios, confirma que la aplicación puede controlar la solicitud y realiza realmente la tarea para cumplir la solicitud del usuario.
  2. Extensión de interfaz de usuario de Intents - Opcional, proporciona una interfaz de usuario personalizada a las respuestas en el entorno de Siri y puede llevar la interfaz de usuario de las aplicaciones y la personalización de marca a Siri para enriquecer la experiencia del usuario.
  3. Aplicación: Proporciona a la aplicación vocabularios específicos del usuario para ayudar a Siri a trabajar con ella.

Todos estos elementos y los pasos para incluirlos en la aplicación se tratarán en detalle en las secciones siguientes.

Preparación de la aplicación

SiriKit se basa en Extensiones, sin embargo, antes de agregar extensiones a la aplicación, hay algunas cosas que el desarrollador debe hacer para ayudar con la adopción de SiriKit.

Mover código compartido común

En primer lugar, el desarrollador puede mover parte del código común que se compartirá entre la aplicación y las extensiones en Proyectos compartidos, Bibliotecas de clases portables (PCL) o Bibliotecas nativas.

Las extensiones deberán poder hacer todas las cosas que hace la aplicación. En términos de la aplicación MonkeyChat de ejemplo, cosas como buscar contactos, agregar nuevos contactos, enviar mensajes y recuperar el historial de mensajes.

Al mover este código común a un proyecto compartido, PCL o biblioteca nativa, facilita el mantenimiento de ese código en un lugar común y garantiza que la extensión y la aplicación primaria proporcionan experiencias y funcionalidades uniformes para el usuario.

En el caso de la aplicación de ejemplo MonkeyChat, los modelos de datos y el código de procesamiento, como el acceso a la red y la base de datos, se moverán a una Biblioteca nativa.

Haga lo siguiente:

  1. Inicie Visual Studio para Mac y abra la aplicación MonkeyChat.

  2. Haga clic con el botón derecho en el nombre de la solución en el Panel de solución y seleccione Agregar>Nuevo proyecto...:

    Incorporación de proyecto nuevo

  3. SeleccioneiOS>Biblioteca>Biblioteca de clases y haga clic en el botón Siguiente:

    Seleccione Biblioteca de clases.

  4. Escriba MonkeyChatCommon para el Nombre y haga clic en el botón Crear:

    Escriba MonkeyChatCommon como nombre

  5. Haga clic con el botón derecho en la carpeta Referencias de la aplicación principal en el Explorador de soluciones y seleccione Editar referencias.... Compruebe el proyecto MonkeyChatCommon y haga clic en el botón Aceptar:

    Comprobación del proyecto MonkeyChatCommon

  6. En el Explorador de soluciones, arrastre el código compartido común desde la aplicación principal a la Biblioteca nativa.

  7. En el caso de MonkeyChat, arrastre las carpetas DataModels y Procesadores desde la aplicación principal a la biblioteca nativa:

    Carpetas DataModels y Procesadores en el Explorador de soluciones

Edite cualquiera de los archivos que se movieron a la biblioteca nativa y cambie el espacio de nombres para que coincida con el de la biblioteca. Por ejemplo, al cambiar MonkeyChat a MonkeyChatCommon:

using System;
namespace MonkeyChatCommon
{
    /// <summary>
    /// A message sent from one user to another within a conversation.
    /// </summary>
    public class MonkeyMessage
    {
        public MonkeyMessage ()
        {
        }
        ...
    }
}

A continuación, vuelva a la aplicación principal y agregue una instrucción using para el espacio de nombres de la biblioteca nativa en cualquier lugar donde la aplicación use una de las clases que se han movido:

using System;
using System.Collections.Generic;
using UIKit;
using Foundation;
using CoreGraphics;
using MonkeyChatCommon;

namespace MonkeyChat
{
    public partial class MasterViewController : UITableViewController
    {
        public DetailViewController DetailViewController { get; set; }

        DataSource dataSource;
        ...
    }
}

Diseño de la aplicación para extensiones

Normalmente, una aplicación se registrará para varias intenciones y el desarrollador debe asegurarse de que la aplicación está diseñada para el número adecuado de extensiones de intención.

En la situación en la que una aplicación requiere más de una intención, el desarrollador tiene la opción de colocar todo su control de intenciones en una extensión de intención o crear una extensión de intención independiente para cada intención.

Si elige crear una extensión de intención independiente para cada intención, el desarrollador podría terminar duplicando una gran cantidad de código reutilizable en cada extensión y crear una gran cantidad de sobrecarga de procesador y memoria.

Para ayudar a elegir entre las dos opciones, vea si alguna de las intenciones pertenece de forma natural. Por ejemplo, una aplicación que realizó llamadas de audio y vídeo podría querer incluir ambas intenciones en una sola extensión de intención, ya que administran tareas similares y podrían proporcionar la mayor reutilización del código.

Para cualquier intención o grupo de intenciones que no se ajusten a un grupo existente, cree una nueva extensión de intención en la solución de la aplicación para contenerlas.

Establecimiento de los derechos necesarios

Cualquier aplicación de Xamarin.iOS que incluya la integración de SiriKit debe tener establecidos los derechos correctos. Si el desarrollador no establece correctamente estos derechos necesarios, no podrá instalar ni probar la aplicación en hardware real de iOS 10 (o superior), que también es necesario, ya que el simulador de iOS 10 no es compatible con SiriKit.

Haga lo siguiente:

  1. Haga doble clic en el archivo Entitlements.plist en el Explorador de soluciones para abrirlo para su edición.

  2. Cambie a la pestaña Source (Origen).

  3. Agregue la com.apple.developer.siri propiedad , establezca el tipo en Boolean y el valor en Yes:

    Agregue la propiedad com.apple.developer.siri

  4. Guarde los cambios en el archivo.

  5. Haga doble clic en el Archivo de proyecto en el Explorador de soluciones para abrirlo para su edición.

  6. Seleccione Firma de lotes de iOS y asegúrese de que el archivo Entitlements.plist esté seleccionado en el campo Derechos personalizados:

    Seleccione el archivo Entitlements.plist en el campo Derechos personalizados

  7. Haga clic en el botón Aceptar para guardar los cambios.

Cuando termine, el archivo Entitlements.plist de la aplicación debe tener un aspecto similar al siguiente (abierto en un editor externo):

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>com.apple.developer.siri</key>
    <true/>
</dict>
</plist>

Aprovisionamiento correcto de la aplicación

Debido a la estricta seguridad que Apple ha colocado alrededor del marco SiriKit, cualquier aplicación de Xamarin.iOS que implemente SiriKit debe tener el identificador de aplicación y los derechos correctos (vea la sección anterior) y debe estar firmado con un perfil de aprovisionamiento adecuado.

Haga lo siguiente en el equipo Mac:

  1. En un explorador web, vaya a https://developer.apple.com e inicie sesión en su cuenta.

  2. Haga clic en Certificados, Identificadores y Perfiles.

  3. Seleccione Perfiles de aprovisionamiento y seleccione Identificadores de aplicación, y a continuación, haga clic en el + botón.

  4. Escriba un Nombre para el nuevo perfil.

  5. Escriba un Id. de lote siguiendo la recomendación de nomenclatura de Apple.

  6. Desplácese hacia abajo hasta la sección App Services, seleccione SiriKit y haga clic en el botón Continuar:

    Seleccione SiriKit

  7. Compruebe toda la configuración y, a continuación, Enviar el identificador de la aplicación.

  8. Seleccione Perfiles de aprovisionamiento>Desarrollo, haga clic en el botón +, seleccione el Id. de Apple, y haga clic en Continuar.

  9. Haga clic en Seleccionar Todo, y a continuación, haga clic en Continuar.

  10. Haga clic en Seleccionar todo de nuevo y, a continuación, haga clic en Continuar.

  11. Escriba un Nombre de perfil con sugerencias de nomenclatura de Apple y haga clic en Continuar.

  12. Inicie Xcode.

  13. En el menú Xcode, seleccione Preferencias…

  14. Seleccione Cuentas, y haga clic en el botón Ver detalles… :

    Seleccionar Cuentas

  15. Haga clic en el Descargar todos los perfiles Botón en la esquina inferior izquierda:

    Descargar todos los perfiles

  16. Asegúrese de que el Perfil de aprovisionamiento creado anteriormente se ha instalado en Xcode.

  17. Abra el proyecto para agregar compatibilidad con SiriKit a en Visual Studio para Mac.

  18. Haga doble clic en el Info.plistarchivo en elExplorador de soluciones.

  19. Asegúrese de que el Identificador de agrupación coincide con el creado en el Portal para desarrolladores de Apple anterior:

    Identificador de agrupación

  20. En el Explorador de soluciones, seleccione Proyecto.

  21. Haga clic con el botón derecho en el proyecto y seleccione Opciones.

  22. Seleccione Firma de paquetes de iOS, seleccione la Identidad de firma y Perfil de aprovisionamiento creado anteriormente:

    Seleccione la identidad de firma y el perfil de aprovisionamiento

  23. Haga clic en el botón Aceptar para guardar los cambios.

Importante

Probar SiriKit solo funciona en un dispositivo de hardware iOS 10 real y no en el simulador de iOS 10. Si tiene problemas al instalar una aplicación de Xamarin.iOS habilitada para SiriKit en hardware real, asegúrese de que los derechos necesarios, el identificador de aplicación, el identificador de firma y el perfil de aprovisionamiento se han configurado correctamente en el Portal para desarrolladores de Apple y Visual Studio para Mac.

Solicitud de autorización de Siri

Antes de que la aplicación agregue cualquier vocabulario específico del usuario o las extensiones de intenciones se conecta a Siri, debe solicitar autorización del usuario para acceder a Siri.

Edite el archivo de Info.plist la aplicación, cambie a la vista Origen y agregue la NSSiriUsageDescription clave con un valor de cadena que describa cómo usará Siri y qué tipos de datos se enviarán. Por ejemplo, la aplicación MonkeyChat podría decir "Los contactos de MonkeyChat se enviarán a Siri":

NSSiriUsageDescription en el editor de Info.plist

Llame al RequestSiriAuthorization método de la INPreferences clase cuando se inicie la aplicación por primera vez. Edite el archivo AppDelegate.cs y haga que el método FinishedLaunching se parezca a lo siguiente:

using Intents;
...

public override bool FinishedLaunching (UIApplication application, NSDictionary launchOptions)
{

    // Request access to Siri
    INPreferences.RequestSiriAuthorization ((INSiriAuthorizationStatus status) => {
        // Respond to returned status
        switch (status) {
        case INSiriAuthorizationStatus.Authorized:
            break;
        case INSiriAuthorizationStatus.Denied:
            break;
        case INSiriAuthorizationStatus.NotDetermined:
            break;
        case INSiriAuthorizationStatus.Restricted:
            break;
        }
    });

    return true;
}

La primera vez que se llama a este método, se muestra una alerta que solicita al usuario que permita que la aplicación acceda a Siri. El mensaje que el desarrollador agregó al NSSiriUsageDescription anterior se mostrará en esta alerta. Si el usuario deniega inicialmente el acceso, puede usar la aplicación Configuración para conceder acceso a la aplicación.

En cualquier momento, la aplicación puede comprobar la capacidad de la aplicación para acceder a Siri llamando al SiriAuthorizationStatus método de la INPreferences clase.

Localización y Siri

En un dispositivo iOS, el usuario puede seleccionar un idioma para Siri diferente y, a continuación, el valor predeterminado del sistema. Al trabajar con datos localizados, la aplicación deberá usar el SiriLanguageCode método de la INPreferences clase para obtener el código de idioma de Siri. Por ejemplo:

var language = INPreferences.SiriLanguageCode();

// Take action based on language
if (language == "en-US") {
    // Do something...
}

Agregar vocabulario específico del usuario

El vocabulario específico del usuario va a proporcionar palabras o frases exclusivas de usuarios individuales de la aplicación. Estos se proporcionarán en tiempo de ejecución desde la aplicación principal (no las extensiones de aplicación) como un conjunto ordenado de términos, ordenados en una prioridad de uso más significativa para los usuarios, con los términos más importantes al principio de la lista.

Vocabulario específico del usuario debe pertenecer a una de las siguientes categorías:

  • Nombres de contacto (no administrados por el marco de contactos).
  • Etiquetas de fotos.
  • Nombres de álbumes de fotos.
  • Nombres de entrenamiento.

Al seleccionar terminología para registrarse como vocabulario personalizado, solo elija términos que alguien no conozca la aplicación podría malinterpretar. Nunca registre términos comunes como "Mi entrenamiento" o "Mi álbum". Por ejemplo, la aplicación MonkeyChat registrará los alias asociados a cada contacto en la libreta de direcciones del usuario.

La aplicación proporciona el vocabulario específico del usuario llamando al SetVocabularyStrings método de la INVocabulary clase y pasando una NSOrderedSet colección desde la aplicación principal. La aplicación siempre debe llamar al RemoveAllVocabularyStrings método primero para quitar los términos existentes antes de agregar otros nuevos. Por ejemplo:

using System;
using System.Linq;
using System.Collections.Generic;
using Foundation;
using Intents;

namespace MonkeyChatCommon
{
    public class MonkeyAddressBook : NSObject
    {
        #region Computed Properties
        public List<MonkeyContact> Contacts { get; set; } = new List<MonkeyContact> ();
        #endregion

        #region Constructors
        public MonkeyAddressBook ()
        {
        }
        #endregion

        #region Public Methods
        public NSOrderedSet<NSString> ContactNicknames ()
        {
            var nicknames = new NSMutableOrderedSet<NSString> ();

            // Sort contacts by the last time used
            var query = Contacts.OrderBy (contact => contact.LastCalledOn);

            // Assemble ordered list of nicknames by most used to least
            foreach (MonkeyContact contact in query) {
                nicknames.Add (new NSString (contact.ScreenName));
            }

            // Return names
            return new NSOrderedSet<NSString> (nicknames.AsSet ());
        }

        // This method MUST only be called on a background thread!
        public void UpdateUserSpecificVocabulary ()
        {
            // Clear any existing vocabulary
            INVocabulary.SharedVocabulary.RemoveAllVocabularyStrings ();

            // Register new vocabulary
            INVocabulary.SharedVocabulary.SetVocabularyStrings (ContactNicknames (), INVocabularyStringType.ContactName);
        }
        #endregion
    }
}

Con este código en su lugar, podría llamarse de la siguiente manera:

using System;
using System.Threading;
using UIKit;
using MonkeyChatCommon;
using Intents;

namespace MonkeyChat
{
    public partial class ViewController : UIViewController
    {
        #region AppDelegate Access
        public AppDelegate ThisApp {
            get { return (AppDelegate)UIApplication.SharedApplication.Delegate; }
        }
        #endregion

        #region Constructors
        protected ViewController (IntPtr handle) : base (handle)
        {
            // Note: this .ctor should not contain any initialization logic.
        }
        #endregion

        #region Override Methods
        public override void ViewDidLoad ()
        {
            base.ViewDidLoad ();

            // Do we have access to Siri?
            if (INPreferences.SiriAuthorizationStatus == INSiriAuthorizationStatus.Authorized) {
                // Yes, update Siri's vocabulary
                new Thread (() => {
                    Thread.CurrentThread.IsBackground = true;
                    ThisApp.AddressBook.UpdateUserSpecificVocabulary ();
                }).Start ();
            }
        }

        public override void DidReceiveMemoryWarning ()
        {
            base.DidReceiveMemoryWarning ();
            // Release any cached data, images, etc that aren't in use.
        }
        #endregion
    }
}

Importante

Siri trata el vocabulario personalizado como sugerencias e incorporará la mayor parte de la terminología posible. Sin embargo, el espacio para vocabulario personalizado es limitado, lo que hace que sea importante registrar solo la terminología que podría resultar confusa, por lo que se mantiene el número total de términos registrados en un mínimo.

Para obtener más información, vea nuestra Referencia de vocabulario específico del usuario y la Especificación de referencia de vocabulario personalizado de Apple.

Agregar vocabulario específico de la aplicación

El vocabulario específico de la aplicación define las palabras y frases específicas que conocerán todos los usuarios de la aplicación, como tipos de vehículo o nombres de entrenamiento. Dado que forman parte de la aplicación, se definen en un archivo AppIntentVocabulary.plist como parte del lote de aplicaciones principal. Además, estas palabras y frases deben localizarse.

Los términos de vocabulario específicos de la aplicación deben pertenecer a una de las siguientes categorías:

  • Opciones de paseo.
  • Nombres de entrenamiento.

El archivo de vocabulario específico de la aplicación contiene dos claves de nivel raíz:

  • ParameterVocabulariesObligatorio: define los términos personalizados de la aplicación y los parámetros de intención a los que se aplican.
  • IntentPhrasesOpcional: contiene frases de ejemplo mediante los términos personalizados definidos en .ParameterVocabularies

Cada entrada en el ParameterVocabularies debe especificar una cadena de identificador, un término y la intención a la que se aplica el término. Además, un único término se puede aplicar a varias intenciones.

Para obtener una lista completa de los valores aceptables y la estructura de archivos requerida, vea Referencia del formato de archivo de vocabulario de la aplicación de Apple.

Para agregar un archivo AppIntentVocabulary.plist al proyecto de aplicación, haga lo siguiente:

  1. Haga clic con el botón derecho en el nombre del proyecto en el Explorador de soluciones y seleccione Agregar>Nuevo archivo...>iOS:

    Agregue una lista de propiedades

  2. Haga doble clic en el archivo AppIntentVocabulary.plist en el Explorador de soluciones para abrirlo para su edición.

  3. Haga clic en el + para agregar una clave, establezca el Nombre en ParameterVocabularies y el Tipo en Array:

    Establezca el Nombre a ParameterVocabularies y el Tipo a Matriz

  4. Expanda ParameterVocabularies y haga clic en el + botón y establezca el Tipo en Dictionary:

    Establezca el Tipo en Diccionario

  5. Haga clic en el + para agregar una nueva clave, establezca el Nombre en ParameterNames y el Tipo en Array:

    Establezca el nombre en ParameterNames y el Tipo en Matriz

  6. Haga clic en el + para agregar una nueva clave con el Tipo de String y el valor como uno de los nombres de parámetro disponibles. Por ejemplo, INStartWorkoutIntent.workoutName:

    La clave INStartWorkoutIntent.workoutName

  7. Agregue la clave de ParameterVocabulary a la clave de ParameterVocabularies con el Tipo de Array:

    Agregue la clave ParameterVocabulary a la clave ParameterVocabularies con el Tipo de Matriz

  8. Agregue una nueva clave con el Tipo de Dictionary:

    Agregue una nueva clave con el tipo de diccionario en Visual Studio para Mac.

  9. Agregue la VocabularyItemIdentifier clave con el Tipo de String y especifique un identificador único para el término:

    Agregue la clave VocabularyItemIdentifier con el tipo de cadena y especifique un id. único

  10. Agregue la VocabularyItemSynonyms clave con el Tipo de Array:

    Agregue la clave VocabularyItemSynonyms con el tipo de matriz

  11. Agregue una nueva clave con el Tipo de Dictionary:

    Agregue otra nueva clave con el tipo de diccionario en Visual Studio para Mac.

  12. Agregue la VocabularyItemPhrase clave con el Tipo de String y el término que define la aplicación:

    Agregue la clave VocabularyItemPhrase con el tipo de cadena y el término que define la aplicación

  13. Agregue la VocabularyItemPronunciation clave con el Tipo de String y la pronunciación fonética del término:

    Agregue la clave VocabularyItemPronunciation con el tipo de cadena y la pronunciación fonética del término

  14. Agregue la VocabularyItemExamples clave con el Tipo de Array:

    Agregue la clave VocabularyItemExamples con el tipo de matriz

  15. Agregue algunas String claves con usos de ejemplo del término :

    Agregue algunas claves de cadena con usos de ejemplo del término en Visual Studio para Mac.

  16. Repita los pasos anteriores para cualquier otro término personalizado que necesite definir la aplicación.

  17. Contraiga la ParameterVocabularies clave.

  18. Agregue la IntentPhrases clave con el Tipo de Array:

    Agregue la clave IntentPhrases con el tipo de matriz

  19. Agregue una nueva clave con el Tipo de Dictionary:

    Agregue una nueva clave adicional con el tipo de diccionario en Visual Studio para Mac.

  20. Agregue la IntentName clave con el Tipo de String y la intención para el ejemplo:

    Agregue la clave IntentName con el tipo de cadena y la intención para el ejemplo

  21. Agregue la IntentExamples clave con el Tipo de Array:

    Agregue la clave IntentExamples con el tipo de matriz

  22. Agregue algunas String claves con usos de ejemplo del término :

    Agregue algunas claves de cadena adicionales con usos de ejemplo del término en Visual Studio para Mac.

  23. Repita los pasos anteriores para cualquier intención de la aplicación que necesite para proporcionar un ejemplo de uso.

Importante

El AppIntentVocabulary.plist se registrará con Siri en los dispositivos de prueba durante el desarrollo y puede tardar algún tiempo en incorporar el vocabulario personalizado. Como resultado, el evaluador tendrá que esperar varios minutos antes de intentar probar vocabulario específico de la aplicación cuando se haya actualizado.

Para obtener más información, vea nuestra Referencia de vocabulario específico de la aplicación y la Referencia de vocabulario personalizado de Apple.

Agregar una extensión de intenciones

Ahora que la aplicación se ha preparado para adoptar SiriKit, el desarrollador tendrá que agregar una (o varias) extensiones de intenciones a la solución para controlar las intenciones necesarias para la integración de Siri.

Para cada extensión de intenciones necesaria, haga lo siguiente:

  • Agregue un proyecto de extensión de intenciones a la solución de aplicación de Xamarin.iOS.
  • Configure el archivo de extensión Info.plist de intenciones.
  • Modifique la clase principal de la extensión de intenciones.

Para obtener más información, vea nuestra Referencia sobre la extensión de intenciones y la Referencia de creación de la extensión de intenciones de Apple.

Creación de la extensión

Para agregar una extensión de intención a la solución, haga lo siguiente:

  1. Haga clic con el botón derecho en el Nombre de la solución en el Panel de solución y seleccione Agregar>Agregar nuevo proyecto....

  2. En el cuadro de diálogo, seleccione iOS>Extensiones>Extensión de intención y haga clic en el botón Siguiente:

    Seleccione la extensión de intención

  3. A continuación, escriba un Nombre para la extensión de intención y haga clic en el botón Siguiente:

    Escriba un nombre para la extensión de intención.

  4. Por último, haga clic en el botón Crear para agregar la extensión de intención a la solución de aplicaciones:

    Agregue la extensión de intención a la solución de aplicaciones.

  5. En el Explorador de soluciones, haga clic con el botón derecho en la carpeta Referencias de la extensión de intención recién creada. Compruebe el nombre del proyecto de biblioteca de código compartido común (que la aplicación creada anteriormente) y haga clic en el botón Aceptar:

    Seleccione el nombre del proyecto de biblioteca de código compartido común.

Repita estos pasos para el número de extensiones de intención (basadas en Arquitectura de la aplicación para extensiones sección anterior) que necesitará la aplicación.

Configuración de Info.plist

Para cada una de las extensiones de intenciones que se han agregado a la solución de la aplicación, debe configurarse en los archivos Info.plist para que funcionen con la aplicación.

Al igual que cualquier extensión de aplicación típica, la aplicación tendrá las claves existentes de NSExtension y NSExtensionAttributes. Para una extensión de intención hay dos atributos nuevos que se deben configurar:

Los dos nuevos atributos que se deben configurar

  • IntentsSupported: Es necesario y consta de una matriz de nombres de clase de intención que la aplicación quiere admitir desde la extensión de intención.
  • IntentsRestrictedWhileLocked: Es una clave opcional para que la aplicación especifique el comportamiento de la pantalla de bloqueo de la extensión. Consta de una matriz de nombres de clase de intención que la aplicación quiere requerir que el usuario inicie sesión para usarlo desde la extensión de intención.

Para configurar el archivo de Info.plist la extensión de intención, haga doble clic en él en el Explorador de soluciones para abrirlo para su edición. A continuación, cambie a la vista Origen y expanda las NSExtension claves y NSExtensionAttributes en el editor:

Expanda la clave IntentsSupported y agregue el nombre de cualquier clase de intención que admita esta extensión. Para la aplicación MonkeyChat de ejemplo, admite el INSendMessageIntent:

Si la aplicación requiere que el usuario inicie sesión en el dispositivo para usar una intención determinada, expanda la clave IntentRestrictedWhileLocked y agregue los nombres de clase de las intenciones que tienen acceso restringido. Para la aplicación MonkeyChat de ejemplo, el usuario debe iniciar sesión para enviar un mensaje de chat, por lo que hemos agregado INSendMessageIntent:

Para obtener una lista completa de los dominios de intención disponibles, vea Referencia de dominios de intención de Apple.

Configuración de la clase Main

A continuación, el desarrollador deberá configurar la clase principal que actúa como punto de entrada principal para la extensión de intención en Siri. Debe ser una subclase de INExtension la que se ajusta al IINIntentHandler delegado. Por ejemplo:

using System;
using System.Collections.Generic;

using Foundation;
using Intents;

namespace MonkeyChatIntents
{
    [Register ("IntentHandler")]
    public class IntentHandler : INExtension, IINSendMessageIntentHandling, IINSearchForMessagesIntentHandling, IINSetMessageAttributeIntentHandling
    {
        #region Constructors
        protected IntentHandler (IntPtr handle) : base (handle)
        {
            // Note: this .ctor should not contain any initialization logic.
        }
        #endregion

        #region Override Methods
        public override NSObject GetHandler (INIntent intent)
        {
            // This is the default implementation.  If you want different objects to handle different intents,
            // you can override this and return the handler you want for that particular intent.

            return this;
        }
        #endregion
        ...
    }
}

Hay un método solitario que la aplicación debe implementar en la clase principal Extensión de intención, el GetHandler método. SiriKit pasa este método y la aplicación debe devolver un Controlador de intencionesque coincida con el tipo de la intención especificada.

Dado que la aplicación MonkeyChat de ejemplo solo controla una intención, se devuelve en el GetHandler método. Si la extensión controla más de una intención, el desarrollador agregaría una clase para cada tipo de intención y devolvería una instancia aquí basada en el Intent pasado al método.

Control de la fase de resolución

La fase de resolución es donde la extensión de intención aclarará y validará los parámetros pasados desde Siri y se han establecido a través de la conversación del usuario.

Para cada parámetro que se envía desde Siri, hay un Resolve método. La aplicación tendrá que implementar este método para cada parámetro que la aplicación pueda necesitar la ayuda de Siri para obtener la respuesta correcta del usuario.

En el caso de la aplicación MonkeyChat de ejemplo, la extensión de intención requerirá que uno o varios destinatarios envíen el mensaje. Para cada destinatario de la lista, la extensión tendrá que realizar una búsqueda de contactos que pueda tener el siguiente resultado:

  • Se encuentra exactamente un contacto coincidente.
  • Se encuentran dos o más contactos coincidentes.
  • No se encuentra ningún contacto coincidente.

Además, MonkeyChat requiere contenido para el cuerpo del mensaje. Si el usuario no lo ha proporcionado, Siri debe solicitar al usuario el contenido.

La extensión de intención tendrá que controlar correctamente cada uno de estos casos.

[Export ("resolveRecipientsForSearchForMessages:withCompletion:")]
public void ResolveRecipients (INSendMessageIntent intent, Action<INPersonResolutionResult []> completion)
{
    var recipients = intent.Recipients;
    // If no recipients were provided we'll need to prompt for a value.
    if (recipients.Length == 0) {
        completion (new INPersonResolutionResult [] { (INPersonResolutionResult)INPersonResolutionResult.NeedsValue });
        return;
    }

    var resolutionResults = new List<INPersonResolutionResult> ();

    foreach (var recipient in recipients) {
        var matchingContacts = new INPerson [] { recipient }; // Implement your contact matching logic here to create an array of matching contacts
        if (matchingContacts.Length > 1) {
            // We need Siri's help to ask user to pick one from the matches.
            resolutionResults.Add (INPersonResolutionResult.GetDisambiguation (matchingContacts));
        } else if (matchingContacts.Length == 1) {
            // We have exactly one matching contact
            resolutionResults.Add (INPersonResolutionResult.GetSuccess (recipient));
        } else {
            // We have no contacts matching the description provided
            resolutionResults.Add ((INPersonResolutionResult)INPersonResolutionResult.Unsupported);
        }
    }

    completion (resolutionResults.ToArray ());
}

[Export ("resolveContentForSendMessage:withCompletion:")]
public void ResolveContent (INSendMessageIntent intent, Action<INStringResolutionResult> completion)
{
    var text = intent.Content;
    if (!string.IsNullOrEmpty (text))
        completion (INStringResolutionResult.GetSuccess (text));
    else
        completion ((INStringResolutionResult)INStringResolutionResult.NeedsValue);
}

Para obtener más información, vea nuestra Referencia de la fase de resolución y la Referencia de intenciones de resolución y control de Apple.

Control de la fase de confirmación

La fase confirmar es donde la extensión de intención comprueba que tiene toda la información para satisfacer la solicitud del usuario. La aplicación quiere enviar confirmación a lo largo de todos los detalles auxiliares de lo que está a punto de pasar a Siri para que se pueda confirmar con el usuario que se trata de la acción prevista.

[Export ("confirmSendMessage:completion:")]
public void ConfirmSendMessage (INSendMessageIntent intent, Action<INSendMessageIntentResponse> completion)
{
    // Verify user is authenticated and the app is ready to send a message.
    ...

    var userActivity = new NSUserActivity (nameof (INSendMessageIntent));
    var response = new INSendMessageIntentResponse (INSendMessageIntentResponseCode.Ready, userActivity);
    completion (response);
}

Para obtener más información, vea nuestra Referencia de la fase de confirmación.

Procesamiento de la intención

Este es el punto en el que la extensión de intención realiza realmente la tarea para cumplir la solicitud del usuario y pasar los resultados a Siri para que el usuario pueda ser informado.

public void HandleSendMessage (INSendMessageIntent intent, Action<INSendMessageIntentResponse> completion)
{
    // Implement the application logic to send a message here.
    ...

    var userActivity = new NSUserActivity (nameof (INSendMessageIntent));
    var response = new INSendMessageIntentResponse (INSendMessageIntentResponseCode.Success, userActivity);
    completion (response);
}

public void HandleSearchForMessages (INSearchForMessagesIntent intent, Action<INSearchForMessagesIntentResponse> completion)
{
    // Implement the application logic to find a message that matches the information in the intent.
    ...

    var userActivity = new NSUserActivity (nameof (INSearchForMessagesIntent));
    var response = new INSearchForMessagesIntentResponse (INSearchForMessagesIntentResponseCode.Success, userActivity);

    // Initialize with found message's attributes
    var sender = new INPerson (new INPersonHandle ("sarah@example.com", INPersonHandleType.EmailAddress), null, "Sarah", null, null, null);
    var recipient = new INPerson (new INPersonHandle ("+1-415-555-5555", INPersonHandleType.PhoneNumber), null, "John", null, null, null);
    var message = new INMessage ("identifier", "I am so excited about SiriKit!", NSDate.Now, sender, new INPerson [] { recipient });
    response.Messages = new INMessage [] { message };
    completion (response);
}

public void HandleSetMessageAttribute (INSetMessageAttributeIntent intent, Action<INSetMessageAttributeIntentResponse> completion)
{
    // Implement the application logic to set the message attribute here.
    ...

    var userActivity = new NSUserActivity (nameof (INSetMessageAttributeIntent));
    var response = new INSetMessageAttributeIntentResponse (INSetMessageAttributeIntentResponseCode.Success, userActivity);
    completion (response);
}

Para obtener más información, vea nuestra Referencia de fase de control.

Agregar una extensión de interfaz de usuario de intenciones

La extensión opcional de interfaz de usuario de intenciones presenta la oportunidad de incorporar la interfaz de usuario y la personalización de marca de la aplicación a la experiencia de Siri y hacer que los usuarios se sientan conectados a la aplicación. Con esta extensión, la aplicación puede traer la marca, así como visual y otra información a la transcripción.

Ejemplo de extensión de la UI de Intenciones

Al igual que la extensión Intents, el desarrollador realizará el siguiente paso para la extensión de interfaz de usuario de intención:

  • Agregue un proyecto de extensión de interfaz de usuario intenciones a la solución de aplicación de Xamarin.iOS.
  • Configure el archivo de extensión de interfaz de usuario de intenciones Info.plist.
  • Modifique la clase principal de extensión de interfaz de usuario de intenciones.

Para obtener más información, vea nuestra Referencia de la extensión de interfaz de usuario de intenciones y la Referencia de creación de interfaces personalizadas de Apple.

Creación de la extensión

Para agregar una extensión de interfaz de usuario de intenciones a la solución, haga lo siguiente:

  1. Haga clic con el botón derecho en el Nombre de la solución en el Panel de solución y seleccione Agregar>Agregar nuevo proyecto....

  2. En el cuadro de diálogo, seleccione iOS>Extensiones>Extensión de interfaz de usuario de intención y haga clic en el botón Siguiente:

    Selección de la extensión de la UI de intención

  3. A continuación, escriba un Nombre para la extensión de intención y haga clic en el botón Siguiente:

    Escriba un nombre para la extensión de intención en Visual Studio para Mac.

  4. Por último, haga clic en el botón Crear para agregar la extensión de intención a la solución de aplicaciones:

    Agregue la extensión de intención a la solución de aplicaciones en Visual Studio para Mac.

  5. En el Explorador de soluciones, haga clic con el botón derecho en la carpeta Referencias de la extensión de intención recién creada. Compruebe el nombre del proyecto de biblioteca de código compartido común (que la aplicación creada anteriormente) y haga clic en el botón Aceptar:

    Seleccione el nombre del proyecto de biblioteca de código compartido común en Visual Studio para Mac.

Configuración de Info.plist

Configure el archivo Info.plist de la extensión interfaz de usuario de intenciones para que funcione con la aplicación.

Al igual que cualquier extensión de aplicación típica, la aplicación tendrá las claves existentes de NSExtension y NSExtensionAttributes. Para una extensión de intenciones hay un nuevo atributo que debe configurarse:

El único atributo nuevo que debe configurarse

IntentsSupported es necesaria y consta de una matriz de nombres de clase de intención que la aplicación quiere admitir desde la extensión de intención.

Para configurar el archivo de laInfo.plist extensión de interfaz de usuario de intenciones, haga doble clic en él en el Explorador de soluciones para abrirlo para su edición. A continuación, cambie a la vista Origen y expanda las NSExtension claves y NSExtensionAttributes en el editor:

Las claves NSExtension y NSExtensionAttributes en el editor.

Expanda la clave IntentsSupported y agregue el nombre de cualquier clase de intención que admita esta extensión. Para la aplicación MonkeyChat de ejemplo, admite el INSendMessageIntent:

Para obtener una lista completa de los dominios de intención disponibles, vea Referencia de dominios de intención de Apple.

Configuración de la clase Main

Configure la clase principal que actúa como punto de entrada principal para la extensión de interfaz de usuario de intención en Siri. Debe ser una subclase de UIViewController la que se ajusta a la IINUIHostedViewController interfaz. Por ejemplo:

using System;
using Foundation;
using CoreGraphics;
using Intents;
using IntentsUI;
using UIKit;

namespace MonkeyChatIntentsUI
{
    public partial class IntentViewController : UIViewController, IINUIHostedViewControlling
    {
        #region Constructors
        protected IntentViewController (IntPtr handle) : base (handle)
        {
            // Note: this .ctor should not contain any initialization logic.
        }
        #endregion

        #region Override Methods
        public override void ViewDidLoad ()
        {
            base.ViewDidLoad ();

            // Do any required interface initialization here.
        }

        public override void DidReceiveMemoryWarning ()
        {
            // Releases the view if it doesn't have a superview.
            base.DidReceiveMemoryWarning ();

            // Release any cached data, images, etc that aren't in use.
        }
        #endregion

        #region Public Methods
        [Export ("configureWithInteraction:context:completion:")]
        public void Configure (INInteraction interaction, INUIHostedViewContext context, Action<CGSize> completion)
        {
            // Do configuration here, including preparing views and calculating a desired size for presentation.

            if (completion != null)
                completion (DesiredSize ());
        }

        [Export ("desiredSize:")]
        public CGSize DesiredSize ()
        {
            return ExtensionContext.GetHostedViewMaximumAllowedSize ();
        }
        #endregion
    }
}

Siri pasará una instancia de clase INInteraction al método Configure de la instancia de UIViewController dentro de la extensión de interfaz de usuario de intención.

El INInteraction objeto proporciona tres fragmentos clave de información a la extensión:

  1. Objeto de intención que se está procesando.
  2. Objeto Intent Response de los métodos Confirm y Handle de la extensión de intención.
  3. Estado de interacción que define el estado de la interacción entre la aplicación y Siri.

La UIViewController instancia es la clase principal para la interacción con Siri y porque hereda de UIViewController, tiene acceso a todas las características de UIKit.

Cuando Siri llama al Configure método de que UIViewController pasa en un contexto de vista que indica que el controlador de vista se hospedará en un Snippit de Siri o Tarjeta Maps.

Siri también pasará un controlador de finalización que la aplicación necesita para devolver el tamaño deseado de la vista una vez que la aplicación haya terminado de configurarla.

Diseño de la interfaz de usuario en iOS Designer

Diseño de la interfaz de usuario de la extensión de interfaz de usuario de intenciones en iOS Designer. Haga doble clic en el archivoMainInterface.storyboard de la extensión en el Explorador de soluciones para abrirlo para su edición. Arrastre todos los elementos de interfaz de usuario necesarios para compilar la interfaz de usuario y guardar los cambios.

Importante

Aunque es posible agregar elementos interactivos como UIButtons o UITextFields al UIViewControllerde la extensión UI de intenciones, estos están estrictamente prohibidos, ya que UI de intenciones no es interactiva y el usuario no podrá interactuar con ellos.

Conexión de la interfaz de usuario

Con la interfaz de usuario de la extensión de interfaz de usuario de intenciones creada en iOS Designer, edite la subclase UIViewController e invalide el método Configure de la siguiente manera:

[Export ("configureWithInteraction:context:completion:")]
public void Configure (INInteraction interaction, INUIHostedViewContext context, Action<CGSize> completion)
{
    // Do configuration here, including preparing views and calculating a desired size for presentation.
    ...

    // Return desired size
    if (completion != null)
        completion (DesiredSize ());
}

[Export ("desiredSize:")]
public CGSize DesiredSize ()
{
    return ExtensionContext.GetHostedViewMaximumAllowedSize ();
}

Invalidación de la interfaz de usuario de Siri predeterminada

La extensión UI de intenciones siempre se mostrará junto con otro contenido de Siri, como el icono de la aplicación y el nombre en la parte superior de la interfaz de usuario o, en función de la Intención, se pueden mostrar botones (como Enviar o Cancelar) en la parte inferior.

Hay algunas instancias en las que la aplicación puede reemplazar la información que Siri muestra al usuario de forma predeterminada, como la mensajería o los mapas en los que la aplicación puede reemplazar la experiencia predeterminada por una adaptada a la aplicación.

Si la extensión de interfaz de usuario de intenciones necesita invalidar elementos de la interfaz de usuario de Siri predeterminada, la UIViewController subclase tendrá que implementar la IINUIHostedViewSiriProvidinginterfaz y participar para mostrar un elemento de interfaz determinado.

Agregue el código siguiente a la subclase UIViewControllerpara indicar a Siri que la extensión de la interfaz de usuario de intención ya muestra el contenido del mensaje:

public bool DisplaysMessage {
    get {return true;}
}

Consideraciones

Apple sugiere que el desarrollador tenga en cuenta las siguientes consideraciones al diseñar e implementar las extensiones de interfaz de usuario de intención:

  • Ser consciente del uso de memoria: Dado que las extensiones de interfaz de usuario de intención son temporales y solo se muestran durante un breve tiempo, el sistema impone restricciones de memoria más estrictas de las que se usan con una aplicación completa.
  • Considere los tamaños de vista mínimo y máximo: Asegúrese de que las extensiones de interfaz de usuario de intención tienen un aspecto correcto en cada tipo de dispositivo iOS, tamaño y orientación. Además, es posible que no se pueda conceder el tamaño deseado que la aplicación envía a Siri.
  • Usar patrones de diseño flexibles y adaptables: De nuevo, para asegurarse de que la interfaz de usuario sea excelente en todos los dispositivos.

Resumen

En este artículo se ha tratado SiriKit y se ha mostrado cómo se puede agregar a las aplicaciones de Xamarin.iOS para proporcionar servicios accesibles para el usuario mediante Siri y la aplicación Maps en un dispositivo iOS.