上一篇我們討論了UWP和Desktop Extension互動中,Desktop Extension執行後立即退出的場景。下圖是提到的四種場景分類:
- 執行後立即退出
- 等待request,處理完後退出
- 一或多個request/response週期
- 和UWP程式相同生命週期
本篇我們討論第二種,Desktop Extension等待request後,根據傳參完成操作後退出的,短生命週期場景。該型別有以下特徵:
- 可能存在多次的單向呼叫
- 通過request接收引數
- 不關心返回結果
- Desktop Extension等待request,完成操作後退出
該場景的示意圖如下:
我們依然以Desktop Extension啟動mspaint.exe和control.exe來舉例。和上一篇不同的是,這次我們會通過UWP端發起的request來傳遞引數。
本篇Sample Code中的AppServiceHandler,以及App.xaml.cs中的OnBackgroundActivated方法。請參考《2020年的UWP(2)——In Process App Service》,相同部分不再介紹。
本篇新增的AppServiceConnectionConnectedEventArgs物件及Connected事件,是當AppServiceConnection通過OpenAsync方法成功連線時,傳遞當前活動的AppServiceConnection物件,以便呼叫SendMessageAsync等方法。
public class AppServiceConnectionConnectedEventArgs : EventArgs { public AppServiceConnection Connection { get; } public AppServiceConnectionConnectedEventArgs(AppServiceConnection connection) { Connection = connection; } } public event EventHandler<AppServiceConnectionConnectedEventArgs> Connected;
在AppServiceHandler中的OnBackgroundActivated方法中,我們首要做的,即是通知訂閱物件,有AppServiceConnection被成功Open了,請及時響應。
public void OnBackgroundActivated(AppServiceTriggerDetails details) { Connected?.Invoke(this, new AppServiceConnectionConnectedEventArgs(details.AppServiceConnection)); Connection = details.AppServiceConnection; Connection.RequestReceived += Connection_RequestReceived; }
訂閱這個Connected事件的,一般都是Desktop Extension的發起方。比如說UWP端的某個Button。
private async void ButtonLaunchApp_Click(object sender, RoutedEventArgs e) { if (ApiInformation.IsApiContractPresent("Windows.ApplicationModel.FullTrustAppContract", 1, 0)) { AppServiceHandler.Instance.Connected += Instance_Connected; await FullTrustProcessLauncher.LaunchFullTrustProcessForCurrentAppAsync(); } } private async void Instance_Connected(object sender, AppServiceConnectionConnectedEventArgs e) { AppServiceHandler.Instance.Connected -= Instance_Connected; var valueSet = new ValueSet(); valueSet.Add("FileName", ComboBoxFileName.SelectionBoxItem); var response = await e.Connection.SendMessageAsync(valueSet); }
之所以需要這個Connect事件,是因為通過SendMessageAsync傳參,需要依賴當前活動的AppServiceConnection物件。我們正是通過Connected事件,將AppServiceConnection物件傳遞給訂閱者,使其能夠訪問SendMessageAsync等方法進行資料互動。
在Instance_Connected方法中,在每次點選按鈕時,均啟動一個新的Desktop Extension程式。在Desktop Extension程式中,會通過OpenAsync方法來連線AppServiceConnection。之後便是由OnBackgroundActivated方法觸發Connected事件,接下來就是發起request。
該場景中,Desktop Extension僅需維持一個較短的生命週期,在等到request後,根據傳參完成相應操作,就可以釋放資源安全退出了。對整個APP而言,既不會長期佔用過多資源,也不會導致UWP端無法Suspend。
下圖中的綠色葉子圖示,在Desktop Extension執行時,是不會出現的。
同時我們要知道AppService的生命週期是不可控的,在UWP端程式最小化以後,Windows會在一段時間後停止AppService,AppServiceConnection也會被dispose。所以儲存一個AppServiceConnection長期物件,用來和永不退出的Desktop Extension通訊並不是個好主意。
以下是Desktop Extension端的部分程式碼,為了方便觀察應用程式的行為,我在Sample中將Enrivonment.Exit給註釋掉了。
public async Task InitializeAsync() { Connection = new AppServiceConnection(); Connection.PackageFamilyName = Package.Current.Id.FamilyName; Connection.AppServiceName = "ParameterAppService"; AppServiceConnectionStatus status = await Connection.OpenAsync(); if (status != AppServiceConnectionStatus.Success) { Console.WriteLine(status); } else { Console.WriteLine(status); Connection.RequestReceived += Connection_RequestReceived; } } private void Connection_RequestReceived(AppServiceConnection sender, AppServiceRequestReceivedEventArgs args) { var content = args.Request.Message["FileName"].ToString(); Process.Start(content); Console.WriteLine("Will exit after received."); //Environment.Exit(0); }
本篇簡單介紹了“等待request,處理完後退出”,這一UWP和Desktop Extension資料互動的場景。感謝看到這裡的同學,單純的文字其實很難講清楚AppService的使用,還請參考Github上的例項程式碼,歡迎評論及提問。