Catch WebKit load failures on account login. Wrap the code path that opens NativeWebDialog / WebView for Audible login in a try/catch for DllNotFoundException (and related load failures). On failure, show a short dialog: install WebKit2GTK and do not crash the app.

This commit is contained in:
rmcrackan
2026-04-15 09:41:47 -04:00
parent a5912efa0c
commit 65623e8e81
2 changed files with 97 additions and 16 deletions

View File

@@ -100,12 +100,44 @@ public class AvaloniaLoginChoiceEager : ILoginChoiceEager
dialog.Source = new Uri(shoiceIn.LoginUrl);
};
if (!Configuration.IsLinux && App.MainWindow is TopLevel topLevel)
dialog.Show(topLevel);
else
dialog.Show();
// NativeWebDialog can fault on a posted dispatcher job (e.g. missing libwebkit2gtk on Linux), which bypasses a try/catch around Show().
void onUnhandledException(object? sender, DispatcherUnhandledExceptionEventArgs e)
{
if (!WebView2LoginErrorMessage.IsWebView2SignInInfrastructureFailure(e.Exception))
return;
e.Handled = true;
try
{
dialog.Close();
}
catch
{
/* ignore */
}
tcs.TrySetException(e.Exception);
}
return await tcs.Task;
Dispatcher.UIThread.UnhandledException += onUnhandledException;
try
{
try
{
if (!Configuration.IsLinux && App.MainWindow is TopLevel topLevel)
dialog.Show(topLevel);
else
dialog.Show();
}
catch (Exception ex) when (WebView2LoginErrorMessage.IsWebView2SignInInfrastructureFailure(ex))
{
tcs.TrySetException(ex);
}
return await tcs.Task;
}
finally
{
Dispatcher.UIThread.UnhandledException -= onUnhandledException;
}
void Dialog_EnvironmentRequested(object? sender, WebViewEnvironmentRequestedEventArgs e)
{

View File

@@ -11,21 +11,56 @@ public static class WebView2LoginErrorMessage
{
public const string Caption = "Sign-in browser could not start";
public static string ExplainerBody =>
"Libation could not start the in-app sign-in browser. On Windows this uses Microsoft WebView2. "
+ "This is a local sign-in or system setup issue — not a failure of the library scan itself.\r\n\r\n"
+ "Things to try:\r\n"
+ "• On Windows: install or repair the Microsoft Edge WebView2 Runtime from https://developer.microsoft.com/microsoft-edge/webview2/\r\n"
+ "• In Libation Settings, try turning off the option to use the embedded browser and use external browser sign-in instead.\r\n"
+ "• Check that security software is not blocking Libation or the embedded browser.\r\n"
+ "• Ensure your account can write to local app data folders (permissions).\r\n"
+ "• If you run as Administrator, try running Libation as a normal user (or the reverse).\r\n\r\n"
+ "After sign-in works, use Import again to scan your library.";
public static string ExplainerBody
{
get
{
const string localIssue =
"This is a local sign-in or system setup issue — not a failure of the library scan itself.\r\n\r\n";
const string thingsToTry = "Things to try:\r\n";
const string settingsBullet =
"• In Libation Settings, try turning off the option to use the embedded browser and use external browser sign-in instead.\r\n";
const string securityBullet =
"• Check that security software is not blocking Libation or the embedded browser.\r\n";
const string permissionsBullet =
"• Ensure your account can write to local app data folders (permissions).\r\n";
const string adminBullet =
"• If you run as Administrator, try running Libation as a normal user (or the reverse).\r\n\r\n";
const string footer = "After sign-in works, use Import again to scan your library.";
if (OperatingSystem.IsLinux())
{
return "Libation could not start the in-app sign-in browser. On Linux this uses WebKit2GTK (native WebKit). "
+ localIssue
+ thingsToTry
+ "• Install WebKit2GTK for your distro (e.g. on Arch: webkit2gtk or webkit2gtk-4.1).\r\n"
+ settingsBullet
+ securityBullet
+ permissionsBullet
+ adminBullet
+ footer;
}
return "Libation could not start the in-app sign-in browser. On Windows this uses Microsoft WebView2. "
+ localIssue
+ thingsToTry
+ "• On Windows: install or repair the Microsoft Edge WebView2 Runtime from https://developer.microsoft.com/microsoft-edge/webview2/\r\n"
+ settingsBullet
+ securityBullet
+ permissionsBullet
+ adminBullet
+ footer;
}
}
public static bool IsWebView2SignInInfrastructureFailure(Exception ex)
{
for (var e = ex; e is not null; e = e.InnerException)
{
// Gtk / WebView2: missing native WebKit or WebView2 runtime often surfaces as DllNotFoundException (sometimes without a useful stack).
if (e is DllNotFoundException dll && IsEmbeddedWebViewNativeDllFailure(dll))
return true;
if (!StackMentionsEmbeddedSignInBrowser(e))
continue;
@@ -40,6 +75,18 @@ public static class WebView2LoginErrorMessage
return false;
}
/// <summary>
/// Gtk WebView (e.g. Avalonia NativeWebDialog on Linux) requires WebKit2GTK; minimal installs omit <c>libwebkit2gtk</c>.
/// </summary>
private static bool IsEmbeddedWebViewNativeDllFailure(DllNotFoundException e)
{
if (e.Message.Contains("libwebkit2gtk", StringComparison.OrdinalIgnoreCase)
|| e.Message.Contains("webkit2gtk", StringComparison.OrdinalIgnoreCase))
return true;
return StackMentionsEmbeddedSignInBrowser(e);
}
public static bool TryFindInTree(Exception ex, out Exception? match)
{
Exception? found = null;
@@ -70,6 +117,8 @@ public static class WebView2LoginErrorMessage
return stack is not null
&& (stack.Contains("WebView2", StringComparison.Ordinal)
|| stack.Contains("CoreWebView2", StringComparison.Ordinal)
|| stack.Contains("NativeWebDialog", StringComparison.Ordinal));
|| stack.Contains("NativeWebDialog", StringComparison.Ordinal)
|| stack.Contains("GtkWebView", StringComparison.Ordinal)
|| stack.Contains("WebViewControlAvalonia", StringComparison.Ordinal));
}
}