
Una de las características útiles (en mi opinión) de iOS 12 introducidas en WWDC 2018 es Siri Shortcuts .
Atajo ( atajo ): un comando rápido, una forma corta de realizar cualquier acción sin pasar por el script estándar.
En sus aplicaciones, puede tomar atajos para algunas acciones. Aprendiendo cómo y cuándo el usuario los implementa, Siri comienza de manera inteligente, en el momento y lugar correctos, para ofrecerle estos atajos y, lo mejor de todo, ¡el usuario puede llamarlos con frases que él les adjuntará! Debajo del gato más.
Como funciona
Utilizamos aplicaciones que, con ciertas acciones, crean y entregan accesos directos al sistema.
Puede ver estos accesos directos en Configuración → Siri y Buscar .

La captura de pantalla anterior muestra los últimos tres accesos directos que el sistema ha detectado desde diferentes aplicaciones. Si hacemos clic en el botón "Más accesos directos", veremos todos los accesos directos entregados al sistema por cada aplicación.
Con ciertas configuraciones en el código de creación de accesos directos, Siri ofrecerá estos accesos directos al usuario en la pantalla bloqueada, en el centro de notificaciones y búsqueda, centrándose en la frecuencia con la que usamos estas acciones, a qué hora, en qué días de la semana y dónde a otros factores.
Por ejemplo, si el viernes por la noche generalmente busca cajeros automáticos, luego de entrenarse, Siri le ofrecerá un acceso directo con esta acción los viernes por la noche.

Podemos agregar nuestro comando de voz a cada acceso directo si hacemos clic en el icono " + ".
Decimos un comando de voz, presionamos "Listo", y ahora podemos realizar la acción detrás del atajo usando la voz a través de Siri. Resulta que el usuario podrá realizar la funcionalidad de su aplicación a través de Siri sin abrir la aplicación en sí. El acceso directo con la frase se conserva en "Mis accesos directos".
Crear atajos
Para el desarrollo, necesitaremos Xcode 10 e iOS 12. En el momento de la escritura, ambos se encuentran en la etapa Beta .
Se puede crear un acceso directo a través de NSUserActivity
o Intent
.
El primer caso:
El usuario hace clic en el acceso directo, que pasa el comando con los parámetros ( NSUserActivity
) a nuestra aplicación, y decide cómo se debe procesar este comando (abra la ventana de la tasa actual de USD o la ventana de pedido de nuestra pizza favorita). Este es el buen atajo de Spotlight que todos conocemos, pero que Siri ofrece de manera inteligente.
Segundo caso:
Los accesos directos creados a través de Intent
más interesantes: le permiten ejecutar un comando inmediatamente en la interfaz Siri sin iniciar su aplicación. Anteriormente, el conjunto de Intent
era difícil para Apple: transferir dinero, enviar mensajes y otros . ¡Ahora, los desarrolladores tenemos la oportunidad de crear nuestras Intent
!
Independientemente de cómo se creó el acceso directo, pasa por 3 etapas del ciclo de vida:
- Anuncio ( Definir )
- Entrega al sistema ( Donar )
- Procesamiento por aplicación ( Manija )

