Skip to content

Commit 9b310de

Browse files
authored
fix: remove dependency on AnalyticsSessionInfo (#2625)
1 parent 31abe73 commit 9b310de

9 files changed

Lines changed: 120 additions & 78 deletions

File tree

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
## Unreleased
44

5+
### Behavioral Changes
6+
7+
- The SDK no longer relies on UnityEngine.Analytics.AnalyticsSessionInfo to determine unique users but uses SDK-internal mechanisms instead. ([#2625](https://github.com/getsentry/sentry-unity/pull/2625))
8+
59
### Fixes
610

711
- When targeting iOS or macOS, the SDK now correctly passes on the `CaptureFailedRequests` flag and set status code ranged ([#2619](https://github.com/getsentry/sentry-unity/pull/2619))

src/Sentry.Unity.Android/SentryNativeAndroid.cs

Lines changed: 7 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
using Sentry.Unity.Integrations;
44
using Sentry.Unity.NativeUtils;
55
using UnityEngine;
6-
using UnityEngine.Analytics;
76

87
namespace Sentry.Unity.Android;
98

@@ -113,25 +112,14 @@ public static void Configure(SentryUnityOptions options)
113112

114113
Logger?.LogDebug("Fetching installation ID");
115114

116-
options.DefaultUserId = SentryJava.GetInstallationId();
117-
if (string.IsNullOrEmpty(options.DefaultUserId))
115+
var installationId = SentryJava.GetInstallationId();
116+
if (!string.IsNullOrEmpty(installationId))
118117
{
119-
// In case we can't get an installation ID we create one and sync that down to the native layer
120-
Logger?.LogDebug(
121-
"Failed to fetch 'Installation ID' from the native SDK. Creating new 'Default User ID'.");
122-
123-
// We fall back to Unity's Analytics Session Info: https://docs.unity3d.com/ScriptReference/Analytics.AnalyticsSessionInfo-userId.html
124-
// It's a randomly generated GUID that gets created immediately after installation helping
125-
// to identify the same instance of the game
126-
options.DefaultUserId = AnalyticsSessionInfo.userId;
127-
if (options.DefaultUserId is not null)
128-
{
129-
options.ScopeObserver.SetUser(new SentryUser { Id = options.DefaultUserId });
130-
}
131-
else
132-
{
133-
Logger?.LogDebug("Failed to create new 'Default User ID'.");
134-
}
118+
options.DefaultUserId = installationId;
119+
}
120+
else
121+
{
122+
Logger?.LogDebug("Failed to fetch 'Installation ID' from the native SDK.");
135123
}
136124

137125
Logger?.LogInfo("Successfully configured the Android SDK");

src/Sentry.Unity.Native/SentryNative.cs

Lines changed: 0 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
using Sentry.Unity.Integrations;
44
using System.Collections.Generic;
55
using UnityEngine;
6-
using UnityEngine.Analytics;
76

87
namespace Sentry.Unity.Native;
98

@@ -67,12 +66,6 @@ internal static void Configure(SentryUnityOptions options, RuntimePlatform platf
6766
options.NativeContextWriter = new NativeContextWriter();
6867
options.NativeDebugImageProvider = new NativeDebugImageProvider();
6968

70-
options.DefaultUserId = GetInstallationId();
71-
if (options.DefaultUserId is not null)
72-
{
73-
options.ScopeObserver.SetUser(new SentryUser { Id = options.DefaultUserId });
74-
}
75-
7669
// Note: we must actually call the function now and on every other call use the value we get here.
7770
// Additionally, we cannot call this multiple times for the same directory, because the result changes
7871
// on subsequent runs. Therefore, we cache the value during the whole runtime of the application.
@@ -123,28 +116,4 @@ private static void ReinstallBackend()
123116
Logger?.LogError(e, "Native dependency not found. Did you delete sentry.dll or move files around?");
124117
}
125118
}
126-
127-
private static string? GetInstallationId(IApplication? application = null)
128-
{
129-
application ??= ApplicationAdapter.Instance;
130-
switch (application.Platform)
131-
{
132-
case RuntimePlatform.Switch:
133-
case RuntimePlatform.PS5:
134-
case RuntimePlatform.XboxOne:
135-
case RuntimePlatform.GameCoreXboxSeries:
136-
case RuntimePlatform.GameCoreXboxOne:
137-
// TODO: Fetch the installation ID from sentry-native
138-
// See https://github.com/getsentry/sentry-native/issues/1324
139-
return null;
140-
141-
case RuntimePlatform.WindowsPlayer:
142-
case RuntimePlatform.WindowsEditor:
143-
case RuntimePlatform.LinuxPlayer:
144-
case RuntimePlatform.LinuxEditor:
145-
return AnalyticsSessionInfo.userId;
146-
default:
147-
return null;
148-
}
149-
}
150119
}

src/Sentry.Unity.iOS/SentryNativeCocoa.cs

Lines changed: 7 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
using Sentry.Extensibility;
22
using Sentry.Unity.Integrations;
33
using UnityEngine;
4-
using UnityEngine.Analytics;
54

65
namespace Sentry.Unity.iOS;
76

@@ -72,24 +71,14 @@ internal static void Configure(SentryUnityOptions options, RuntimePlatform platf
7271
options.NativeSupportCloseCallback += () => Close(options);
7372
if (options.UnityInfo.IL2CPP)
7473
{
75-
options.DefaultUserId = SentryCocoaBridgeProxy.GetInstallationId();
76-
if (string.IsNullOrEmpty(options.DefaultUserId))
74+
var installationId = SentryCocoaBridgeProxy.GetInstallationId();
75+
if (!string.IsNullOrEmpty(installationId))
7776
{
78-
// In case we can't get an installation ID we create one and sync that down to the native layer
79-
Logger?.LogDebug("Failed to fetch 'Installation ID' from the native SDK. Creating new 'Default User ID'.");
80-
81-
// We fall back to Unity's Analytics Session Info: https://docs.unity3d.com/ScriptReference/Analytics.AnalyticsSessionInfo-userId.html
82-
// It's a randomly generated GUID that gets created immediately after installation helping
83-
// to identify the same instance of the game
84-
options.DefaultUserId = AnalyticsSessionInfo.userId;
85-
if (options.DefaultUserId is not null)
86-
{
87-
options.ScopeObserver.SetUser(new SentryUser { Id = options.DefaultUserId });
88-
}
89-
else
90-
{
91-
Logger?.LogDebug("Failed to create new 'Default User ID'.");
92-
}
77+
options.DefaultUserId = installationId;
78+
}
79+
else
80+
{
81+
Logger?.LogDebug("Failed to fetch 'Installation ID' from the native SDK.");
9382
}
9483
}
9584

src/Sentry.Unity/Integrations/UnityScopeIntegration.cs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -159,12 +159,17 @@ private void PopulateUnity(Protocol.Unity unity)
159159

160160
private void PopulateUser(Scope scope)
161161
{
162+
if (scope.User.Id is not null)
163+
{
164+
return;
165+
}
166+
167+
// Only set the native installation ID here. The .NET SDK's Enricher handles
168+
// the fallback to InstallationId after the HasUser() check, which allows
169+
// IsEnvironmentUser/SendDefaultPii to set the Username first.
162170
if (_options.DefaultUserId is not null)
163171
{
164-
if (scope.User.Id is null)
165-
{
166-
scope.User.Id = _options.DefaultUserId;
167-
}
172+
scope.User.Id = _options.DefaultUserId;
168173
}
169174
}
170175
}

src/Sentry.Unity/WebGL/SentryWebGL.cs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
using Sentry.Extensibility;
22
using Sentry.Unity.Integrations;
3-
using UnityEngine.Analytics;
43

54
namespace Sentry.Unity.WebGL;
65

@@ -46,9 +45,6 @@ public static void Configure(SentryUnityOptions options)
4645
options.LogWarning("IL2CPP line number support is unsupported on WebGL - disabling.");
4746
}
4847

49-
// Use AnalyticsSessionInfo.userId as the default UserID
50-
options.DefaultUserId = AnalyticsSessionInfo.userId;
51-
5248
// Indicate that this platform doesn't support running background threads.
5349
options.MultiThreading = false;
5450
}

test/Sentry.Unity.Android.Tests/SentryNativeAndroidTests.cs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,14 +111,25 @@ public void Configure_NativeAndroidSupportDisabled_DoesNotReInitializeNativeBack
111111
}
112112

