Compartir a través de


Vínculo profundo desde una aplicación en segundo plano en Cortana hasta una aplicación en primer plano

Advertencia

Esta característica ya no se admite a partir de la actualización de mayo de 2020 de Windows 10 (versión 2004, nombre de código "20H1").

Consulte Cortana en Microsoft 365 para obtener información sobre cómo Cortana está transformando las experiencias de productividad modernas.

Proporcione vínculos profundos desde una aplicación en segundo plano en Cortana que inicie la aplicación en primer plano en un estado o contexto específico.

Nota:

Cortana y el servicio de aplicaciones en segundo plano finalizan cuando se inicia la aplicación en primer plano.

Un vínculo profundo se muestra de forma predeterminada en la pantalla de finalización de Cortana como se muestra aquí ("Ir a AdventureWorks"), pero puede mostrar vínculos profundos en varias otras pantallas.

Captura de pantalla de la finalización de la aplicación en segundo plano de Cortana para un próximo viaje

Información general

Los usuarios pueden acceder a la aplicación a través de Cortana:

Analizamos la vinculación profunda aquí.

La vinculación profunda es útil cuando Cortana y el servicio de aplicaciones actúan como puerta de enlace a la aplicación completa (en lugar de exigir al usuario que inicie la aplicación a través de la menú Inicio), o para proporcionar acceso a detalles y funcionalidades más completos dentro de la aplicación que no es posible a través de Cortana. La vinculación profunda es otra manera de aumentar la facilidad de uso y promover la aplicación.

Hay tres maneras de proporcionar vínculos profundos:

  • Vínculo "Ir a la <aplicación>" en varias pantallas de Cortana.
  • Vínculo incrustado en un icono de contenido en varias pantallas de Cortana.
  • Iniciar mediante programación la aplicación en primer plano desde el servicio de aplicaciones en segundo plano.

Cortana muestra un vínculo profundo "Ir a la <aplicación>" debajo de la tarjeta de contenido en la mayoría de las pantallas.

Captura de pantalla del vínculo profundo

Puede proporcionar un argumento launch para este vínculo que abra la aplicación en un contexto similar al de App Service. Si no proporciona un argumento launch, la aplicación se inicia en la pantalla principal.

En este ejemplo de AdventureWorksVoiceCommandService.cs del ejemplo AdventureWorks, pasamos la cadena de destino especificada (destination) al método SendCompletionMessageForDestination, que recupera todos los viajes coincidentes y proporciona un vínculo profundo a la aplicación.

En primer lugar, creamos un VoiceCommandUserMessage (userMessage) que habla por Cortana y se muestra en el lienzo de Cortana. A continuación, se crea un objeto de lista VoiceCommandContentTile para mostrar la colección de tarjetas de resultados en el lienzo

A continuación, estos dos objetos se pasan al método CreateResponse del objeto VoiceCommandResponse (response). A continuación, establecemos el valor de la propiedad AppLaunchArgument del objeto de respuesta en el valor de destination pasado a esta función. Cuando un usuario pulsa un icono de contenido en el lienzo de Cortana, los valores de parámetro se pasan a la aplicación a través del objeto de respuesta.

Por último, llamamos al 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);
}

Puede agregar vínculos profundos a tarjetas de contenido en varias pantallas de Cortana.

Captura de pantalla del lienzo de Cortana para finalizar el flujo de la aplicación en segundo plano de Cortana mediante el próximo viaje de AdventureWorks con entregaAdventureWorks "Próximo viaje" con pantalla de entrega

Al igual que los vínculos "Ir a la <aplicación>", puede proporcionar un argumento de inicio para abrir la aplicación con un contexto similar al de App Service. Si no proporciona un argumento launch, el icono de contenido no se vincula a la aplicación.

En este ejemplo de AdventureWorksVoiceCommandService.cs del ejemplo AdventureWorks, pasamos el destino especificado al método SendCompletionMessageForDestination, que recupera todos los viajes coincidentes y proporciona tarjetas de contenido con vínculos profundos a la aplicación.

En primer lugar, creamos un VoiceCommandUserMessage (userMessage) que habla por Cortana y se muestra en el lienzo de Cortana. A continuación, se crea un objeto de lista VoiceCommandContentTile para mostrar la colección de tarjetas de resultados en el lienzo

A continuación, estos dos objetos se pasan al método CreateResponse del objeto VoiceCommandResponse (response). A continuación, establecemos el valor de la propiedad AppLaunchArgument en el valor del destino en el comando de voz.

Por último, llamamos al método ReportSuccessAsync de VoiceCommandServiceConnection. Aquí, agregamos dos iconos de contenido con distintos valores de parámetro AppLaunchArgument a una lista VoiceCommandContentTile usada en la llamada ReportSuccessAsync del 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);
}

También puede iniciar la aplicación mediante programación con un argumento launch para abrir la aplicación con un contexto similar al de App Service. Si no proporciona un argumento launch, la aplicación se inicia en la pantalla principal.

Aquí, agregamos un parámetro AppLaunchArgument con un valor de "Las Vegas" a un objeto VoiceCommandResponse usado en la llamada RequestAppLaunchAsync del 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);

Manifiesto de aplicación

Para habilitar la vinculación profunda a la aplicación, debe declarar la extensión windows.personalAssistantLaunch en el archivo Package.appxmanifest del proyecto de aplicación.

Aquí declaramos la extensión windows.personalAssistantLaunch para la aplicación 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

La aplicación se inicia en primer plano mediante la activación del identificador uniforme de recursos (URI) mediante un contrato de protocolo. La aplicación debe invalidar el evento OnActivated de la aplicación y comprobar si hay un ActivationKind de Protocolo. Para más información, consulte Gestionar la activación de URI.

Aquí descodificamos el URI proporcionado por ProtocolActivatedEventArgs para acceder al argumento launch. En este ejemplo, el URI se establece en "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();
  }