Win10/UWP开发—使用Cortana语音与App后台Service交互

上篇文章中我们介绍了使用Cortana调用前台App,不熟悉的移步到:Win10/UWP开发—使用Cortana语音指令与App的前台交互,这篇我们讲讲如何使用Cortana调用App的后台任务,相比调用前台的App,调用后台任务有个有点就是App不用被启动即可为用户提供服务。

要想使用Cortana调用App后台任务,首先我们需要定义VCD文件,我们依旧使用上篇中的代码,让它支持Cortana调用后台任务。

创建后台任务

新增一个[Windows运行时组件]项目,暂时起名叫做:XiaoMiBackgroundTask

创建一个类,暂且叫做XiaoMiTask,并继承IBackgroundTask

完成如下代码:

//------------------------------------------------------
//
// FileName:    XiaoMiTask.cs
// Namespace:   XiaoMiBackgroundTask
// Assembly:    XiaoMiBackgroundTask
// Description:
// Author:      aran_wang
// Created On:  2015-09-10
//------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading.Tasks;
using Windows.ApplicationModel.AppService;
using Windows.ApplicationModel.Background;
using Windows.ApplicationModel.VoiceCommands;
using Windows.Storage;

namespace XiaoMiBackgroundTask
{
    /*
    VoiceCommandServiceConnection 类是接受Cortana传递过来的信息以及给Cortana回应信息的
    里面有几个重要的方法:
        GetVoiceCommandAsync        检索用户的语音命令提交Cortana通过语音或文本。
        ReportFailureAsync          发送一个响应,表明Cortana语音命令处理失败了。
        ReportProgressAsync         发送一个响应,Cortana在处理语音命令。
        ReportSuccessAsync          发送一个响应,Cortana语音命令已成功了。
        RequestAppLaunchAsync       发送一个响应,要求Cortana启动前台应用
        RequestConfirmationAsync    发送一个响应,指示Cortana语音命令需要确认。
        RequestDisambiguationAsync  发送一个响应,表示Cortana语音命令返回多个结果,需要用户选择一个。
    */

    public sealed class XiaoMiTask : IBackgroundTask
    {
        BackgroundTaskDeferral _taskDerral;
        VoiceCommandServiceConnection _serviceConnection;
        public async void Run(IBackgroundTaskInstance taskInstance)
        {
            _taskDerral = taskInstance.GetDeferral();
            var details = taskInstance.TriggerDetails as AppServiceTriggerDetails;

            // 验证是否调用了正确的app service
            if (details == null || details.Name != "XiaoMiService")
            {
                _taskDerral.Complete();
                return;
            }
            _serviceConnection = VoiceCommandServiceConnection.FromAppServiceTriggerDetails(details);
            // 获取被识别的语音命令
            var cmd = await _serviceConnection.GetVoiceCommandAsync();
            switch (cmd.CommandName)
            {
                case "QueryTrain":
                    var date = cmd.Properties["DateTime"][0];
                    var from = cmd.Properties["From"][0];
                    var to = cmd.Properties["To"][0];
                    await QueryTrain(date, from, to);
                    break;
                case "CancelTrain":
                    var cancelTrain = cmd.Properties["City"][0];
                    CancelTrain(cancelTrain);
                    break;
            }
            _taskDerral.Complete();
        }

        private void CancelTrain(string cancelTrain)
        {
            //取消火车 交互类似
            Debug.WriteLine(cancelTrain);
        }

        private async Task QueryTrain(string date, string from, string to)
        {
            // msgback是返回给Cortana 要显示的内容
            var msgback = new VoiceCommandUserMessage();
            // msgRepeat是指当cortana对用户语音指令不明确的时候显示的,一般用来消除用户歧义
            // 比如存在让用户选择某个选项时,用户没有按照预期的操作方式去操作,cortana会显示第二消息来告诉一些操作提示信息
            var msgRepeat = new VoiceCommandUserMessage();

            //模拟火车列表,真实情况下需要调用api获取火车信息
            var trainList = new List<VoiceCommandContentTile>();
            for (var i = 0; i < 6; i++)
            {
                trainList.Add(new VoiceCommandContentTile
                {
                    AppContext = i, //用来存储该条Tile的标识  一般存储数据id
                    ContentTileType = VoiceCommandContentTileType.TitleWith68x68IconAndText,
                    Image = await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///Images/300300.jpg")),
                    Title = $"D{i + 3}8{i * 2}",
                    TextLine1 = $"出发:{DateTime.Now.AddHours(i)} - 到达:{DateTime.Now.AddHours(i + 2)}"
                });
            }

            TrainList:

            msgback.DisplayMessage = msgback.SpokenMessage = $"我找到了{date}从{from}到{to}的火车列表,请选择:";
            msgRepeat.DisplayMessage = msgRepeat.SpokenMessage = "你要告诉我你想预定哪个车次的火车:";
            // 把查询到的火车列表发回到Cortana ,注意 列表最多显示10个
            var response = VoiceCommandResponse.CreateResponseForPrompt(msgback, msgRepeat, trainList);

            // 用户选择了哪个项
            var selectedRes = await _serviceConnection.RequestDisambiguationAsync(response);

            //创建咨询用户是否确定要预定该车次的信息
            msgback.DisplayMessage = msgback.SpokenMessage = $"您确定要预定 {selectedRes.SelectedItem.Title} 次列车吗?";
            msgRepeat.DisplayMessage = msgRepeat.SpokenMessage = "请选择是或者不是";
            response = VoiceCommandResponse.CreateResponseForPrompt(msgback, msgRepeat);

            //返回让用户选择 是 或者 不是 的信息给cortana
            var result = await _serviceConnection.RequestConfirmationAsync(response);
            //如果用户选择是
            if (result.Confirmed)
            {
                //提示预定成功
                msgback.DisplayMessage = msgback.SpokenMessage = $"您成功预定了 {selectedRes.SelectedItem.Title} 次列车,{date}从{from}到{date},{selectedRes.SelectedItem.TextLine1}!";
                msgRepeat.DisplayMessage = msgRepeat.SpokenMessage = $"您成功预定了 {selectedRes.SelectedItem.Title} 次列车。";
                response = VoiceCommandResponse.CreateResponseForPrompt(msgback, msgRepeat);
            }
            else
            {
                goto TrainList;
            }
            // 返回一个操作成功的指令
            await _serviceConnection.ReportSuccessAsync(response);
        }
    }
}