113113
[Test]
114-
public void Configure_NoInstallationIdReturned_SetsNewDefaultUserId()
114+
public void Configure_InstallationIdReturned_SetsDefaultUserId()
115+
{
116+
var options = new SentryUnityOptions();
117+
_testSentryJava.InstallationId = "test-installation-id";
118+
119+
SentryNativeAndroid.Configure(options);
120+
121+
Assert.AreEqual("test-installation-id", options.DefaultUserId);
122+
}
123+
124+
[Test]
125+
public void Configure_NoInstallationIdReturned_DoesNotSetDefaultUserId()
115126
{
116127
var options = new SentryUnityOptions();
117128
_testSentryJava.InstallationId = string.Empty;
118129

119130
SentryNativeAndroid.Configure(options);
120131

121-
Assert.False(string.IsNullOrEmpty(options.DefaultUserId));
132+
Assert.IsNull(options.DefaultUserId);
122133
}
123134

124135
[Test]

test/Sentry.Unity.Tests/ContextWriterTests.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,9 @@ public void Arguments()
7878
Debug = true,
7979
DiagnosticLogger = new TestLogger(),
8080
NativeContextWriter = context,
81+
CreateHttpMessageHandler = () => new TestHttpClientHandler(),
82+
AutoSessionTracking = false,
83+
CacheDirectoryPath = null,
8184
};
8285

