
Um dos recursos úteis (na minha opinião) do iOS 12 introduzidos na WWDC 2018 é o Siri Shortcuts .
Atalho ( atalho ) - um comando rápido, uma maneira curta de executar qualquer ação ignorando o script padrão.
Nos seus aplicativos, você pode ajustar atalhos para algumas ações. Aprendendo como e quando o usuário os executa, o Siri começa de maneira inteligente, no momento e no local certos, para oferecer a ele esses atalhos e, o melhor de tudo, o usuário poderá chamá-los com frases que serão anexadas a eles! Sob o gato mais.
Como isso funciona
Utilizamos aplicativos que, com determinadas ações, criam e entregam atalhos para o sistema.
Você pode visualizar esses atalhos em Configurações → Siri e Pesquisa .

A captura de tela acima mostra os três últimos atalhos que o sistema capturou de diferentes aplicativos. Se clicarmos no botão "Mais atalhos", veremos todos os atalhos entregues ao sistema por cada aplicativo.
Com certas configurações no código de criação de atalhos, a Siri oferecerá esses atalhos ao usuário em uma tela bloqueada, na central de notificações e na pesquisa, focando na frequência com que usamos essas ações, a que horas, em quais dias da semana, onde e por outros fatores.
Por exemplo, se na sexta à noite você costuma procurar caixas eletrônicos, depois de treinar, a Siri oferecerá um atalho com essa ação nas noites de sexta-feira.

Podemos adicionar nosso comando de voz a cada atalho se clicarmos no ícone " + ".
Dizemos um comando de voz, pressione "Concluído" e agora podemos executar a ação por trás do atalho usando a voz da Siri. Acontece que o usuário poderá executar a funcionalidade do seu aplicativo através do Siri sem abrir o próprio aplicativo. O atalho com a frase é preservado em "Meus atalhos".
Criando atalhos
Para o desenvolvimento, precisaremos do Xcode 10 e do iOS 12. No momento da redação, os dois estão na fase Beta .
Um atalho pode ser criado pelo NSUserActivity
ou pelo Intent
.
O primeiro caso:
O usuário clica no atalho, que passa o comando com parâmetros ( NSUserActivity
) para o nosso aplicativo, e decide como esse comando deve ser processado (abra a janela da taxa atual de USD ou a janela de pedidos da nossa pizza favorita). Este é o bom e antigo atalho do Spotlight que todos conhecemos, mas oferecido de forma inteligente pela Siri.
Segundo caso:
Os atalhos criados por meio do Intent
mais interessantes - eles permitem que você execute um comando imediatamente na interface Siri sem iniciar o aplicativo. Anteriormente, o conjunto de Intent
era difícil para a Apple: transferir dinheiro, enviar mensagens e outros . Agora, nós desenvolvedores temos a oportunidade de criar nossas Intent
!
Independentemente de como o atalho foi criado, ele passa por três estágios do ciclo de vida:
- Anúncio ( Definir )
- Entrega no sistema ( Doação )
- Processando por aplicativo ( Handle )

