上篇文章中咱們介紹了使用Cortana調用前臺App,不熟悉的移步到:Win10/UWP開發—使用Cortana語音指令與App的前臺交互,這篇咱們講講如何使用Cortana調用App的後臺任務,相比調用前臺的App,調用後臺任務有個有點就是App不用被啓動便可爲用戶提供服務。html
要想使用Cortana調用App後臺任務,首先咱們須要定義VCD文件,咱們依舊使用上篇中的代碼,讓它支持Cortana調用後臺任務。api
新增一個[Windows運行時組件]項目,暫時起名叫作:XiaoMiBackgroundTaskapp
建立一個類,暫且叫作XiaoMiTask,並繼承IBackgroundTaskasync
完成以下代碼:學習
//------------------------------------------------------ // // 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); } } }
代碼意思就不解釋了,寫的一手詳細的註釋不是嗎?spa
回到咱們的主程序中,在引用裏添加該後臺應用服務的引用。code
打開Package.appxmanifest文件,切換到"聲明"選項卡,添加一個應用服務的聲明,名稱隨便填,一會VCD文件裏要用到這個名字,這裏填寫XiaoMiService,別覺得是小米的意思哈,哥是米黑,是小祕。入口點填寫上面建立的後臺服務的"命名空間.類名",截圖以下:xml
在vcd語音指令中添加兩個新的Command節點,以及定義須要的PhraseTopic,對VCD文件不熟悉的移步到:Win10/UWP開發—使用Cortana語音指令與App的前臺交互htm
添加的代碼以下:blog
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文件上篇文章一毛同樣:
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 你們能夠進來一塊兒學習