代码意思就不解释了,写的一手详细的注释不是吗?

回到我们的主程序中,在引用里添加该后台应用服务的引用。

注册App后台服务

打开Package.appxmanifest文件,切换到"声明"选项卡,添加一个应用服务的声明,名称随便填,一会VCD文件里要用到这个名字,这里填写XiaoMiService,别以为是小米的意思哈,哥是米黑,是小秘。入口点填写上面创建的后台服务的"命名空间.类名",截图如下:

编写VCD文件

在vcd语音指令中添加两个新的Command节点,以及定义需要的PhraseTopic,对VCD文件不熟悉的移步到:Win10/UWP开发—使用Cortana语音指令与App的前台交互

添加的代码如下:

 1 <Command Name="QueryTrain">
 2   <Example> 查询去某地的火车  </Example>
 3   <ListenFor >查询{DateTime}从{From}到{To}的火车</ListenFor>
 4   <Feedback> 正在查询{DateTime}从{From}到{To}的火车 </Feedback>
 5   <VoiceCommandService Target="XiaoMiService"/>
 6 </Command>
 7
 8
 9 <Command Name="CancelTrain">
10   <Example> 取消去某地的火车  </Example>
11   <ListenFor >取消去{City}的火车</ListenFor>
12   <Feedback> 正取消去{City}的火车 </Feedback>
13   <VoiceCommandService Target="XiaoMiService"/>
14 </Command>
15
16 <!--PhraseTopic 可以提高识别率,内部属性Subject可指定该关键字类型,比如 城市名 姓名  地址 等类型-->
17 <PhraseTopic Label="City" Scenario="Natural Language">
18   <Subject>City/State</Subject>
19 </PhraseTopic>
20 <PhraseTopic Label="From" Scenario="Natural Language">
21   <Subject>City/State</Subject>
22 </PhraseTopic>
23 <PhraseTopic Label="To" Scenario="Natural Language">
24   <Subject>City/State</Subject>
25 </PhraseTopic>
26 <PhraseTopic Label="DateTime" Scenario="Natural Language">
27   <Subject>Date/Time</Subject>
28 </PhraseTopic>

上面的Command节点中,使用了VoiceCommandService元素来标注该语音指令是要启动后台任务服务,而后台任务服务名称为XiaoMiService。

注册VCD文件

注册vcd文件上篇文章一毛一样:

1 /// <summary>
2 /// 注册语音指令
3 /// </summary>
4 private async Task InsertVoiceCommands()
5 {
6     await VoiceCommandDefinitionManager.InstallCommandDefinitionsFromStorageFileAsync(
7         await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///VoiceCommandsFile.xml")));
8 }

Ok,打开一次App完成VCD语音指令的注册,然后尽情的使用Cortana吧:

推荐一个UWP开发群:53078485 大家可以进来一起学习

时间: 2024-11-14 03:03:24

Win10/UWP开发—使用Cortana语音与App后台Service交互的相关文章

Win10/UWP开发—使用Cortana语音指令与App的前台交互

Win10开发中最具有系统特色的功能点绝对少不了集成Cortana语音指令,其实Cortana语音指令在以前的wp8/8.1时就已经存在了,发展到了Win10,Cortana最明显的进步就是开始支持调用App 的App Service.当然App Service也是Win10 App的新特性之一,通过调用App Service就可以在App没有前台运行的时候为Cortana提供数据交互.这样一来Cortana就具有了两种App交互方式: Cortana语音指令与前台App的交互 Cortana语

Win10 UWP开发系列:使用VS2015 Update2+ionic开发第一个Cordova App

安装VS2015 Update2的过程是非常曲折的.还好经过不懈的努力,终于折腾成功了. 如果开发Cordova项目的话,推荐大家用一下ionic这个框架,效果还不错.对于Cordova.PhoneGap.ionic.AngularJS这些框架或库的关系,我个人理解是这样,PhoneGap是一个商业项目,用来实现HTML5式的跨平台开发,后来Adobe公司将其中的核心代码开源,就是Cordova,Cordova只负责实现JavaScript调用原生代码的功能,是一个壳,而壳里具体用什么样式,在H

【Win10 应用开发】集成语音命令

原文:[Win10 应用开发]集成语音命令 记得老周以前在写WP8应用开发的文章时,曾经写过语音命令集成的文章,后来8.1的时候“小娜”问世,但考虑到其变化不大,故老周没有补写相应的文章. 今天,老周打算补一下Win 10通用应用开发中,有关语音命令集成相关的内容.虽然还是一脉相承,大的变化没有,不过Win10 sdk在语音命令定义文件中添加了新内容,而且现在不仅能在手机应用中加入语音集成,在面向PC和板子的应用中也能如愿,因为应用程序已经通用. 同理,在开始之前,老周仍然先给大家讲个故事. 话

Win10 UWP开发系列:解决Win10不同版本的Style差异导致的兼容性问题

原文:Win10 UWP开发系列:解决Win10不同版本的Style差异导致的兼容性问题 最近在开发一个项目时,遇到了一个奇怪的问题,项目依赖的最低版本是10586,目标版本是14393,开发完毕发布到商店后,很多用户报无法正常加载页面.经查,有问题的都是Win10 10586版本. 我上篇博客中写到的自定义的AppBar控件,也存在这个问题,10586会报错. 为此特意下载了10586的SDK调试.错误显示,一个样式找不到,名为ListViewItemBackground.因为开发的时候是基于

Win10 UWP开发系列——开源控件库:UWPCommunityToolkit

原文:Win10 UWP开发系列--开源控件库:UWPCommunityToolkit 在开发应用的过程中,不可避免的会使用第三方类库.之前用过一个WinRTXamlToolkit.UWP,现在微软官方发布了一个新的开源控件库—— UWPCommunityToolkit 项目代码托管在Github上:https://github.com/Microsoft/UWPCommunityToolkit 包括以下几个类库: 都可以很方便的从Nuget上安装. NuGet Package Name des

UWP开发:教你给App加上动态磁贴

UWP开发:教你给App加上动态磁贴 UWP应用的一大特色就是动态磁贴,所以,你的应用如果还没有设置动态磁贴,那么,和我一起来为应用加上动态磁贴吧! UWP动态磁贴可以通过消息推送实现,可以通过后台任务实现.我所用的方式,是通过注册后台任务的方式来实现. 方法: 使用后台任务更新动态磁贴: 其中,用到的API主要有如下两个. IBackgroundTask BackgroundTaskBuilder 第一步:创建后台任务项目: 要为应用启用动态磁贴,请向你的解决方案中添加一个新的 Windows

Win10 UWP开发系列:实现Master/Detail布局

在开发XX新闻的过程中,UI部分使用了Master/Detail(大纲/细节)布局样式.Win10系统中的邮件App就是这种样式,左侧一个列表,右侧是详情页面.关于这种 样式的说明可参看MSDN文档:https://msdn.microsoft.com/zh-cn/library/windows/apps/xaml/dn997765.aspx 样式如下: 在微软官方的Sample里,有这种样式的代码示例,下载地址:https://github.com/Microsoft/Windows-univ

Win10 UWP开发实现Bing翻译

微软在WP上的发展从原来的Win7到Win8,Win8.1,到现在的Win10 UWP,什么是UWP,UWP即Windows 10 中的Universal Windows Platform简称.即Windows通用应用平台,在Win 10 Mobile/Surface(Windows平板电脑)/PC/Xbox/HoloLens等平台上运行,uwp不同于传统pc上的exe应用也跟只适用于手机端的app有本质区别.它并不是为某一个终端而设计,而是可以在所有windows10设备上运行. 简单的说,u

Win10/UWP开发—凭据保险箱PasswordVault

PasswordVault用户凭据保险箱其实并不算是Win10的新功能,早在Windows 8.0时代就已经存在了,本文仅仅是介绍在UWP应用中如何使用凭据保险箱进行安全存储和检索用户凭据. 那么什么是凭据保险箱呢?简单的说就是开发者可以在用户输入完凭证(一般是用户名和密码),凭证有效的情况下将该凭证存储在叫做"凭据保险箱"里,该凭据保险箱里的用户凭据将会自动漫游到用户设备的Windows账户中并随时能够再次被App获取. 例如:有一个UWP的App运行在PC上,某用户在使用该App时