Minha pesquisa mostrou que um aplicativo pode fornecer no máximo 20 atalhos para o sistema.
Além disso, consideraremos como dar ao nosso aplicativo a capacidade de criar atalhos e como trabalhar com eles dentro dele.
Criando atalhos por meio do NSUserActivity
Vamos analisar o primeiro tipo simples de atalhos que são abertos por meio do NSUserActivity
.
Por exemplo, no aplicativo de banco móvel, temos uma tela de pesquisa em caixas eletrônicos e geralmente os procuro. Para acessar a tela com um cartão ATM, eu tenho que iniciar o aplicativo, vá para a aba “Mais” na aba, selecione a seção “Info” e clique no botão “ATMs”.
Se criarmos um atalho que leva imediatamente a essa tela, o usuário poderá acessá-lo com um toque quando a Siri oferecer a ele, por exemplo, em uma tela bloqueada.
Declarar atalho
O primeiro passo é declarar um tipo como o NSUserActivity
(podemos dizer que esse é o seu identificador) em info.playlist :
<key>NSUserActivityTypes</key> <array> <string>ru.tinkoff.demo.show-cashMachine</string> </array>
Anunciado.
Entregue o atalho para o sistema (Doação)
Após a declaração, podemos criar NSUserActivity
no código do nosso aplicativo com o tipo que definimos acima em info.playlist :
let activity = NSUserActivity(activityType: "ru.tinkoff.demo.show-cashMachine")
Para que a atividade entre na lista de atalhos do sistema, ela deve ser configurada como title
e definir a propriedade isEligibleForSearch
como true
. Outras propriedades não são necessárias para adicionar atalhos, mas sua presença torna o atalho mais legível e fácil de usar.
Fogo! NSUserActivity
é, para entregá-lo ao sistema, resta dar o último passo.
ViewConroller
possui uma propriedade userActivity
, à qual precisamos atribuir a activity
criada acima:
self.userActivity = activity
Assim que essa linha for executada, um atalho será criado a partir dessa atividade. Ele será entregue ao sistema e exibido nas configurações da Siri ( Configurações → Siri e Pesquisa ). Em seguida, a Siri poderá oferecer ao usuário, e o usuário poderá atribuir a ele seu comando de voz.
Nota : A documentação da Apple diz que, em vez de atribuir atividade ao controlador de exibição, basta chamar o método becomeCurrent()
na becomeCurrent()
. No entanto, esta ação não entregou atividade ao meu sistema e o atalho não apareceu na lista
Em seguida, chame o método becomeCurrent()
no objeto de atividade do usuário para marcá-lo como atual, o que doa a atividade à Siri. Como alternativa, você pode anexar o objeto a um objeto UIViewController ou UIResponder, que também marca a atividade como atual.
Para verificar se tudo funcionou, abra Configurações> Siri e pesquise - o atalho com base em nossa atividade deve estar na lista.
Processando atalhos por aplicativo (identificador)
Quando um usuário navega pelo atalho a partir do centro de notificação ou o ativa por voz, o aplicativo é iniciado e precisamos processar esse atalho.
activity
lançada para nós no AppDelegate
', um método:
func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool { if userActivity.activityType == "ru.tinkoff.demo.show-cashMachine" {
Total
Um NSUserActivity
NSUserActivity é criado da seguinte maneira:
- Declare o tipo (identificador) de
NSUserActivity
em NSUserActivity
. - Criamos
NSUserActivity
no código e configuramos viewController'
.
Criando comandos de voz a partir de um aplicativo
Portanto, se o usuário abrir Configurações> Siri e pesquisar , ele verá uma lista de seus atalhos, criados por vários aplicativos, incluindo o nosso. Ao clicar no " + ", o usuário pode criar qualquer comando de voz e associá-lo ao atalho selecionado. No entanto, cada vez que entrar nas configurações é inconveniente para o usuário, muitos nem percebem essa possibilidade.
É legal poder anexar um comando de voz a uma ação específica diretamente dentro do aplicativo.
Suponha que um usuário execute alguma ação, seja entregue ao sistema, ele queira salvá-lo. Podemos adicionar o botão " adicionar ação ao Siri " (você pode nomear e desenhar o botão como desejar) na tela do nosso aplicativo, para que o usuário, ao clicar nele, possa associar esta ação a um comando de voz dentro do aplicativo sem acessar as configurações.
Ao clicar no botão, você deve abrir modalmente a tela para adicionar um comando de voz a um atalho no Siri INUIAddVoiceShortcutViewController
, ou a tela para editar um comando de voz INUIEditVoiceShortcutViewController
, se já tiver sido criado. A action
não reagida desse botão será aproximadamente a seguinte:
@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 } } }
Portanto, as telas para adicionar e editar um comando de voz para o atalho Siri são exibidas:

Também devemos implementar os métodos delegados desses viewControllers, nos quais eles precisam ocultar dismiss(animated: true, completion: nil)
e, se necessário, atualizar a tela atual. Por exemplo, se houve um botão "adicionar comando de voz" na tela anteriormente, depois de adicionar um comando de voz, esse botão deve desaparecer ou mudar para "editar comando de voz".
Atalhos de intenção
Até o momento, falamos apenas sobre atalhos que abrem um aplicativo e transmitem NSUserActivity
dados para o NSUserActivity
.
Mas voltemos aos atalhos criados pelo Intent
, que permitem executar algumas ações sem abrir o aplicativo. Aqui a diversão começa.
Imagine que um usuário peça sua pizza favorita. Ele fará o pedido várias vezes sempre que quiser, e até adicionou um comando de voz ao atalho dessa pizza - e isso simplifica sua vida. Mas podemos fazer mais por ele - podemos garantir que, dando o comando de voz Siri, o sistema não o jogue no aplicativo, mas exiba informações sobre pedidos e solicite pizza imediatamente na interface Siri! Este é apenas o caso em que o usuário não precisa abrir o aplicativo em si para executar alguma ação.
Primeiro, vá para as configurações do projeto, selecione o destino principal, a guia Capabilities
e habilite o acesso ao Siri.
Nosso aplicativo pode interagir com o Siri, mas isso não acontece no código principal do aplicativo, mas em uma extensão de destino separada.
Para começar, esse destino deve ser criado: Arquivo → Novo → Destino , selecione Extensões de Intenção . O Xcode oferecerá a criação de outra extensão de destino para a janela que exibe suas ações no Siri. Se houver necessidade, concordamos.