Mi investigación mostró que una aplicación no puede entregar más de 20 accesos directos al sistema.
Además, consideraremos cómo darle a nuestra aplicación la capacidad de crear accesos directos y cómo trabajar con ellos dentro de ella.
Crear accesos directos a través de NSUserActivity
Analicemos el primer tipo de acceso directo simple que se abre a través de NSUserActivity
.
Por ejemplo, en la aplicación de banco móvil, tenemos una pantalla de búsqueda en cajeros automáticos y a menudo los busco. Para acceder a la pantalla con una tarjeta de cajero automático, tengo que iniciar la aplicación, ir a la pestaña "Más" en la pestaña, seleccionar la sección "Información" y hacer clic en el botón "Cajeros automáticos".
Si creamos un acceso directo que conduce inmediatamente a esta pantalla, el usuario podrá acceder a él con un solo toque cuando Siri se lo ofrezca, por ejemplo, en una pantalla bloqueada.
Declarar acceso directo
El primer paso es declarar un tipo como nuestra NSUserActivity
(podemos decir que este es su identificador) en info.playlist :
<key>NSUserActivityTypes</key> <array> <string>ru.tinkoff.demo.show-cashMachine</string> </array>
Anunciado
Entregue el acceso directo al sistema (Donar)
Después de la declaración, podemos crear NSUserActivity
en el código de nuestra aplicación con el tipo que establecimos anteriormente en info.playlist :
let activity = NSUserActivity(activityType: "ru.tinkoff.demo.show-cashMachine")
Para que la actividad entre en la lista de accesos directos del sistema, debe establecerse en title
y establecer la propiedad isEligibleForSearch
en true
. No son necesarias otras propiedades para agregar accesos directos, pero su presencia hace que el acceso directo sea más legible y fácil de usar.
Fuego! NSUserActivity
es, para entregarlo al sistema, queda por dar el último paso.
ViewConroller
tiene una propiedad userActivity
, a la que debemos asignar la activity
creada anteriormente:
self.userActivity = activity
Tan pronto como se ejecute esta línea, se creará un acceso directo a partir de esta actividad. Se entregará al sistema y se mostrará en la configuración de Siri ( Configuración → Siri y Buscar ). Entonces Siri podrá ofrecérselo al usuario, y el usuario podrá asignarle su comando de voz.
Nota : La documentación de Apple dice que en lugar de asignar actividad al controlador de vista, es suficiente llamar al método becomeCurrent()
en la becomeCurrent()
. Sin embargo, esta acción no entregó actividad a mi sistema y el acceso directo no apareció en la lista
Luego, llame al método becomeCurrent()
en el objeto de actividad del usuario para marcarlo como actual, que dona la actividad a Siri. Alternativamente, puede adjuntar el objeto a un objeto UIViewController o UIResponder, que también marca la actividad como actual.
Para verificar que todo funcionó, abra Configuración> Siri y busque : el acceso directo basado en nuestra actividad debe estar en la lista.
Atajos de procesamiento por aplicación (asa)
Cuando un usuario navega por el acceso directo desde el centro de notificaciones o lo activa por voz, la aplicación se inicia y debemos procesar este acceso directo.
activity
lanzada en AppDelegate
'un método:
func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool { if userActivity.activityType == "ru.tinkoff.demo.show-cashMachine" {
Total
Un acceso NSUserActivity
NSUserActivity se crea de la siguiente manera:
- Declare el tipo (identificador) de
NSUserActivity
en NSUserActivity
. - Creamos
NSUserActivity
en el código y configuramos viewController'
.
Crear comandos de voz desde una aplicación
Entonces, si el usuario abre Configuración> Siri y busca , verá una lista de sus accesos directos, que fue creada por varias aplicaciones, incluida la nuestra. Al hacer clic en " + ", el usuario puede crear cualquier comando de voz y asociarlo con el acceso directo seleccionado. Sin embargo, cada vez que ingresar la configuración es inconveniente para el usuario, muchos ni siquiera se dan cuenta de esta posibilidad.
Es genial que pueda adjuntar un comando de voz a una acción específica directamente dentro de la aplicación.
Supongamos que un usuario realiza alguna acción, se entrega al sistema, quiere guardarlo. Podemos agregar el botón " agregar acción a Siri " (puede nombrar y dibujar el botón como desee) en la pantalla de nuestra aplicación, luego el usuario, al hacer clic en él, podrá asociar esta acción con un comando de voz desde la aplicación sin entrar en la configuración.
Al hacer clic en el botón, debe abrir la pantalla para agregar un comando de voz a un acceso directo en Siri INUIAddVoiceShortcutViewController
, o la pantalla para editar un comando de voz INUIEditVoiceShortcutViewController
, si ya se ha creado uno. La action
no reaccionada action
dicho botón será aproximadamente la siguiente:
@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 } } }
Entonces, las pantallas para agregar y editar un comando de voz para el acceso directo de Siri se ven:

También debemos implementar los métodos delegados de estos viewControllers, en los que deben ocultar el dismiss(animated: true, completion: nil)
y, si es necesario, actualizar la pantalla actual. Por ejemplo, si antes había un botón "agregar comando de voz" en la pantalla, luego de agregar un comando de voz este botón debería desaparecer o cambiar a "editar comando de voz".
Atajos de intención
Hasta ahora, solo hemos hablado de accesos directos que abren una aplicación y pasan NSUserActivity
datos allí a NSUserActivity
.
Pero volvamos a los accesos directos creados a través de Intent
, que le permiten realizar algunas acciones sin abrir la aplicación. Aquí comienza la diversión.
Imagine que un usuario ordena su pizza favorita. Lo pedirá muchas veces cuando lo desee, e incluso agregó un comando de voz al atajo de esta pizza, y esto simplifica su vida. Pero podemos hacer más por él: podemos asegurarnos de que al dar el comando de voz Siri, el sistema no lo arroje a la aplicación, sino que muestre información de pedidos y pida pizza de inmediato en la interfaz Siri. Este es solo el caso cuando el usuario no necesita abrir la aplicación para realizar alguna acción.
Primero, vaya a la configuración del proyecto, seleccione el objetivo principal, la pestaña Capabilities
y habilite el acceso a Siri.
Nuestra aplicación puede interactuar con Siri, pero esto no sucede en el código principal de la aplicación, sino en extensiones de intenciones de extensiones de destino separadas
Para comenzar, se debe crear este objetivo: Archivo → Nuevo → Objetivo , seleccione Extensiones de intención . Xcode ofrecerá crear otra extensión de destino para la ventana que muestra sus acciones en Siri, si es necesario, estamos de acuerdo.

Declarar acceso directo
La principal innovación de SiriKit en iOS 12 es la capacidad de crear sus Inetnts
, para aquellos que eran anteriores.

Para hacer esto, cree un nuevo archivo: Archivo → Nuevo → Archivo , seleccionando Archivo de definición de intención SiriKit en la sección Recurso .

Como resultado, aparece un archivo con la extensión .intentdefinition , en el que puede crear sus propios Intents
. Abrimos el archivo, y donde dice " Sin intenciones " en la parte inferior hay un icono " + " - haga clic en él. " Nueva intención ". Aparecerá una intención en la lista a la que puede agregar parámetros. En el caso de un pedido de pizza, puede agregar el número de pizzas y el tipo de pizza para ordenar como parámetros. Para la cantidad elegimos el tipo Integer
, y para el tipo de pizza seleccionamos el tipo Custom
, que en el código estará representado por la clase INObject
.
Ahora un par de líneas de frustración:
El usuario no podrá transmitir diferentes parámetros al mismo comando de voz guardado. ¡Ay!

