diff --git a/CHANGELOG.md b/CHANGELOG.md index e763e5ad19..c0c82d9d30 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ ### Features -- Initial support for .NET MAUI ([#1663](https://github.com/getsentry/sentry-dotnet/pull/1663)) +- Initial support for .NET MAUI ([#1663](https://github.com/getsentry/sentry-dotnet/pull/1663)) ([#1670](https://github.com/getsentry/sentry-dotnet/pull/1670)) - Initial support for `net6.0-android` apps ([#1288](https://github.com/getsentry/sentry-dotnet/pull/1288)) ([#1669](https://github.com/getsentry/sentry-dotnet/pull/1669)) ### Fixes diff --git a/samples/Sentry.Samples.Maui/Sentry.Samples.Maui.csproj b/samples/Sentry.Samples.Maui/Sentry.Samples.Maui.csproj index 18129fde5c..4ae723a232 100644 --- a/samples/Sentry.Samples.Maui/Sentry.Samples.Maui.csproj +++ b/samples/Sentry.Samples.Maui/Sentry.Samples.Maui.csproj @@ -29,6 +29,13 @@ 21.0 10.0.17763.0 10.0.17763.0 + + + DISABLE_XAML_GENERATED_BREAK_ON_UNHANDLED_EXCEPTION + @@ -53,4 +60,11 @@ + + + + + + + diff --git a/src/Sentry.Maui/Constants.cs b/src/Sentry.Maui/Constants.cs new file mode 100644 index 0000000000..cc59423a3f --- /dev/null +++ b/src/Sentry.Maui/Constants.cs @@ -0,0 +1,12 @@ +using System.Reflection; + +namespace Sentry.Maui; + +internal static class Constants +{ + // See: https://github.com/getsentry/sentry-release-registry + public const string SdkName = "sentry.dotnet.maui"; + + public static string SdkVersion = typeof(SentryMauiOptions).Assembly + .GetCustomAttribute()!.InformationalVersion; +} diff --git a/src/Sentry.Maui/MauiEventProcessor.cs b/src/Sentry.Maui/MauiEventProcessor.cs new file mode 100644 index 0000000000..1680548be8 --- /dev/null +++ b/src/Sentry.Maui/MauiEventProcessor.cs @@ -0,0 +1,15 @@ +using Sentry.Extensibility; + +namespace Sentry.Maui; + +internal class MauiEventProcessor : ISentryEventProcessor +{ + public SentryEvent Process(SentryEvent @event) + { + // Set SDK name and version for MAUI + @event.Sdk.Name = Constants.SdkName; + @event.Sdk.Version = Constants.SdkVersion; + + return @event; + } +} diff --git a/src/Sentry.Maui/SentryMauiInitializer.cs b/src/Sentry.Maui/SentryMauiInitializer.cs index 3602eb7bf2..615522a664 100644 --- a/src/Sentry.Maui/SentryMauiInitializer.cs +++ b/src/Sentry.Maui/SentryMauiInitializer.cs @@ -9,6 +9,12 @@ internal class SentryMauiInitializer : IMauiInitializeService public void Initialize(IServiceProvider services) { var options = services.GetRequiredService>().Value; + +#if ANDROID + var context = global::Android.App.Application.Context; + SentrySdk.Init(context, options); +#else SentrySdk.Init(options); +#endif } } diff --git a/src/Sentry.Maui/SentryMauiOptionsSetup.cs b/src/Sentry.Maui/SentryMauiOptionsSetup.cs index 4afacf48c1..15bef83319 100644 --- a/src/Sentry.Maui/SentryMauiOptionsSetup.cs +++ b/src/Sentry.Maui/SentryMauiOptionsSetup.cs @@ -16,6 +16,10 @@ public override void Configure(SentryMauiOptions options) // We'll initialize the SDK in SentryMauiInitializer options.InitializeSdk = false; - // TODO: Anything MAUI specific for setting up the options. (Can inject dependencies.) + // Global Mode makes sense for client apps + options.IsGlobalModeEnabled = true; + + // We'll use an event processor to set things like SDK name + options.AddEventProcessor(new MauiEventProcessor()); } } diff --git a/src/Sentry/Android/SentrySdk.cs b/src/Sentry/Android/SentrySdk.cs index 3a5b1d9ded..9cc5573095 100644 --- a/src/Sentry/Android/SentrySdk.cs +++ b/src/Sentry/Android/SentrySdk.cs @@ -15,6 +15,14 @@ public static IDisposable Init( Action? configureOptions) { var options = new SentryOptions(); + configureOptions?.Invoke(options); + return Init(context, options); + } + + public static IDisposable Init( + global::Android.Content.Context context, + SentryOptions options) + { // TODO: Pause/Resume options.AutoSessionTracking = true; options.IsGlobalModeEnabled = true; @@ -27,8 +35,6 @@ public static IDisposable Init( return evt; })); - configureOptions?.Invoke(options); - Sentry.Android.SentryAndroid.Init(context, new JavaLogger(options), new ConfigureOption(o => { diff --git a/test/Sentry.Maui.Tests/ApiApprovalTests.Run.DotNet6_0.verified.txt b/test/Sentry.Maui.Tests/ApiApprovalTests.Run.DotNet6_0.verified.txt new file mode 100644 index 0000000000..27896e0d18 --- /dev/null +++ b/test/Sentry.Maui.Tests/ApiApprovalTests.Run.DotNet6_0.verified.txt @@ -0,0 +1,12 @@ +[assembly: System.Runtime.Versioning.TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName="")] +namespace Microsoft.Maui.Hosting +{ + public static class SentryMauiAppBuilderExtensions { } +} +namespace Sentry.Maui +{ + public class SentryMauiOptions : Sentry.Extensions.Logging.SentryLoggingOptions + { + public SentryMauiOptions() { } + } +} \ No newline at end of file diff --git a/test/Sentry.Maui.Tests/ApiApprovalTests.cs b/test/Sentry.Maui.Tests/ApiApprovalTests.cs new file mode 100644 index 0000000000..b52a2c408c --- /dev/null +++ b/test/Sentry.Maui.Tests/ApiApprovalTests.cs @@ -0,0 +1,13 @@ +using Sentry.Tests; + +namespace Sentry.Maui.Tests; + +[UsesVerify] +public class ApiApprovalTests +{ + [Fact] + public Task Run() + { + return typeof(SentryMauiOptions).Assembly.CheckApproval(); + } +} diff --git a/test/Sentry.Maui.Tests/SentryMauiAppBuilderExtensionsTests.cs b/test/Sentry.Maui.Tests/SentryMauiAppBuilderExtensionsTests.cs index b530063e5c..6015a22d90 100644 --- a/test/Sentry.Maui.Tests/SentryMauiAppBuilderExtensionsTests.cs +++ b/test/Sentry.Maui.Tests/SentryMauiAppBuilderExtensionsTests.cs @@ -95,4 +95,50 @@ public void CanUseSentry_WithConfigurationAndOptions() Assert.Equal(DsnSamples.ValidDsnWithoutSecret, options.Dsn); Assert.True(options.Debug); } + + [Fact] + public void UseSentry_EnablesGlobalMode() + { + // Arrange + var builder = MauiApp.CreateBuilder(); + + // Act + _ = builder.UseSentry(DsnSamples.ValidDsnWithoutSecret); + + using var app = builder.Build(); + var options = app.Services.GetRequiredService>().Value; + + // Assert + Assert.True(options.IsGlobalModeEnabled); + } + + [Fact] + public void UseSentry_SetsMauiSdkNameAndVersion() + { + // Arrange + SentryEvent @event = null; + var builder = MauiApp.CreateBuilder() + .UseSentry(options => + { + options.Dsn = DsnSamples.ValidDsnWithoutSecret; + options.BeforeSend = e => + { + // capture the event + @event = e; + + // but don't actually send it + return null; + }; + }); + + // Act + using var app = builder.Build(); + var client = app.Services.GetRequiredService(); + client.CaptureMessage("test"); + + // Assert + Assert.NotNull(@event); + Assert.Equal(Constants.SdkName, @event.Sdk.Name); + Assert.Equal(Constants.SdkVersion, @event.Sdk.Version); + } }