|
8 | 8 | using System.Runtime.CompilerServices;
|
9 | 9 | using System.Threading;
|
10 | 10 | using System.Threading.Tasks;
|
| 11 | +using CommunityToolkit.AppServices.Helpers; |
11 | 12 | using Windows.ApplicationModel;
|
12 | 13 | using Windows.ApplicationModel.Activation;
|
13 | 14 | using Windows.ApplicationModel.AppService;
|
14 | 15 | using Windows.ApplicationModel.Background;
|
15 | 16 | using Windows.Foundation.Collections;
|
16 | 17 | using Windows.Foundation.Metadata;
|
17 | 18 | using Windows.System.Profile;
|
18 |
| -using CommunityToolkit.AppServices.Helpers; |
| 19 | +using Windows.UI.Core.Preview; |
19 | 20 |
|
20 | 21 | #pragma warning disable CA1068
|
21 | 22 |
|
@@ -143,6 +144,58 @@ public bool OnBackgroundActivated(BackgroundActivatedEventArgs args)
|
143 | 144 | return true;
|
144 | 145 | }
|
145 | 146 |
|
| 147 | + /// <summary> |
| 148 | + /// Handles the app service host shutdown when <see cref="SystemNavigationManagerPreview.GetForCurrentView().CloseRequested"/> is raised. |
| 149 | + /// </summary> |
| 150 | + /// <param name="args">The args for the close request.</param> |
| 151 | + /// <remarks> |
| 152 | + /// <para> |
| 153 | + /// This method should be used as follows (from <c>App.xaml.cs</c>): |
| 154 | + /// <code language="cs"> |
| 155 | + /// private void OnCloseRequested(object? sender, SystemNavigationCloseRequestedPreviewEventArgs e) |
| 156 | + /// { |
| 157 | + /// // Any other work, possibly marking the request as handled |
| 158 | + /// |
| 159 | + /// DesktopExtension.OnCloseRequested(e); |
| 160 | + /// } |
| 161 | + /// </code> |
| 162 | + /// </para> |
| 163 | + /// <para> |
| 164 | + /// The app might be holding a deferral for the app service connection to the extension process, which is currently only completed when the |
| 165 | + /// connection is closed. This means that when the application is closed, that deferral will actually try to keep the connection alive, until |
| 166 | + /// the OS will eventually force terminate it. This will cause following launches of the app to be delayed until the previous process is |
| 167 | + /// completely gone, meaning that closing the app and immediately reopening it will cause it to remain stuck at the splash screen for a few |
| 168 | + /// seconds. Note that during this time, no app code is actually executed, it's just that the OS is waiting to terminate the existing connection |
| 169 | + /// and fully close the previous instance before allowing a new one to be started. To avoid this issue, this method takes care of fully closing |
| 170 | + /// any existing connection (by canceling its associated deferral), when the app is about to exit. This avoids the OS timeout for the connection. |
| 171 | + /// </para> |
| 172 | + /// </remarks> |
| 173 | + public void OnCloseRequested(SystemNavigationCloseRequestedPreviewEventArgs args) |
| 174 | + { |
| 175 | + // Do nothing if the close request has been handled |
| 176 | + if (args.Handled) |
| 177 | + { |
| 178 | + return; |
| 179 | + } |
| 180 | + |
| 181 | + // Remove the registered connection handlers |
| 182 | + if (_appServiceConnection is { } appServiceConnection) |
| 183 | + { |
| 184 | + appServiceConnection.ServiceClosed -= AppServiceConnection_ServiceClosed; |
| 185 | + appServiceConnection.RequestReceived -= AppServiceConnection_RequestReceived; |
| 186 | + |
| 187 | + _appServiceConnection = null; |
| 188 | + } |
| 189 | + |
| 190 | + // Cancel the deferral, if present |
| 191 | + if (_appServiceDeferral is { } appServiceDeferral) |
| 192 | + { |
| 193 | + appServiceDeferral.Complete(); |
| 194 | + |
| 195 | + _appServiceDeferral = null; |
| 196 | + } |
| 197 | + } |
| 198 | + |
146 | 199 | /// <summary>
|
147 | 200 | /// Creates a new <see cref="AppServiceRequest"/> for a given operation.
|
148 | 201 | /// </summary>
|
|
0 commit comments