-
-
Notifications
You must be signed in to change notification settings - Fork 205
/
SentryMauiAppBuilderExtensions.cs
154 lines (132 loc) · 6.64 KB
/
SentryMauiAppBuilderExtensions.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Microsoft.Maui.LifecycleEvents;
using Sentry.Extensibility;
using Sentry.Extensions.Logging.Extensions.DependencyInjection;
using Sentry.Maui;
using Sentry.Maui.Internal;
// ReSharper disable once CheckNamespace
namespace Microsoft.Maui.Hosting;
/// <summary>
/// Sentry extensions for <see cref="MauiAppBuilder"/>.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
public static class SentryMauiAppBuilderExtensions
{
/// <summary>
/// Uses Sentry integration.
/// </summary>
/// <param name="builder">The builder.</param>
/// <returns>The <paramref name="builder"/>.</returns>
public static MauiAppBuilder UseSentry(this MauiAppBuilder builder)
=> UseSentry(builder, (Action<SentryMauiOptions>?)null);
/// <summary>
/// Uses Sentry integration.
/// </summary>
/// <param name="builder">The builder.</param>
/// <param name="dsn">The DSN.</param>
/// <returns>The <paramref name="builder"/>.</returns>
public static MauiAppBuilder UseSentry(this MauiAppBuilder builder, string dsn)
=> builder.UseSentry(o => o.Dsn = dsn);
/// <summary>
/// Uses Sentry integration.
/// </summary>
/// <param name="builder">The builder.</param>
/// <param name="configureOptions">An action to configure the options.</param>
/// <returns>The <paramref name="builder"/>.</returns>
public static MauiAppBuilder UseSentry(this MauiAppBuilder builder,
Action<SentryMauiOptions>? configureOptions)
{
var services = builder.Services;
var section = builder.Configuration.GetSection("Sentry");
services.AddSingleton<IConfigureOptions<SentryMauiOptions>>(_ => new SentryMauiOptionsSetup(section));
if (configureOptions != null)
{
services.Configure(configureOptions);
}
services.AddLogging();
services.AddSingleton<ILoggerProvider, SentryMauiLoggerProvider>();
services.AddSingleton<IMauiInitializeService, SentryMauiInitializer>();
services.AddSingleton<IConfigureOptions<SentryMauiOptions>, SentryMauiOptionsSetup>();
services.AddSingleton<Disposer>();
services.TryAddSingleton<IMauiEventsBinder, MauiEventsBinder>();
services.AddSentry<SentryMauiOptions>();
builder.RegisterMauiEventsBinder();
return builder;
}
private static void RegisterMauiEventsBinder(this MauiAppBuilder builder)
{
// Bind to MAUI events during the platform-specific application creating events.
// Note that we used to do this in SentryMauiInitializer, but that approach caused the
// IApplication instance to be constructed earlier than normal, having the side-effect
// of interfering with a common approach to static DI in App.xaml.cs or AppShell.xaml.cs.
// See https://github.com/getsentry/sentry-dotnet/issues/2001
builder.ConfigureLifecycleEvents(events =>
{
#if __IOS__
events.AddiOS(lifecycle =>
{
lifecycle.FinishedLaunching((application, launchOptions) =>
{
// A bit of hackery here, because we can't mock UIKit.UIApplication in tests.
var platformApplication = application != null!
? application.Delegate as IPlatformApplication
: launchOptions["application"] as IPlatformApplication;
platformApplication?.HandleMauiEvents();
return true;
});
lifecycle.WillTerminate(application =>
{
if (application == null!)
{
return;
}
var platformApplication = application.Delegate as IPlatformApplication;
platformApplication?.HandleMauiEvents(bind: false);
//According to https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1623111-applicationwillterminate#discussion
//WillTerminate is called: in situations where the app is running in the background (not suspended) and the system needs to terminate it for some reason.
SentryMauiEventProcessor.InForeground = false;
});
lifecycle.OnActivated(application => SentryMauiEventProcessor.InForeground = true);
lifecycle.DidEnterBackground(application => SentryMauiEventProcessor.InForeground = false);
lifecycle.OnResignActivation(application => SentryMauiEventProcessor.InForeground = false);
});
#elif ANDROID
events.AddAndroid(lifecycle =>
{
lifecycle.OnApplicationCreating(application => (application as IPlatformApplication)?.HandleMauiEvents());
lifecycle.OnDestroy(application => (application as IPlatformApplication)?.HandleMauiEvents(bind: false));
lifecycle.OnResume(activity => SentryMauiEventProcessor.InForeground = true);
lifecycle.OnStart(activity => SentryMauiEventProcessor.InForeground = true);
lifecycle.OnStop(activity => SentryMauiEventProcessor.InForeground = false);
lifecycle.OnPause(activity => SentryMauiEventProcessor.InForeground = false);
});
#elif WINDOWS
events.AddWindows(lifecycle =>
{
lifecycle.OnLaunching((application, _) => (application as IPlatformApplication)?.HandleMauiEvents());
lifecycle.OnClosed((application, _) => (application as IPlatformApplication)?.HandleMauiEvents(bind: false));
});
#endif
});
}
private static void HandleMauiEvents(this IPlatformApplication platformApplication, bool bind = true)
{
// We need to resolve the application manually, because it's not necessarily
// set on platformApplication.Application at this point in the lifecycle.
var services = platformApplication.Services;
var app = services.GetService<IApplication>();
// Use a real Application control, because the required events needed for binding
// are not present on IApplication and related interfaces.
if (app is not Application application)
{
var options = services.GetService<IOptions<SentryMauiOptions>>()?.Value;
options?.LogWarning("Could not bind to MAUI events!");
return;
}
// Bind the events
var binder = services.GetRequiredService<IMauiEventsBinder>();
binder.HandleApplicationEvents(application, bind);
}
}