Spanish (Español) translation by Rafael Chavarría (you can also view the original English article)



Introducción
Ya que Siri fue introducido en 2011, los desarrolladores iOS han estado pidiendo la posibilidad de integrar aplicaciones de terceros. Con la liberación de iOS 10 durante WWDC 2016, Apple finalmente hizo a SiriKit disponible para desarrolladores. Aún hay algunas restricciones sobre los tipos de aplicaciones que pueden sacar ventaja de Siri, pero es un paso en la dirección correcta. Echemos un vistazo a lo que podemos hacer con Siri.
Para más sobre SiriKit y las otras nuevas características para desarrolladores en iOS 10, revisa el curso de Markus Mühlberger, aquí en Envato Tuts+.
Dominios Soportados
Para hacer uso de SiriKit, tu aplicación tiene que estar en uno o más de los siguientes dominios:
- Llamadas VoIP (por ejemplo, Skype)
- Mensajería (WhatsApp)
- Pagos (Square, PayPal)
- Fotos (Photo)
- Ejercicio (Runtastic)
- Transporte (Uber, Lyft)
- CarPlay (marcas de autos únicamente)
- Reservaciones de restaurante (requiere soporte adicional de Apple)
Si tu aplicación no pertenece a ninguna de estas categorías, desafortunadamente no puedes usar Siri en tu aplicación en este momento. No lo abandones aún, ya que SiriKit es muy poderoso, ¡y podría tener nuevas capacidades en el futuro!
Arquitectura de Extensión
Una extensión SiriKit es en realidad compuesta por dos tipos de extensión. Una extensión de Intents
es requerida y se encarga de manejar las peticiones por el usuario y excluyendo una tarea específica en tu aplicación (tal como comenzar una llamada, enviar un mensaje, etc.).
Por otro lado, una extensión IntentsUI
no es obligatoria. Deberías solo crear una si quieres personalizar la interfaz de usuario que Siri muestra cuando presenta tu información. Si no haces esto, la interfaz estándar de Siri será mostrada. Vamos a echar un vistazo a ambos tipos de extensión en este tutorial.
Para tu información, durante WWDC 2016 Apple liberó dos videos muy interesantes sobre SiriKit. Podrías querer revisarlos:
Proyecto de Ejemplo
Vamos a construir una aplicación sencilla que procesa pagos vía Siri. La meta es procesar exitosamente la oración "Enviar $20 a Patrick vía TutsplusPayments". El formato de la oración consiste en una cantidad de dinero con una divisa específica, el nombre del receptor y la aplicación a usar para completar la transacción. Después vamos a analizar el intent de pago a más detalle.
Configuración Inicial
Vamos a comenzar creando un proyecto Xcode estándar en Swift y dándole un nombre. Hay unos cuantos pasos obligatorios que tienes que hacer antes de escribir cualquier código para habilitar tu aplicación para usar las APIs de Siri.
1. Selecciona tu Objetivo > Capacidades y habilita la capacidad Siri. Asegúrate de que los derechos fueron creados exitosamente en la estructura de tu proyecto.



2. Abre el Info.plist
de tu aplicación y agrega la llave NSSiriUsageDescription
. El valor debe ser una cadena explicando tu uso de Siri que será mostrado al usuario cuando se le pida el permiso inicial.
3. Selecciona Archivo > Nuevo > Objetivo En la nueva ventana presentada por Xcode, bajo Extensiones de Aplicación, elige Extension de Intents. También selecciona la opción para incluir una Extensión UI. Esto te salvará de tener que crear otra extensión por separado después.



En el archivo Info.plist
de tu recién creado objetivo Intents
, expande completamente el diccionario NSExtension
para estudiar sus contenidos. El diccionario describe a más detalle qué intents soporta tu extensión y si quieres permitir al usuario invocar un intent mientras el dispositivo está bloqueado.
Inserta los intents más relevantes en la parte superior si quieres soportar más de uno. Siri usa esta orden para descifrar cuál quiere utilizar el usuario en caso de ambigüedad.
Ahora necesitamos definir qué intents queremos soportar. En este ejemplo, vamos a construir una extensión que soporte el intent de pago. Modifica el archivo Info.plist
de acuerdo a la siguiente imagen.



