Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
- The SDK now makes use of the new SessionEndStatus `Unhandled` when capturing an unhandled but non-terminal exception, i.e. through the UnobservedTaskExceptionIntegration ([#4633](https://github.com/getsentry/sentry-dotnet/pull/4633), [#4653](https://github.com/getsentry/sentry-dotnet/pull/4653))
- The SDK now provides a `IsSessionActive` to allow checking the session state ([#4662](https://github.com/getsentry/sentry-dotnet/pull/4662))
- The SDK now makes use of the new SessionEndStatus `Unhandled` when capturing an unhandled but non-terminal exception, i.e. through the UnobservedTaskExceptionIntegration ([#4633](https://github.com/getsentry/sentry-dotnet/pull/4633))
- Add missing Activity lifecycle events in MAUI apps on Android ([#4688](https://github.com/getsentry/sentry-dotnet/pull/4688))

### Fixes

Expand Down
46 changes: 43 additions & 3 deletions integration-test/android.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -54,14 +54,17 @@ Describe 'MAUI app (<tfm>, <configuration>)' -ForEach @(
{
param(
[string] $Dsn,
[string] $TestArg = 'None'
[string] $TestArg = 'None',
[string] $TestCondition = 'OnAppearing',
[scriptblock] $Callback = $null
)
Write-Host "::group::Run Android app (TestArg=$TestArg)"
$dsn = $Dsn.Replace('http://', 'http://key@') + '/0'
xharness android adb -v `
-- shell am start -S -n io.sentry.dotnet.maui.device.integrationtestapp/.MainActivity `
-e SENTRY_DSN $dsn `
-e SENTRY_TEST_ARG $TestArg
-e SENTRY_TEST_ARG $TestArg `
-e SENTRY_TEST_CONDITION $TestCondition
| ForEach-Object { Write-Host $_ }
Write-Host '::endgroup::'
$LASTEXITCODE | Should -Be 0
Expand All @@ -73,7 +76,10 @@ Describe 'MAUI app (<tfm>, <configuration>)' -ForEach @(

$procid = (& xharness android adb -- shell pidof "io.sentry.dotnet.maui.device.integrationtestapp") -replace '\s', ''
$activity = (& xharness android adb -- shell dumpsys activity activities) -match "io\.sentry\.dotnet\.maui\.device\.integrationtestapp"

if ($procid -and $activity -and $Callback)
{
& $Callback
}
} while ($procid -and $activity)
}

Expand Down Expand Up @@ -201,4 +207,38 @@ Describe 'MAUI app (<tfm>, <configuration>)' -ForEach @(
$result.Envelopes() | Should -AnyElementMatch "`"type`":`"system`",`"thread_id`":`"1`",`"category`":`"network.event`",`"action`":`"NETWORK_CAPABILITIES_CHANGED`""
$result.Envelopes() | Should -HaveCount 1
}

It 'Native native lifecycle events' {
$result = Invoke-SentryServer {
param([string]$url)
RunAndroidApp -Dsn $url -TestArg "Native" -TestCondition "OnSleep" {
xharness android adb -- shell input keyevent KEYCODE_HOME
}
RunAndroidApp -Dsn $url
}

Dump-ServerErrors -Result $result
$result.HasErrors() | Should -BeFalse
@('created', 'started', 'resumed', 'paused') | ForEach-Object {
# TODO: why is native breadcrumb data a string instead of object?
$result.Envelopes() | Should -AnyElementMatch ('"type":"navigation","data":"{\"screen\":\"MainActivity\",\"state\":\"' + $_ + '\"}\","category":"ui.lifecycle"')
}
$result.Envelopes() | Should -HaveCount 1
}

It 'Managed lifecycle events' {
$result = Invoke-SentryServer {
param([string]$url)
RunAndroidApp -Dsn $url -TestArg "Managed" -TestCondition "OnSleep" {
xharness android adb -- shell input keyevent KEYCODE_HOME
}
}

Dump-ServerErrors -Result $result
$result.HasErrors() | Should -BeFalse
@('created', 'started', 'resumed', 'paused') | ForEach-Object {
$result.Envelopes() | Should -AnyElementMatch ('"type":"navigation","data":{"screen":"MainActivity","state":"' + $_ + '"},"category":"ui.lifecycle"')
}
$result.Envelopes() | Should -HaveCount 1
}
}
25 changes: 25 additions & 0 deletions integration-test/net9-maui/App.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ public partial class App : Application
{
private static readonly ConcurrentDictionary<string, Dictionary<string, string>> systemBreadcrumbs = new();
private static string? testArg;
private static string? testCondition;

public App()
{
Expand All @@ -20,6 +21,11 @@ public static bool HasTestArg(string arg)
return string.Equals(testArg, arg, StringComparison.OrdinalIgnoreCase);
}

public static bool HasTestCondition(string condition)
{
return string.Equals(testCondition, condition, StringComparison.OrdinalIgnoreCase);
}

public static void ReceiveSystemBreadcrumb(Breadcrumb breadcrumb)
{
if (breadcrumb.Type != "system" ||
Expand Down Expand Up @@ -64,7 +70,26 @@ protected override Window CreateWindow(IActivationState? activationState)
public static void OnAppearing()
{
testArg = System.Environment.GetEnvironmentVariable("SENTRY_TEST_ARG");
testCondition = System.Environment.GetEnvironmentVariable("SENTRY_TEST_CONDITION");

if (HasTestCondition("OnAppearing"))
{
RunTest();
}
}

protected override void OnSleep()
{
base.OnSleep();

if (HasTestCondition("OnSleep"))
{
RunTest();
}
}

private static void RunTest()
{
#pragma warning disable CS0618
if (Enum.TryParse<CrashType>(testArg, ignoreCase: true, out var crashType))
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,6 @@ protected override void OnCreate(Bundle? savedInstanceState)

System.Environment.SetEnvironmentVariable("SENTRY_DSN", Intent?.GetStringExtra("SENTRY_DSN"));
System.Environment.SetEnvironmentVariable("SENTRY_TEST_ARG", Intent?.GetStringExtra("SENTRY_TEST_ARG"));
System.Environment.SetEnvironmentVariable("SENTRY_TEST_CONDITION", Intent?.GetStringExtra("SENTRY_TEST_CONDITION"));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#if ANDROID
using Microsoft.Maui.LifecycleEvents;
using Activity = Android.App.Activity;

namespace Sentry.Maui.Internal;

// Capture Android Activity lifecycle events as breadcrumbs.
// See: https://github.com/getsentry/sentry-java/blob/ab8a72db41b2e5c66e60cef3102294dddba90b20/sentry-android-core/src/main/java/io/sentry/android/core/ActivityBreadcrumbsIntegration.java
internal static class AndroidActivityBreadcrumbsIntegration
{
public static void Register(IAndroidLifecycleBuilder lifecycle)
{
lifecycle.OnCreate((activity, _) => AddBreadcrumb(activity, "created"));
lifecycle.OnStart(activity => AddBreadcrumb(activity, "started"));
lifecycle.OnResume(activity => AddBreadcrumb(activity, "resumed"));
lifecycle.OnPause(activity => AddBreadcrumb(activity, "paused"));
lifecycle.OnStop(activity => AddBreadcrumb(activity, "stopped"));
lifecycle.OnSaveInstanceState((activity, _) => AddBreadcrumb(activity, "saveInstanceState"));
lifecycle.OnDestroy(activity => AddBreadcrumb(activity, "destroyed"));
}

private static void AddBreadcrumb(Activity activity, string state)
{
var breadcrumb = new Breadcrumb(
DateTimeOffset.UtcNow,
message: null,
type: MauiEventsBinder.NavigationType,
data: new Dictionary<string, string>
{
{ "screen", activity.Class.SimpleName },
{ "state", state }
},
category: MauiEventsBinder.LifecycleCategory,
level: BreadcrumbLevel.Info
);
SentrySdk.AddBreadcrumb(breadcrumb);
}
}
#endif
5 changes: 5 additions & 0 deletions src/Sentry.Maui/Internal/SentryMauiOptionsSetup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@ public void Configure(SentryMauiOptions options)
_config.Bind(bindable);
bindable.ApplyTo(options);

#if __ANDROID__
// Disable Android Activity lifecycle breadcrumbs as Sentry.Maui already tracks these.
options.Native.EnableActivityLifecycleBreadcrumbs = false;
#endif

#if __ANDROID__ || __IOS__
options.Native.AttachScreenshot = options.AttachScreenshot;
#endif
Expand Down
2 changes: 2 additions & 0 deletions src/Sentry.Maui/SentryMauiAppBuilderExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,8 @@ private static void RegisterMauiEventsBinder(this MauiAppBuilder builder)

lifecycle.OnStop(activity => SentryMauiEventProcessor.InForeground = false);
lifecycle.OnPause(activity => SentryMauiEventProcessor.InForeground = false);

AndroidActivityBreadcrumbsIntegration.Register(lifecycle);
});
#elif WINDOWS
events.AddWindows(lifecycle =>
Expand Down
Loading