¿Cuáles son los parámetros para:
Suponga que crea una entidad "Mostrar tasa %currency
", donde la currency
es un parámetro de entidad. Esto no significa que el usuario pueda decir las frases "Mostrar la tasa de cambio del dólar", "Mostrar la tasa de cambio de Bitcoin", etc. Fuera de la caja, esto no funcionará así. Pero esto significa que si el usuario miró la tasa de cambio del dólar, se creó el acceso directo "Mostrar tasa de USD", entonces cuando miró la tasa de cambio de Bitcoin, se creó el acceso directo "Mostrar la tasa de BTC", etc. En otras palabras, puede tener varias shorkatas que se basan en la misma intención, pero con diferentes parámetros. Cada uno de los accesos directos, el usuario podrá solicitar su comando de voz.
Bueno, al crear una intención en el archivo .intentdefinition , Xcode generará automáticamente una clase para esa intención (nota: no aparecerá en los archivos del proyecto, pero estará disponible para su uso). Este archivo generado automáticamente solo estará en aquellos destinos que tengan el archivo .intentdefinition .
Después de crear la intención en el archivo .intentdefinition , podemos crear nuestras intenciones en el código.
let intent = OrderPizzaIntent()
Entregue el acceso directo al sistema (Donar)
Para que esta entidad se incluya en la lista de accesos directos, debe incrustarla. Para hacer esto, se INInteraction
un objeto INInteraction
con una instancia de su intención, y se llama al método .donate en esta .donate
let intent = OrderPizzaIntentf() // ... let interaction = INInteraction(intent: intent, response: nil) interaction.donate { (error) in // ... / }
Después de ejecutar este código, el acceso directo basado en la intención se entregará al sistema y se mostrará en la Configuración de Siri.
Procesamos la aplicación de acceso directo (Handle)
El siguiente paso es procesar el intento cuando el usuario hace clic en él en el Sirjest del Siri o lo llama con un comando de voz.
Ya hemos creado una extensión de destino para Siri y tiene una clase IntentHandler pre-creada, que tiene un único método: `` manejar (por intención) ''
class IntentHandler: INExtension { override func handler(for intent: INIntent) -> Any { guard intent is OrderPizzaIntent else { fatalError("Unhandled intent type: \(intent)") } return OrderPizzaIntentHandler() } }
Nota: Si el compilador no ve la clase de su intención, entonces no ha agregado el archivo de extensión de destino .intentdefinition para Siri.
En este método, determinamos el tipo de intención entrante y para cada tipo creamos un objeto controlador que procesará esta intención. Cree un controlador para nuestro OrderPizzaIntent
e implemente el protocolo OrderPizzaIntentHandling
en él, que ya se genera automáticamente después de crear su Intención en .intentdefinition .
El protocolo contiene dos métodos de confirm
y handle
. Primero, se llama a confirm
donde se verifican todos los datos y se verifica la disponibilidad de la acción. Luego, el handle
funcionará en una acción corta que se realizará.
public class OrderPizzaIntentHandler: NSObject, OrderPizzaIntentHandling { public func confirm(intent: OrderPizzaIntent, completion: @escaping (OrderPizzaIntentResponse) -> Void) {
Ambos métodos definitivamente deben completion
llamada con la respuesta OrderPizzaIntentResponse
(también se genera automáticamente), de lo contrario, Siri solo esperará mucho tiempo y luego dará un error.
Respuestas más detalladas de Siri
Existe un conjunto estándar de códigos de respuesta generados automáticamente: enum OrderPizzaIntentResponseCode
, pero pueden no ser suficientes para una interfaz amigable. Por ejemplo, en la etapa de confirm
, pueden ocurrir varios errores diferentes: la pizza se ha agotado, la pizzería no funciona en este momento, etc. y el usuario debe conocer estos hechos, en lugar del mensaje estándar "Error de aplicación". ¿Recuerdas que creamos Intent
en el archivo .intentdefinition ? Junto con la intención en sí, Response
su Response
en la que puede agregar sus propias opciones para errores y respuestas exitosas, y configurarlas con los parámetros:

Ahora podemos decirle al usuario más errores informativos y respuestas:
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)) }
Intent
representación
Si creamos una extensión de destino de la interfaz de usuario de Intent Extension , entonces podemos dibujar una vista personalizada en Siri para los intentos que necesitamos. Tenemos MainInterface.storyboard
e IntentViewController
en el que podemos esbozar su diseño. Este controlador de vista implementa el protocolo INUIHostedViewControlling y la vista se configureView
en el método 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 }
Para llamar a este método, es necesario agregar el nombre de nuestra intención a la matriz NSExtension
-> NSExtensionAttributes
-> IntentsSupported
, que se refiere a la interfaz de usuario de Intentos de destino de extensión
<key>NSExtension</key> <dict> <key>NSExtensionAttributes</key> <dict> <key>IntentsSupported</key> <array> <string>OrderPizzaIntent</string> </array> </dict>
Dependiendo del diseño de su vista en Siri y de la interaction.intent
que se introdujo en el método, puede dibujar esta vista de la manera que desee. A continuación se muestran capturas de pantalla de cómo se ve nuestra intención en Siri, en la búsqueda y en una pantalla bloqueada.

