Deep-Link aus einer Hintergrund-App in Cortana zu einer Vordergrund-App

Warnung

Diese Funktion wird seit dem Windows 10 Mai 2020 Update (Version 2004, Codename „20H1“) nicht mehr unterstützt.

Unter Cortana in Microsoft 365 erfahren Sie, wie Cortana die moderne Produktivität verändert.

Stellen Sie Deep-Links aus einer Hintergrund-App in Cortana bereit, die die App in einem bestimmten Zustand oder Kontext im Vordergrund startet.

Hinweis

Sowohl Cortana als auch der Hintergrund-App-Service werden beendet, wenn die Vordergrund-App gestartet wird.

Ein Deep-Link wird standardmäßig auf dem Cortana-Abschlussbildschirm angezeigt, wie hier gezeigt („Gehe zu AdventureWorks“), aber Sie können Deep-Links auf verschiedenen anderen Bildschirmen anzeigen.

Screenshot des Abschlusses der Cortana-Hintergrund-App für eine bevorstehende Reise

Übersicht

Benutzer können über Cortana auf Ihre App zugreifen, indem sie:

Hier besprechen wir Deep Linking.

Deep Linking ist nützlich, wenn Cortana und Ihr App Service als Gateway zu Ihrer App mit vollem Funktionsumfang fungieren (anstatt den Benutzer auffordern, die App über das Startmenü zu starten) oder um Zugriff auf umfassendere Details und Funktionen in Ihrer App bereitzustellen, die über Cortana nicht möglich sind. Deep Linking ist eine weitere Möglichkeit, die Benutzerfreundlichkeit zu erhöhen und Ihre App zu bewerben.

Es gibt drei Möglichkeiten, Deep-Links bereitzustellen:

  • Ein „Gehe zu <App>“-Link auf verschiedenen Cortana-Bildschirmen.
  • Ein in eine Inhaltskachel eingebetteter Link auf verschiedenen Cortana-Bildschirmen.
  • Programmgesteuertes Starten der Vordergrund-App aus dem Hintergrund-App-Service.

Cortana zeigt unterhalb der Inhaltskarte auf den meisten Bildschirmen einen „Gehe zu <App>“-Deep-Link an.

Screenshot des Deep-Links von Cortana

Sie können ein Startargument für diesen Link bereitstellen, mit dem Ihre App in einem ähnlichen Kontext wie der App Service geöffnet wird. Wenn Sie kein Startargument bereitstellen, wird die App auf dem Hauptbildschirm gestartet.

In diesem Beispiel aus AdventureWorksVoiceCommandService.cs des AdventureWorks-Beispiels übergeben wir die angegebene Zielzeichenfolge (destination) an die SendCompletionMessageForDestination-Methode, die alle übereinstimmenden Reisen abruft und einen Deep-Link zur App bereitstellt.

Zunächst erstellen wir eine VoiceCommandUserMessage (userMessage), die von Cortana gesprochen und im Cortana-Kollaborationsbereich angezeigt wird. Anschließend wird ein VoiceCommandContentTile-Listenobjekt zum Anzeigen der Sammlung von Ergebniskarten auf dem Kollaborationsbereich erstellt.

Diese beiden Objekte werden dann an die CreateResponse-Methode des VoiceCommandResponse-Objekts (response) übergeben. Anschließend legen wir den AppLaunchArgument-Eigenschaftswert des Antwortobjekts auf den Wert von destination fest, der an diese Funktion übergeben wird. Wenn ein Benutzer auf eine Inhaltskachel auf dem Cortana-Kollaborationsbereich tippt, werden die Parameterwerte über das Antwortobjekt an die App übergeben.

Schließlich rufen wir die ReportSuccessAsync-Methode des VoiceCommandServiceConnection auf.

/// <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);
}

Sie können Deep-Links zu Inhaltskarten auf verschiedenen Cortana-Bildschirmen hinzufügen.

Screenshot der Cortana-Canvas zum Beenden des Cortana-Hintergrund-App-Flusses mithilfe von AdventureWorks anstehender Reise mit ÜbergabeAdventureWorks „Bevorstehende Reise“ mit Übergabebildschirm

Wie die „Gehe zu <App>“-Links können Sie ein Startargument bereitstellen, um Ihre App mit einem ähnlichen Kontext wie dem App Service zu öffnen. Wenn Sie kein Startargument bereitstellen, wird die Inhaltskachel nicht mit Ihrer App verknüpft.

In diesem Beispiel aus AdventureWorksVoiceCommandService.cs des AdventureWorks-Beispiels übergeben wir das angegebene Ziel an die SendCompletionMessageForDestination-Methode, die alle übereinstimmenden Reisen abruft und Inhaltskarten mit Deep-Links zur App bereitstellt.

Zunächst erstellen wir eine VoiceCommandUserMessage (userMessage), die von Cortana gesprochen und im Cortana-Kollaborationsbereich angezeigt wird. Anschließend wird ein VoiceCommandContentTile-Listenobjekt zum Anzeigen der Sammlung von Ergebniskarten auf dem Kollaborationsbereich erstellt.

Diese beiden Objekte werden dann an die CreateResponse-Methode des VoiceCommandResponse-Objekts (response) übergeben. Anschließend legen wir den AppLaunchArgument-Eigenschaftswert auf den Wert des Ziels im Sprachbefehl fest.

Schließlich rufen wir die ReportSuccessAsync-Methode des VoiceCommandServiceConnection auf. Hier fügen wir zwei Inhaltskacheln mit unterschiedlichen AppLaunchArgument-Parameterwerten zu einer VoiceCommandContentTile-Liste hinzu, die im ReportSuccessAsync-Aufruf des VoiceCommandServiceConnection-Objekts verwendet wird.

/// <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);
}

Sie können Ihre App auch programmatisch mit einem Startargument starten, um Ihre App in einem ähnlichen Kontext wie den App Service zu öffnen. Wenn Sie kein Startargument bereitstellen, wird die App auf dem Hauptbildschirm gestartet.

Hier fügen wir einen AppLaunchArgument-Parameter mit dem Wert „Las Vegas“ zu einem VoiceCommandResponse-Objekt hinzu, das im RequestAppLaunchAsync-Aufruf des VoiceCommandServiceConnection-Objekts verwendet wird.

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);

App-Manifest

Um Deep Linking zu Ihrer App zu ermöglichen, müssen Sie die windows.personalAssistantLaunch-Erweiterung in der Datei Package.appxmanifest Ihres App-Projekts deklarieren.

Hier deklarieren wir die windows.personalAssistantLaunch-Erweiterung für die Adventure Works-App.

<Extensions>
  <uap:Extension Category="windows.appService" 
    EntryPoint="AdventureWorks.VoiceCommands.AdventureWorksVoiceCommandService">
    <uap:AppService Name="AdventureWorksVoiceCommandService"/>
  </uap:Extension>
  <uap:Extension Category="windows.personalAssistantLaunch"/> 
</Extensions>

Protokollvertrag

Ihre App wird mithilfe eines Protokollvertrags über die URI-Aktivierung (Uniform Resource Identifier) im Vordergrund gestartet. Ihre App muss das OnActivated-Event Ihrer App außer Kraft setzen und nach einem ActivationKind von Protokoll suchen. Weitere Einzelheiten finden Sie unter Handle-URI-Aktivierung.

Hier decodieren wir den vom ProtocolActivatedEventArgs bereitgestellten URI für den Zugriff auf das Startargument. In diesem Beispiel wird der URI auf „windows.personalassistantlaunch:?LaunchContext=Las Vegas“ gesetzt.

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();
  }