Aquí especificamos que queremos manejar el INSendPaymentIntent
y que requerimos que el dispositivo esté desbloqueado. ¡No queremos que extraños envíen pagos cuando el dispositivo se pierde o es robado!
Objetivo iOS
El siguiente paso de hecho involucra escribir algo de código en la aplicación iOS. Tenemos que pedir permiso al usuario para mandar su voz a Apple para análisis. Nosotros simplemente tenemos que importar el framework Intents
y llamar al método apropiado como sigue:
1 |
import UIKit |
2 |
import Intents |
3 |
|
4 |
class ViewController: UIViewController { |
5 |
|
6 |
override func viewDidLoad() { |
7 |
super.viewDidLoad() |
8 |
// Ask permission to access Siri
|
9 |
INPreferences.requestSiriAuthorization { authorizationStatus in |
10 |
switch authorizationStatus { |
11 |
case .authorized: |
12 |
print("Authorized") |
13 |
default: |
14 |
print("Not Authorized") |
15 |
}
|
16 |
}
|
17 |
}
|
18 |
}
|
El diálogo resultante presentado al usuario durante el primer lanzamiento de la aplicación lucirá así.



Esto es todo lo que tenemos que hacer en nuestra aplicación iOS. ¡Entremos ahora en el mundo de las extensiones!
Extensión de Intents
Cambia ala extensión de Intents
que hemos creado antes. Expande sus contenidos en el navegador de proyecto Xcode. Verás solo un archivo llamado IntentHandler.swift
.
Este archivo es el punto de entrada a tu extensión y es usado para manejar cualquier intent que Siri te envíe. Siri continuará al método handler (for:)
todos los intents en caso de que tu extensión soporte múltiples tipos. Es tu trabajo revisar el tipo de objeto INIntent
y manejarlo apropiadamente.
La plantilla IntentHandler.swift
ya contiene un ejemplo de implementación de un Intent de Mensajería. Reemplaza todo el código con el siguiente método vacío para que podamos recorrer juntos cada paso.
1 |
class IntentHandler: INExtension { |
2 |
|
3 |
override func handler(for intent: INIntent) -> Any? { |
4 |
// This is the default implementation. If you want different objects to handle different intents,
|
5 |
// you can override this and return the handler you want for that particular intent.
|
6 |
return self |
7 |
}
|
8 |
}
|
Cada intent tiene un protocolo asociado para asegurar que una clase implemente todos los métodos requeridos. La mayoría de los protocolos en el framework de Intents tienen la misma estructura.
El protocolo que vamos a implementar es llamado INSendPaymentIntentHandling
. Este protocolo contiene los siguientes métodos requeridos y opcionales:
- Requerido:
handle(sendPayment:completion:)
- Opcional:
confirm(sendPayment:completion:)
resolvePayee(forSendPayment:with:)
resolveCurrencyAmount(forSendPayment:with:)
resolveNote(forSendPayment:with:)
Creemos una extensión de la clase IntentHandler
en el mismo archivo Swift para implementar el único método requerido.
1 |
extension IntentHandler: INSendPaymentIntentHandling { |
2 |
|
3 |
func handle(sendPayment intent: INSendPaymentIntent, completion: @escaping (INSendPaymentIntentResponse) -> Void) { |
4 |
// Check that we have valid values for payee and currencyAmount
|
5 |
guard let payee = intent.payee, let amount = intent.currencyAmount else { |
6 |
return completion(INSendPaymentIntentResponse(code: .unspecified, userActivity: nil)) |
7 |
}
|
8 |
// Make your payment!
|
9 |
print("Sending \(amount) payment to \(payee)!") |
10 |
completion(INSendPaymentIntentResponse(code: .success, userActivity: nil)) |
11 |
}
|
12 |
}
|
Esta es una implementación muy básica. Nos aseguramos de que son payee
y currencyAmount
válidos para establecer la transacción como exitosa. Tal vez no lo creas, ¡pero ya funciona! Selecciona el esquema de Intents desde Xcode y ejecútalo. Cuando Xcode presenta el menú usual para elegir una aplicación para ejecutar, selecciona Siri.



Cuando Siri comienza, intenta decir, "Enviar $20 a Patrick vía TutsplusPayments". ¡Ahora disfruta tu primer pago exitoso completado con tu voz!



También puedes intentar probar el caso fallido. Trata de decir la misma oración de antes pero sin especificar al receptor (ej. "Enviar $20 vía TutsplusPayments"). Verás que Siri fallará y presenta al usuario un botón para continuar con el pago en tu aplicación.