Vale la pena considerar que el usuario no podrá interactuar con botones, desplazamiento y otros controles en su vista, ya que el método se llama con el parámetro interactiveBehavior = .none
, esto ciertamente impone una serie de limitaciones.
Total
Un Intent
directo basado en la Intent
puede representarse en la interfaz siri o en el centro de notificaciones y realizar una acción sin abrir la aplicación. Para crearlo necesitas:
- Habilitar capacidades para usar Siri
- Crear extensiones de intenciones y UI de extensiones de intenciones
- Crear archivo de definición de intención SiriKit
- Creamos nuestra
Intent
en este archivo y le asignamos parámetros. - Cree un
IntentHandler
en el que implementemos los hanlde
confirm
y hanlde
Recomendaciones
Código genérico en el objetivo de extensión Siri y la aplicación principal
Si tiene un código que se usa tanto en el destino de Siri como en el objetivo del proyecto principal, hay 2 formas de resolver este problema:
- Resalte las clases comunes y agréguelos a ambos objetivos. ( Ver → Utilidades → Mostrar inspector de archivos 'e, en la sección Membresía de destino agregue marcas de verificación a los objetivos que necesitan acceso al archivo seleccionado)
- Cree uno o más marcos de destino y lleve el código general allí.
El último método es preferible, ya que puede usar estos marcos en otras extensiones y proyectos. También vale la pena señalar que es aconsejable establecer el indicador Allow app extension API only
para estos marcos, luego, al desarrollar el marco, el compilador jurará si intenta usar una API que es ilegal en el desarrollo de extensiones (por ejemplo, UIApplication
).
Los recursos compartidos se pueden hurgar entre objetivos a través de Grupos de aplicaciones
Depuración
Los accesos directos de prueba ayudarán a ayudar:
- Configuración del teléfono Configuración → Desarrollador : Mostrar accesos directos recientes y Mostrar donaciones en los interruptores de la pantalla de bloqueo :

- Para probar Intens, puede iniciar inmediatamente la extensión de destino especificando en Xcode la frase con la que Siri se abre. Para hacer esto, seleccione el esquema para la extensión de destino Siri

Haga clic en este objetivo, haga clic en Editar esquema ...

En el campo Consulta de intención de Siri , ingrese una frase con la que Siri ya comenzará, como si ya lo hubiera dicho.
Total
Propongo parar y resumir lo que hicimos:
- Los accesos directos se pueden crear a través de
NSUserActivity
o a través de INIntent
- Los atajos se deben declarar (declarar), informar al sistema (donar) y procesar (manejar).
- Puede agregar el botón " Agregar a Siri " a la aplicación, haciendo clic en el cual el usuario puede agregar una frase para la acción y luego llamarla con su voz.
- Puede crear sus propias
Intents
además de las integradas. - Mediante accesos
Intents
basados en intenciones Intents
puede crear acciones que se realizarán a través de la interfaz Siri (ya sea en una pantalla bloqueada o en búsqueda) sin la necesidad de abrir la aplicación.
En la documentación de Apple hay un enlace al proyecto de demostración , que es útil para descargar y centrarse en él durante el desarrollo.
Me gustaría enfatizar que al momento de escribir este artículo es una API en la etapa beta
. Y a menudo atrapo problemas y errores. Durante el trabajo, periódicamente encontré lo siguiente:
- , Intent Siri, .
- Siri .
- Siri.
Referencias
- 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