Declarar atalho
A principal inovação do SiriKit no iOS 12 é a capacidade de criar seus Inetnts
, para aqueles que eram anteriores.

Para fazer isso, crie um novo arquivo: Arquivo → Novo → Arquivo , selecionando Arquivo de definição de intenção do SiriKit na seção Recurso .

Como resultado, um arquivo com a extensão .intentdefinition é exibido , no qual você pode criar seus próprios Intents
. Abrimos o arquivo e, onde está escrito " Sem Intenção ", na parte inferior, há um ícone " + " - clique nele. " Nova intenção ". Uma intenção aparecerá na lista à qual você pode adicionar parâmetros. No caso de um pedido de pizza, você pode adicionar o número de pizzas e o tipo de pizza a serem pedidos como parâmetros. Para a quantidade, escolhemos o tipo Integer
, e para o tipo de pizza, selecionamos o tipo Custom
, que no código será representado pela classe INObject
.
Agora, algumas linhas de frustração:
O usuário não poderá transmitir parâmetros diferentes para o mesmo comando de voz salvo. Ai!

Quais são os parâmetros para:
Suponha que você crie uma entidade "Mostrar taxa %currency
", em que currency
é um parâmetro da entidade. Isso não significa que o usuário possa dizer as frases "Mostrar a taxa de câmbio do dólar", "Mostrar a taxa de câmbio do Bitcoin" etc. Fora da caixa, isso não funcionará assim. Mas isso significa que, se o usuário analisou a taxa de câmbio do dólar, o atalho "Mostrar taxa do USD" foi criado e, quando analisou a taxa de câmbio do Bitcoin, o atalho "Mostrar taxa do BTC" foi criado, etc. Em outras palavras, ele pode ter várias shorkatas baseadas na mesma intenção, mas com parâmetros diferentes. Cada um dos atalhos, o usuário poderá solicitar seu comando de voz.
Bem, ao criar uma intenção no arquivo .intentdefinition , o Xcode gerará automaticamente uma classe para essa intenção (nota: não aparecerá nos arquivos do projeto, mas estará disponível para uso). Esse arquivo gerado automaticamente estará apenas nos destinos que possuem o arquivo .intentdefinition .
Depois de criar a intenção no arquivo .intentdefinition , podemos criar nossas intenções no código.
let intent = OrderPizzaIntent()
Entregue o atalho para o sistema (Doação)
Para que essa entidade seja incluída na lista de atalhos, é necessário incorporá-la. Para fazer isso, um objeto INInteraction
é criado com uma instância de sua intenção e o método .donate é chamado nessa .donate
let intent = OrderPizzaIntentf() // ... let interaction = INInteraction(intent: intent, response: nil) interaction.donate { (error) in // ... / }
Após a execução desse código, o atalho baseado em intenção será entregue ao sistema e exibido nas Configurações da Siri.
Processamos o aplicativo de atalho (Handle)
O próximo passo é processar a intenção quando o usuário clicar nela no Sirjest da Siri ou a chamar com um comando de voz.
Já criamos uma extensão de destino para a Siri e ela possui uma classe IntentHandler pré-criada, que possui um único método - `` handle (for intent) ''
class IntentHandler: INExtension { override func handler(for intent: INIntent) -> Any { guard intent is OrderPizzaIntent else { fatalError("Unhandled intent type: \(intent)") } return OrderPizzaIntentHandler() } }
Nota: Se o compilador não vir a classe de sua intenção, você não adicionou o arquivo de extensão de destino .intentdefinition para o Siri.
Nesse método, determinamos o tipo de intenção recebida e, para cada tipo, criamos um objeto manipulador que processará essa intenção. Crie um manipulador para o nosso OrderPizzaIntent
e implemente o protocolo OrderPizzaIntentHandling
nele, que já é gerado automaticamente após a criação do Intent na definição .intent .
O protocolo contém dois métodos de confirm
e handle
. Primeiro, confirm
é chamado onde todos os dados são verificados e a disponibilidade da ação é verificada. Em seguida, o handle
funcionará em uma ação curta a ser executada.
public class OrderPizzaIntentHandler: NSObject, OrderPizzaIntentHandling { public func confirm(intent: OrderPizzaIntent, completion: @escaping (OrderPizzaIntentResponse) -> Void) {
Ambos os métodos devem definitivamente chamar a completion
com a resposta OrderPizzaIntentResponse
(também é gerada automaticamente), caso contrário, a Siri irá esperar um longo tempo e, em seguida, cometer um erro.
Respostas mais detalhadas da Siri
Existe um conjunto padrão de códigos de resposta gerados automaticamente - enum OrderPizzaIntentResponseCode
, mas eles podem não ser suficientes para uma interface amigável. Por exemplo, no estágio de confirm
, vários erros diferentes podem ocorrer - a pizza acabou, a pizzaria não está funcionando no momento, etc. e o usuário deve aprender sobre esses fatos, em vez da mensagem padrão "Erro de aplicativo". Lembre-se de que criamos Intent
no arquivo .intentdefinition ? Juntamente com a intenção em si, sua Response
na qual você pode adicionar suas próprias opções para erros e respostas bem-sucedidas e configurá-las com os parâmetros:

Agora podemos dizer ao usuário erros e respostas mais informativos:
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)) }
Renderização Intent
Se criamos uma extensão de destino da interface do usuário de Intent Extension , podemos desenhar uma Siri na Siri para as intenções de que precisamos. Temos MainInterface.storyboard
e IntentViewController
nos quais podemos esboçar seu design. Este controlador de visualização implementa o protocolo INUIHostedViewControlling e a visualização é configureView
no 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 que esse método seja chamado, você precisa adicionar o nome de nossa intenção à matriz NSExtension
-> NSExtensionAttributes
-> IntentsSupported
, que se refere à interface de destino Intents UI
<key>NSExtension</key> <dict> <key>NSExtensionAttributes</key> <dict> <key>IntentsSupported</key> <array> <string>OrderPizzaIntent</string> </array> </dict>
Dependendo do design da sua exibição no Siri e da interaction.intent
que entrou no método, você pode desenhar essa exibição da maneira que desejar. Abaixo estão as capturas de tela de como é nossa intenção no Siri, na pesquisa e em uma tela bloqueada.