En caso de que Siri no entienda o no se le proporcione alguno de ls parámetros opcionales per requieras un valor válido, puedes implementar uno de los métodos de resolución. Esos métodos presentan al usuario una opción de dar más detalles acerca del pago tal como el nombre del receptor, la cantidad de divisa exacta e incluso una nota. Con esta arquitectura inteligente de la API, a ti como desarrollador se te presenta la posibilidad de entender fácil y claramente la petición de tu usuario en diferentes formas.
En una aplicación del mundo real, podrías crear un framework dinámico que está compartido entre tu aplicación iOS y extensiones. Haciendo uso de esta arquitectura, puedes compartir la misma lógica de negocio en objetivos múltiples. No necesitarás implementarlo varias veces, ¡solo una vez para todos los objetivos!
Extensión UI de Intents
En la última parte de este tutorial, te voy a mostrar cómo puedes personalizar la interfaz de usuario que muestra Siri.
Primero que todo, recuerda establecer la clase intent correcta que quieres manejar en el Info.plist
del ExtensionUI
, como hicimos en la sección previa.
Salta a la extensión Intents UI y verás la plantilla que Xcode ha creado por ti. Contiene un IntentViewController
, que es una simple subclase de UIViewController
que implementa el protocolo INUIHostedViewControlling
. Un archivo de Storyboard también fue creado por ti; ábrelo de manera que podamos personalizar la interfaz de usuario.
Agrega un UIImageView
como el fondo y una etiqueta en el centro. Descarga la imagen de fondo, importala al objetivo Intents UI y establécela como la imagen del recién creado UIImageView
. Crea un objeto UILabel
y posicionalo al centro de la vista. Puedes usar fácilmente AutoLayout
para configurar las restricciones en Storyboard.
Abre el Editor Asistente y crea un @IBOutlet
para tu etiqueta y llámalo contentLabel
. El resultado debería lucir algo como esto:



Abre el archivo IntentViewController
y verás un montón de ejemplo de código. Puedes quitar todo excepto el método configure(with:context:completion:)
que vamos a implementar ahora. El método es llamado cuando la interfaz de usuario está lista para ser configurada. Lo que tenemos que hacer es establecer el contenido del UILabel
.
1 |
class IntentViewController: UIViewController, INUIHostedViewControlling { |
2 |
|
3 |
@IBOutlet weak var contentLabel: UILabel! |
4 |
|
5 |
// MARK: - INUIHostedViewControlling
|
6 |
|
7 |
func configure(with interaction: INInteraction!, context: INUIHostedViewContext, completion: ((CGSize) -> Void)!) { |
8 |
|
9 |
if let paymentIntent = interaction.intent as? INSendPaymentIntent { |
10 |
// If any of this properties is not set, use the default UI.
|
11 |
guard let amount = paymentIntent.currencyAmount?.amount, let currency = paymentIntent.currencyAmount?.currencyCode, let name = paymentIntent.payee?.displayName else { |
12 |
return completion(CGSize.zero) |
13 |
}
|
14 |
let paymentDescription = "\(amount)\(currency) to \(name)" |
15 |
contentLabel.text = paymentDescription |
16 |
}
|
17 |
if let completion = completion { |
18 |
completion(self.desiredSize) |
19 |
}
|
20 |
}
|
21 |
|
22 |
var desiredSize: CGSize { |
23 |
return self.extensionContext!.hostedViewMaximumAllowedSize |
24 |
}
|
25 |
}
|
Primero que todo, revisa que el objeto intent
es de tipo INSendPaymentIntent
. Si lo es, también nos aseguramos de que todas las propiedades que queremos mostrar no sean nil
, de otro modo simplemente llamaos al bloque de terminación con el tamaño de cero para ocultar nuestra vista personalizada. Si todo sale según lo esperado, creamos una cadena personalizada con la información que queremos mostrar al usuario y la establecemos como el texto de contentLabel
.
¡Ejecuta la extensión de nuevo y verás la nueva vista dentro de Siri!



Siri aún muestra la vista por defecto. Podemos ocultarla haciendo nuestro controlador de vista conforme al protocolo INUIHostedViewSiriProviding
.
1 |
class IntentViewController: UIViewController, INUIHostedViewControlling, INUIHostedViewSiriProviding { |
2 |
// Previous code goes here...
|
3 |
var displaysPaymentTransaction: Bool { |
4 |
return true |
5 |
}
|
6 |
}
|
Regresando true
en la variable displaysPaymentTransaction
, le decimos a Siri que nuestro controlador de vista se está encargando de mostrar toda la información necesaria al usuario y que la vista por defecto puede ser ocultada. ¡El resultado es mucho más limpio ahora!



Nota: Como puedes ver en esta imagen, cuando se especifica una divisa diferente a Dólares Americanos, Siri entiendo correctamente y regresa el código de divisa a la extensión. Desafortunadamente, el texto siempre muestra Dólares Americanos. ¡He reportado este bug a Apple!
Conclusión
Espero que hayas disfrutado este tutorial. Siri es muy poderoso incluso si se limita a ciertos tipos de aplicación por el momento. ¡Si planeas implementarlo en tus propias aplicaciones, asegúrate mercadearlo bien a tus usuarios porque tal vez no estén conscientes de que tan interesante y avanzada se haya vuelto tu aplicación!
Si quieres aprender acerca de integrar Siri en tu aplicación, o si quieres averiguar sobre otras características interesantes de desarrollador de iOS 10, revisa el curso de Markus Mühlberger.
También, revisa algunos de nuestros otros tutoriales gratuitos sobre características de iOS 10