从 Cortana 中的后台应用到前台应用的深层链接
警告
自 Windows 10 2020 年 5 月更新(版本 2004,codename“20H1”)起,不再支持此功能。
从 Cortana 中的后台应用提供深层链接,以便在特定状态或上下文中将应用启动到前台。
注意
启动前台应用时,Cortana 和后台应用服务都会终止。
深层链接默认显示在 Cortana 完成屏幕上,如下所示(“转到 AdventureWorks”),但你可以在其他各种屏幕上显示深层链接。
概述
用户可以使用以下方式通过 Cortana 访问你的应用:
- 将应用激活为前台应用(请参阅通过 Cortana 使用语音命令激活前台应用)。
- 将特定功能公开为后台应用服务(请参阅在 Cortana 中使用语音命令激活后台应用)。
- 深层链接到特定的页面、内容以及状态或上下文。
本文将介绍深层链接。
当 Cortana 和应用服务充当全功能应用的网关(而不要求用户通过“开始”菜单启动应用)时,或者需要提供对应用中更丰富细节和功能的访问(无法通过 Cortana 做到这一点)时,深层链接非常有用。 深层链接是提高可用性和推广应用的另一种方式。
可通过三种方式提供深层链接:
- 在各种 Cortana 屏幕上提供“转到 <应用>”链接。
- 在各种 Cortana 屏幕上的内容磁贴中嵌入链接。
- 以编程方式从后台应用服务启动前台应用。
“转到 <应用>”深层链接
Cortana 在大多数屏幕上的内容卡下方都会显示一个“转到 <应用>”深层链接。
可为此链接提供启动参数,用于在与应用服务类似的上下文中打开应用。 如果不提供启动参数,则会在主屏幕上启动应用。
此示例摘自 AdventureWorks 示例的 AdventureWorksVoiceCommandService.cs,在其中,我们将指定的目标 (destination
) 字符串传递给 SendCompletionMessageForDestination 方法,该方法检索所有匹配的行程并提供应用的深层链接。
首先,我们创建一个由 Cortana 讲出的并显示在 Cortana 画布上的 VoiceCommandUserMessage (userMessage
)。 然后创建一个 VoiceCommandContentTile 列表对象,用于在画布上显示结果卡的集合。
然后将这两个对象传递给 VoiceCommandResponse 对象 (response
) 的 CreateResponse 方法。 然后将响应对象的 AppLaunchArgument 属性值设置为传递给此函数的 destination
的值。 当用户点击 Cortana 画布上的内容磁贴时,参数值将通过响应对象传递给应用。
最后,调用 VoiceCommandServiceConnection 的 ReportSuccessAsync 方法。
/// <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);
}
内容磁贴深层链接
可将深层链接添加到各种 Cortana 屏幕上的内容卡中。
AdventureWorks“即将到来的旅行”与转接屏幕
与使用“转到 <应用>”链接时一样,你可以提供启动参数,以便在与应用服务类似的上下文中打开应用。 如果不提供启动参数,则内容磁贴不会链接到应用。
此示例摘自 AdventureWorks 示例的 AdventureWorksVoiceCommandService.cs,在其中,我们将指定的目标传递给 SendCompletionMessageForDestination 方法,该方法检索所有匹配的行程并提供包含应用深层链接的内容卡。
首先,我们创建一个由 Cortana 讲出的并显示在 Cortana 画布上的 VoiceCommandUserMessage (userMessage
)。 然后创建一个 VoiceCommandContentTile 列表对象,用于在画布上显示结果卡的集合。
然后将这两个对象传递给 VoiceCommandResponse 对象 (response
) 的 CreateResponse 方法。 然后将 AppLaunchArgument 属性值设置为语音命令中目标的值。
最后,调用 VoiceCommandServiceConnection 的 ReportSuccessAsync 方法。 在此处,我们将两个具有不同 AppLaunchArgument 参数值的内容磁贴,添加到 VoiceCommandServiceConnection 对象的 ReportSuccessAsync 调用中使用的 VoiceCommandContentTile 列表。
/// <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);
}
编程深层链接
还可以使用启动参数以编程方式启动应用,以便在与应用服务类似的上下文中打开应用。 如果不提供启动参数,则会在主屏幕上启动应用。
在此处,我们将值为“Las Vegas”的 AppLaunchArgument 参数添加到 VoiceCommandServiceConnection 对象的 RequestAppLaunchAsync 调用中使用的 VoiceCommandResponse 对象。
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);
应用部件清单
若要启用应用的深层链接,必须在应用项目的 Package.appxmanifest 文件中声明 windows.personalAssistantLaunch
扩展。
在此处,我们将为 Adventure Works 应用声明 windows.personalAssistantLaunch
扩展。
<Extensions>
<uap:Extension Category="windows.appService"
EntryPoint="AdventureWorks.VoiceCommands.AdventureWorksVoiceCommandService">
<uap:AppService Name="AdventureWorksVoiceCommandService"/>
</uap:Extension>
<uap:Extension Category="windows.personalAssistantLaunch"/>
</Extensions>
Protocol 协定
应用使用 Protocol 协定通过统一资源标识符 (URI) 激活启动到前台。 应用必须重写其 OnActivated 事件并检查 Protocol 的 ActivationKind。 有关详细信息,请参阅处理 URI 激活。
在此处,我们将解码 ProtocolActivatedEventArgs 提供的 URI 以访问启动参数。 对于此示例,Uri 设置为“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();
}