Vale a pena considerar que o usuário não poderá interagir com botões, rolagem e outros controles na sua exibição, pois o método é chamado com o parâmetro interactiveBehavior = .none
, isso certamente impõe uma série de limitações.
Total
Um atalho baseado em Intent
pode ser renderizado na interface siri ou no centro de notificação e executar uma ação sem abrir o aplicativo. Para criá-lo, você precisa:
- Habilitar recursos para usar o Siri
- Criar Intents Extensions e Intents Extensions UI
- Criar arquivo de definição de intenção SiriKit
- Criamos nossa
Intent
nesse arquivo e atribuímos parâmetros a ele. - Crie um
IntentHandler
no qual implementamos os hanlde
confirm
e hanlde
Recomendações
Código genérico no destino da extensão Siri e no aplicativo principal
Se você tiver um código usado no destino da Siri e no destino do projeto principal - existem duas maneiras de resolver esse problema:
- Destaque as classes comuns e adicione-as aos dois destinos. ( Exibir → Utilitários → Mostrar inspetor de arquivos 'e, na seção Associação ao destino , adicione marcas de seleção aos destinos que precisam acessar o arquivo selecionado)
- Crie uma ou mais estruturas de destino e leve o código geral para lá.
O último método é preferível, porque você pode usar essas estruturas em outras extensões e projetos. Também é importante notar que, para essas estruturas, é aconselhável definir o sinalizador Allow app extension API only
e, ao desenvolver a estrutura, o compilador jurará se você tentar usar uma API ilegal no desenvolvimento de extensões (por exemplo, UIApplication
).
Recursos compartilhados podem ser vasculhados entre destinos por meio de Grupos de aplicativos
Depuração
Testar atalhos ajudará a ajudar:
- Configurações do telefone Configurações → Desenvolvedor : exibir atalhos recentes e exibir doações nas opções da tela de bloqueio :

- Para testar o Intens, você pode iniciar imediatamente a extensão de destino especificando no Xcode a frase que a Siri abre. Para fazer isso, selecione o esquema para a extensão de destino Siri

Clique neste destino, clique em Editar esquema ...

No campo Consulta de intenção da Siri , insira uma frase com a qual a Siri já iniciará, como se você já tivesse dito.
Total
Proponho parar e resumir o que fizemos:
- Os atalhos podem ser criados através do
NSUserActivity
ou através do INIntent
- Os atalhos precisam ser declarados (declarar), relatados ao sistema (doar) e processados (manipular).
- Você pode adicionar o botão " Adicionar à Siri " ao aplicativo, clicando no qual o usuário pode adicionar uma frase para a ação e, posteriormente, chamá-la com sua voz.
- Você pode criar suas próprias
Intents
, além do incorporado. - Através dos
Intents
baseados no Intents
você pode criar ações que serão executadas através da interface Siri (em uma tela bloqueada ou em pesquisa) sem a necessidade de abrir o próprio aplicativo.
Na documentação da Apple, há um link para o projeto Demo , que é útil para baixar e focar nele durante o desenvolvimento.
Gostaria de enfatizar que, no momento da redação deste artigo, há uma API na fase beta
. E eu sempre pego problemas e bugs. Durante o trabalho, periodicamente me deparei com o seguinte:
- , Intent Siri, .
- Siri .
- Siri.
Referências
- 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