Link profundo de um aplicativo em segundo plano na Cortana para um aplicativo em primeiro plano
Aviso
Não há mais suporte para este recurso a partir da atualização de maio de 2020 do Windows 10 (versão 2004, codinome "20H1").
Forneça links profundos de um aplicativo em segundo plano na Cortana que iniciem o aplicativo em primeiro plano em um estado ou contexto específico.
Observação
A Cortana e o serviço de aplicativo em segundo plano são encerrados quando o aplicativo em primeiro plano é iniciado.
Um link profundo é exibido por padrão na tela de conclusão da Cortana, conforme mostrado aqui ("Ir para o AdventureWorks"). Porém, você pode exibir links profundos em várias outras telas.
Observação
APIs importantes
Visão geral
Os usuários podem acessar o aplicativo por meio da Cortana, fazendo o seguinte:
- Ativando-o como um aplicativo em primeiro plano (consulte Ativar um aplicativo em primeiro plano com comandos de voz por meio da Cortana).
- Expondo uma funcionalidade específica como um serviço de aplicativo em segundo plano (consulte Ativar um aplicativo em segundo plano na Cortana usando comandos de voz).
- Links profundos para páginas, conteúdo e estado ou contexto específicos.
Discutimos a vinculação profunda aqui.
A vinculação profunda é útil quando a Cortana e seu serviço de aplicativo atuam como gateway para seu aplicativo completo (em vez de exigir que o usuário inicie o aplicativo por meio do menu Iniciar) ou para fornecer acesso a detalhes e funcionalidades mais ricos no seu aplicativo que não são possíveis com a Cortana. A vinculação profunda é outra maneira de aumentar a usabilidade e promover o aplicativo.
Há três maneiras de fornecer links profundos:
- Um link "Ir para o <aplicativo>" em várias telas da Cortana.
- Um link incorporado em um bloco de conteúdo em várias telas da Cortana .
- Iniciando programaticamente o aplicativo em primeiro plano pelo serviço de aplicativo em segundo plano.
Link profundo "Ir para o <aplicativo>"
A Cortana exibe um link profundo "Ir para o <aplicativo>" abaixo do cartão de conteúdo na maioria das telas.
Você pode fornecer um argumento de inicialização para esse link que abre seu aplicativo em um contexto semelhante ao serviço de aplicativo. Se você não fornecer um argumento de inicialização, o aplicativo será iniciado na tela principal.
Neste exemplo de AdventureWorksVoiceCommandService.cs da amostra AdventureWorks, passamos a cadeia de caracteres de destino (destination
) especificada para o método SendCompletionMessageForDestination, que recupera todas as viagens correspondentes e fornece um link profundo para o aplicativo.
Primeiro, criamos uma VoiceCommandUserMessage (userMessage
) que é falado pela Cortana e mostrado na tela da Cortana. Um objeto de lista VoiceCommandContentTile é criado para exibir a coleção de cartões de resultados na tela.
Esses dois objetos são então transmitidos ao método CreateResponse do objeto VoiceCommandResponse (response
). Em seguida, definimos o valor da propriedade AppLaunchArgument do objeto de resposta como o valor de destination
transmitido a essa função. Quando um usuário toca em um bloco de conteúdo na tela da Cortana, os valores de parâmetro são transmitidos ao aplicativo por meio do objeto de resposta.
Finalmente, chamamos o método ReportSuccessAsync de VoiceCommandServiceConnection.
/// <summary>
/// Show details for a single trip, if the trip can be found.
/// This demonstrates a simple response flow in Cortana.
/// </summary>
/// <param name="destination">The destination specified in the voice command.</param>
private async Task SendCompletionMessageForDestination(string destination)
{
...
IEnumerable<Model.Trip> trips = store.Trips.Where(p => p.Destination == destination);
var userMessage = new VoiceCommandUserMessage();
var destinationsContentTiles = new List<VoiceCommandContentTile>();
...
var response = VoiceCommandResponse.CreateResponse(userMessage, destinationsContentTiles);
if (trips.Count() > 0)
{
response.AppLaunchArgument = destination;
}
await voiceServiceConnection.ReportSuccessAsync(response);
}
Link profundo do bloco de conteúdo
É possível adicionar links profundos a cartões de conteúdo em várias telas da Cortana.
"Próxima viagem" da AdventureWorks com tela de transferência
Como os links "Ir para o <aplicativo>", você pode fornecer um argumento de inicialização para abrir seu aplicativo com contexto semelhante ao serviço de aplicativo. Se um argumento de inicialização não for fornecido, o bloco de conteúdo não será vinculado ao seu aplicativo.
Neste exemplo de AdventureWorksVoiceCommandService.cs da amostra AdventureWorks, transmitidos o destino especificado ao método SendCompletionMessageForDestination, que recupera todas as viagens correspondentes e fornece cartões de conteúdo com links profundos para o aplicativo.
Primeiro, criamos uma VoiceCommandUserMessage (userMessage
) que é falado pela Cortana e mostrado na tela da Cortana. Um objeto de lista VoiceCommandContentTile é criado para exibir a coleção de cartões de resultados na tela.
Esses dois objetos são então transmitidos ao método CreateResponse do objeto VoiceCommandResponse (response
). Em seguida, definimos o valor da propriedade AppLaunchArgument como o valor do destino no comando de voz.
Finalmente, chamamos o método ReportSuccessAsync de VoiceCommandServiceConnection. Adicionamos dois blocos de conteúdo com valores de parâmetro AppLaunchArgument diferentes a uma lista VoiceCommandContentTile usada na chamada ReportSuccessAsync do objeto VoiceCommandServiceConnection.
/// <summary>
/// Show details for a single trip, if the trip can be found.
/// This demonstrates a simple response flow in Cortana.
/// </summary>
/// <param name="destination">The destination specified in the voice command.</param>
private async Task SendCompletionMessageForDestination(string destination)
{
// If this operation is expected to take longer than 0.5 seconds, the task must
// supply a progress response to Cortana before starting the operation, and
// updates must be provided at least every 5 seconds.
string loadingTripToDestination = string.Format(
cortanaResourceMap.GetValue("LoadingTripToDestination", cortanaContext).ValueAsString,
destination);
await ShowProgressScreen(loadingTripToDestination);
Model.TripStore store = new Model.TripStore();
await store.LoadTrips();
// Query for the specified trip.
// The destination should be in the phrase list. However, there might be
// multiple trips to the destination. We pick the first.
IEnumerable<Model.Trip> trips = store.Trips.Where(p => p.Destination == destination);
var userMessage = new VoiceCommandUserMessage();
var destinationsContentTiles = new List<VoiceCommandContentTile>();
if (trips.Count() == 0)
{
string foundNoTripToDestination = string.Format(
cortanaResourceMap.GetValue("FoundNoTripToDestination", cortanaContext).ValueAsString,
destination);
userMessage.DisplayMessage = foundNoTripToDestination;
userMessage.SpokenMessage = foundNoTripToDestination;
}
else
{
// Set plural or singular title.
string message = "";
if (trips.Count() > 1)
{
message = cortanaResourceMap.GetValue("PluralUpcomingTrips", cortanaContext).ValueAsString;
}
else
{
message = cortanaResourceMap.GetValue("SingularUpcomingTrip", cortanaContext).ValueAsString;
}
userMessage.DisplayMessage = message;
userMessage.SpokenMessage = message;
// Define a tile for each destination.
foreach (Model.Trip trip in trips)
{
int i = 1;
var destinationTile = new VoiceCommandContentTile();
destinationTile.ContentTileType = VoiceCommandContentTileType.TitleWith68x68IconAndText;
destinationTile.Image = await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///AdventureWorks.VoiceCommands/Images/GreyTile.png"));
destinationTile.AppLaunchArgument = trip.Destination;
destinationTile.Title = trip.Destination;
if (trip.StartDate != null)
{
destinationTile.TextLine1 = trip.StartDate.Value.ToString(dateFormatInfo.LongDatePattern);
}
else
{
destinationTile.TextLine1 = trip.Destination + " " + i;
}
destinationsContentTiles.Add(destinationTile);
i++;
}
}
var response = VoiceCommandResponse.CreateResponse(userMessage, destinationsContentTiles);
if (trips.Count() > 0)
{
response.AppLaunchArgument = destination;
}
await voiceServiceConnection.ReportSuccessAsync(response);
}
Link profundo programático
Você também pode iniciar o aplicativo programaticamente com um argumento de inicialização para abri-lo com contexto semelhante ao serviço de aplicativo. Se você não fornecer um argumento de inicialização, o aplicativo será iniciado na tela principal.
Adicionamos um parâmetro AppLaunchArgument com um valor de "Las Vegas" a um objeto VoiceCommandResponse usado na chamada RequestAppLaunchAsync do objeto VoiceCommandServiceConnection.
var userMessage = new VoiceCommandUserMessage();
userMessage.DisplayMessage = "Here are your trips.";
userMessage.SpokenMessage =
"You have one trip to Vegas coming up.";
response = VoiceCommandResponse.CreateResponse(userMessage);
response.AppLaunchArgument = "Las Vegas";
await VoiceCommandServiceConnection.RequestAppLaunchAsync(response);
Manifesto de aplicativo
Para habilitar a vinculação profunda ao aplicativo, você deve declarar a extensão windows.personalAssistantLaunch
no arquivo Package.appxmanifest do seu projeto de aplicativo.
Aqui, declaramos a extensão windows.personalAssistantLaunch
para o aplicativo Adventure Works.
<Extensions>
<uap:Extension Category="windows.appService"
EntryPoint="AdventureWorks.VoiceCommands.AdventureWorksVoiceCommandService">
<uap:AppService Name="AdventureWorksVoiceCommandService"/>
</uap:Extension>
<uap:Extension Category="windows.personalAssistantLaunch"/>
</Extensions>
Contrato de protocolo
O aplicativo é iniciado em primeiro plano por meio da ativação do URI usando um contrato de Protocolo. O aplicativo deve substituir o evento OnActivated do aplicativo e verificar se há um ActivationKind de Protocolo. Para obter mais informações, consulte Lidar com a ativação de URI.
Aqui, decodificamos o URI fornecido pelo ProtocolActivatedEventArgs para acessar o argumento de inicialização. Para este exemplo, o Uri é definido como "windows.personalassistantlaunch:?LaunchContext=Las Vegas".
if (args.Kind == ActivationKind.Protocol)
{
var commandArgs = args as ProtocolActivatedEventArgs;
Windows.Foundation.WwwFormUrlDecoder decoder =
new Windows.Foundation.WwwFormUrlDecoder(commandArgs.Uri.Query);
var destination = decoder.GetFirstValueByName("LaunchContext");
navigationCommand = new ViewModel.TripVoiceCommand(
"protocolLaunch",
"text",
"destination",
destination);
navigationToPageType = typeof(View.TripDetails);
rootFrame.Navigate(navigationToPageType, navigationCommand);
// Ensure the current window is active.
Window.Current.Activate();
}
Artigos relacionados
Windows developer