8386
// act

test/Sentry.Unity.Tests/UnityEventScopeTests.cs

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -358,6 +358,65 @@ public void UserId_UnchangedIfNonEmpty()
358358
Assert.AreEqual(scope.User.Id, "bar");
359359
}
360360

361+
[Test]
362+
public void UserId_DefaultUserIdIsSet()
363+
{
364+
// arrange
365+
var options = new SentryUnityOptions(application: _testApplication) { DefaultUserId = "native-id" };
366+
367+
var sut = new UnityScopeUpdater(options, _testApplication);
368+
var scope = new Scope(options);
369+
370+
// act
371+
sut.ConfigureScope(scope);
372+
373+
// assert
374+
Assert.AreEqual("native-id", scope.User.Id);
375+
}
376+
377+
[Test]
378+
public void UserId_ScopeSync_TriggeredWhenUserIdSet()
379+
{
380+
// arrange - enable scope sync with a tracking observer
381+
var options = new SentryUnityOptions(application: _testApplication) { DefaultUserId = "sync-test-id" };
382+
var observer = new TestScopeObserver(options);
383+
options.ScopeObserver = observer;
384+
options.EnableScopeSync = true;
385+
386+
var sut = new UnityScopeUpdater(options, _testApplication);
387+
var scope = new Scope(options);
388+
389+
// act
390+
sut.ConfigureScope(scope);
391+
392+
// assert - the observer should have received the SetUser call via PropertyChanged
393+
Assert.IsNotNull(observer.LastUser, "ScopeObserver.SetUser should have been called");
394+
Assert.AreEqual("sync-test-id", observer.LastUser!.Id);
395+
}
396+
397+
[Test]
398+
public void UserId_ScopeSync_NotTriggeredWhenUserAlreadySet()
399+
{
400+
// arrange - User.Id already set, PopulateUser should early-return
401+
var options = new SentryUnityOptions(application: _testApplication) { DefaultUserId = "should-not-sync" };
402+
var observer = new TestScopeObserver(options);
403+
options.ScopeObserver = observer;
404+
options.EnableScopeSync = true;
405+
406+
var sut = new UnityScopeUpdater(options, _testApplication);
407+
var scope = new Scope(options);
408+
scope.User.Id = "already-set";
409+
410+
// Reset observer after the initial scope.User.Id set above triggered it
411+
observer.LastUser = null;
412+
413+
// act
414+
sut.ConfigureScope(scope);
415+
416+
// assert - PopulateUser should not have set a new user
417+
Assert.IsNull(observer.LastUser, "ScopeObserver.SetUser should not be called when User.Id is already set");
418+
}
419+
361420
[Test]
362421
public void OperatingSystemProtocol_Assigned()
363422
{
@@ -600,3 +659,21 @@ internal sealed class TestSentrySystemInfo : ISentrySystemInfo
600659
public Lazy<string>? RenderingThreadingMode { get; set; }
601660
public Lazy<DateTimeOffset>? StartTime { get; set; }
602661
}
662+
663+
internal sealed class TestScopeObserver : ScopeObserver
664+
{
665+
public SentryUser? LastUser { get; set; }
666+
667+
public TestScopeObserver(SentryOptions options) : base("Test", options) { }
668+
669+
public override void AddBreadcrumbImpl(Breadcrumb breadcrumb) { }
670+
public override void SetExtraImpl(string key, string? value) { }
671+
public override void SetTagImpl(string key, string value) { }
672+
public override void UnsetTagImpl(string key) { }
673+
public override void SetUserImpl(SentryUser user) => LastUser = user;
674+
public override void UnsetUserImpl() => LastUser = null;
675+
public override void SetTraceImpl(SentryId traceId, SpanId spanId) { }
676+
public override void AddFileAttachmentImpl(string filePath, string fileName, string? contentType) { }
677+
public override void AddByteAttachmentImpl(byte[] data, string fileName, string? contentType) { }
678+
public override void ClearAttachmentsImpl() { }
679+
}

0 commit comments

Comments
 (0)