Collegamento diretto da un'app in background in Cortana a un'app in primo piano
Avviso
Questa funzionalità non è più supportata a partire dall'aggiornamento di Windows 10 di maggio 2020 (versione 2004, nome codice "20H1").
Fornire collegamenti diretti da un'app in background in Cortana che avvia l'app in primo piano in un contesto o stato specifico.
Nota
Cortana e il servizio dell'app in background vengono entrambi terminati all'avvio dell'app in primo piano.
Un collegamento diretto viene visualizzato per impostazione predefinita nella schermata di completamento di Cortana, come illustrato qui ("Vai ad AdventureWorks"), ma è possibile visualizzare collegamenti diretti su altre schermate.
Panoramica
Gli utenti possono accedere all'app tramite Cortana:
- Attivandola come app in primo piano (vedere Attivare un'app in primo piano con comandi vocali tramite Cortana).
- Esponendo funzionalità specifica come servizio dell'app in background (vedere Attivare un'app sullo sfondo in Cortana usando comandi vocali).
- Collegamento diretto a pagine, contenuto, stato e contesto specifici.
Qui si illustra il deep linking.
Il deep linking è utile quando Cortana e il servizio app fungono da gateway per l'app completa (anziché richiedere all'utente di avviare l'app tramite il menu Start) o per fornire l'accesso a dettagli e funzionalità più avanzati all'interno dell'app che Cortana non fornisce. Il deep linking è un altro modo per aumentare l'usabilità e promuovere l'app.
Esistono tre modi per fornire collegamenti diretti:
- Un collegamento "Vai all'<app>" nelle varie schermate di Cortana.
- Un collegamento incorporato in un riquadro di contenuti su varie schermate di Cortana.
- Avvio dell'app in primo piano a livello di codice dal servizio app in background.
Collegamento diretto "Vai all'<app>"
Cortana visualizza "Vai all'<app>" sotto la scheda contenuto nella maggior parte delle schermate.
È possibile fornire un argomento di avvio per questo collegamento che apre l'app in un contesto simile a quello del servizio app. Se non si fornisce un argomento di avvio, l'app viene avviata nella schermata principale.
In questo esempio tratto da AdventureWorksVoiceCommandService.cs dell'esempio AdventureWorks, si passa la stringa di destinazione specificata (destination
) al metodo SendCompletionMessageForDestination, che recupera tutti i viaggi corrispondenti e fornisce un collegamento diretto all'app.
Innanzitutto, si crea un VoiceCommandUserMessage (userMessage
) pronunciato da Cortana e mostrato nell'area di disegno di Cortana. Si crea quindi un oggetto elenco VoiceCommandContentTile per visualizzare la raccolta di schede risultato nell'area di disegno.
Questi due oggetti vengono quindi passati al metodo CreateResponse dell'oggetto VoiceCommandResponse (response
). Si imposta quindi il valore della proprietà AppLaunchArgument dell'oggetto risposta sul valore di destination
passato a questa funzione. Quando un utente tocca un riquadro di contenuto nell'area di disegno di Cortana, i valori dei parametri vengono passati all'app tramite l'oggetto risposta.
Infine, si chiama il metodo ReportSuccessAsync di 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);
}
Collegamento diretto al riquadro di contenuto
È possibile aggiungere collegamenti diretti alle schede di contenuto in varie schermate di Cortana .
"Prossimo viaggio" di AdventureWorks con schermata di handoff
Analogamente ai collegamenti "Vai all'<app>", è possibile fornire un argomento di avvio per aprire l'app con un contesto simile a quello del servizio app. Se non si fornisce un argomento di avvio, il riquadro di contenuto non si collega all'app.
In questo esempio tratto da AdventureWorksVoiceCommandService.cs dell'esempio AdventureWorks, si passa la destinazione specificata al metodo SendCompletionMessageForDestination, che recupera tutti i viaggi corrispondenti e fornisce schede di contenuto con collegamenti diretti all'app.
Innanzitutto, si crea un VoiceCommandUserMessage (userMessage
) pronunciato da Cortana e mostrato nell'area di disegno di Cortana. Si crea quindi un oggetto elenco VoiceCommandContentTile per visualizzare la raccolta di schede risultato nell'area di disegno.
Questi due oggetti vengono quindi passati al metodo CreateResponse dell'oggetto VoiceCommandResponse (response
). Si imposta quindi il valore della proprietà AppLaunchArgument sul valore della destinazione nel comando vocale.
Infine, si chiama il metodo ReportSuccessAsync di VoiceCommandServiceConnection. Qui si aggiungono due riquadri di contenuto con valori dei parametri AppLaunchArgument diversi su un elenco VoiceCommandContentTile usato nella chiamata a ReportSuccessAsync dell'oggetto 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);
}
Collegamento diretto a livello di codice
È anche possibile avviare l'app a livello di codice con un argomento di avvio per aprire l'app con un contesto simile a quello del servizio app. Se non si fornisce un argomento di avvio, l'app viene avviata nella schermata principale.
Qui si aggiunge un parametro AppLaunchArgument con il valore "Las Vegas" su un oggetto VoiceCommandResponse usato nella chiamata a RequestAppLaunchAsync dell'oggetto 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 dell'app
Per abilitare il deep linking all'app, è necessario dichiarare l'estensione windows.personalAssistantLaunch
nel file Package.appxmanifest del progetto app.
Qui, si dichiara l'estensione windows.personalAssistantLaunch
per l'app Adventure Works.
<Extensions>
<uap:Extension Category="windows.appService"
EntryPoint="AdventureWorks.VoiceCommands.AdventureWorksVoiceCommandService">
<uap:AppService Name="AdventureWorksVoiceCommandService"/>
</uap:Extension>
<uap:Extension Category="windows.personalAssistantLaunch"/>
</Extensions>
Contratto protocollo
L'app viene avviata in primo piano tramite l'attivazione dell'URI (Uniform Resource Identifier) usando un contratto protocollo. L'app deve eseguire l'evento OnActivated dell'app e cercare un elemento ActivationKind per protocollo. Per altre informazioni, vedere Gestire l'attivazione dell'URI.
Qui, si decodifica l'URI fornito da ProtocolActivatedEventArgs per accedere all'argomento di avvio. Per questo esempio, l'URI è impostato su "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();
}