Skip to content
Merged
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
8 changes: 6 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,13 @@

## Unreleased

## Features
### Fixes

- The SDK now correctly resolves the storage path on Xbox during initialization, enabling offline caching and native crash capturing without user setup out of the box. ([#2617](https://github.com/getsentry/sentry-unity/pull/2617))

### Features

- The _Metrics_ APIs are now stable: removed `Experimental` from `SentrySdk` and `SentryOptions` ([#2615](https://github.com/getsentry/sentry-unity/pull/2615))
- The _Metrics_ APIs are now stable: removed `Experimental` from `SentrySdk` and `SentryOptions`. ([#2615](https://github.com/getsentry/sentry-unity/pull/2615))

### Dependencies

Expand Down
123 changes: 123 additions & 0 deletions package-dev/Runtime/Sentry.Unity.Native.Xbox.dll.meta
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This includes this assembly for Xbox builds.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 4 additions & 4 deletions package-dev/Runtime/Sentry.Unity.Native.dll.meta
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This excludes the assembly from being included in Xbox builds.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

19 changes: 19 additions & 0 deletions src/Sentry.Unity.Native/Sentry.Unity.Native.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,23 @@
/>
</Target>

<!-- Build Xbox version after the Switch build -->
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The pattern has already been established above.

<Target Name="BuildXboxAssembly" AfterTargets="BuildSwitchAssembly">
<Message Importance="High" Text="Building Xbox-specific native assembly." />

<Csc
Sources="@(Compile)"
References="@(ReferencePath)"
OutputAssembly="$(OutDir)Sentry.Unity.Native.Xbox.dll"
DefineConstants="$(DefineConstants);SENTRY_NATIVE_XBOX"
TargetType="library"
EmitDebugInformation="true"
DebugType="portable"
Nullable="$(Nullable)"
LangVersion="$(LangVersion)"
TreatWarningsAsErrors="$(TreatWarningsAsErrors)"
WarningLevel="$(WarningLevel)"
/>
</Target>

</Project>
10 changes: 9 additions & 1 deletion src/Sentry.Unity.Native/SentryNativeBridge.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@ public static bool Init(SentryUnityOptions options)
UseLibC = Application.platform
is RuntimePlatform.LinuxPlayer or RuntimePlatform.LinuxServer
or RuntimePlatform.PS5 or RuntimePlatform.Switch;
IsWindows = Application.platform is RuntimePlatform.WindowsPlayer or RuntimePlatform.WindowsServer;
IsWindows = Application.platform
is RuntimePlatform.WindowsPlayer or RuntimePlatform.WindowsServer
or RuntimePlatform.GameCoreXboxSeries or RuntimePlatform.GameCoreXboxOne;
Comment on lines +35 to +36
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is used to determine how the SDK handled and passes paths to sentry-native. For this purpose we can consider the Xbox IsWindows. But admittedly, the whole UseLibC vs IsWindows is technical debt.


var cOptions = sentry_options_new();

Expand Down Expand Up @@ -69,6 +71,10 @@ is RuntimePlatform.LinuxPlayer or RuntimePlatform.LinuxServer
sentry_options_set_attach_screenshot(cOptions, options.AttachScreenshot ? 1 : 0);
}

#if SENTRY_NATIVE_XBOX
SentryNativeXbox.ResolveStoragePath(options, Logger);
#endif

var databasePath = GetDatabasePath(options);
#if SENTRY_NATIVE_SWITCH
Logger?.LogDebug("Setting DatabasePath: {0}", databasePath);
Expand Down Expand Up @@ -119,6 +125,8 @@ internal static string GetDatabasePath(SentryUnityOptions options, IApplication?
return Path.Combine(options.CacheDirectoryPath, ".sentry-native");
}

// This is a fallback attempting to provide native crash support in case of CacheDirectoryPath not being set.
// Xbox and Switch rely on their own mechanisms to resolve storage, see SentryNativeXbox and SentryNativeSwitch.
application ??= ApplicationAdapter.Instance;
return Path.Combine(application.PersistentDataPath, ".sentry-native");
}
Expand Down
62 changes: 62 additions & 0 deletions src/Sentry.Unity.Native/SentryNativeXbox.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
#if SENTRY_NATIVE_XBOX
using System;
using System.Runtime.InteropServices;
using Sentry.Extensibility;

namespace Sentry.Unity.Native;

/// <summary>
/// Xbox-specific helpers for Sentry native support.
/// </summary>
/// <remarks>
/// On Xbox, <c>Application.persistentDataPath</c> returns an empty string for packaged (installed) builds.
/// The writable storage must be resolved via the Xbox Persistent Local Storage (PLS) API, which requires
/// <c>PersistentLocalStorage</c> to be configured in the game's <c>MicrosoftGame.config</c>.
/// </remarks>
internal static class SentryNativeXbox
{
[DllImport("sentry")]
private static extern IntPtr sentry_xbox_utils_get_pls_path();

/// <summary>
/// Resolves the Xbox Persistent Local Storage path and sets <see cref="SentryOptions.CacheDirectoryPath"/>.
/// </summary>
/// <remarks>
/// Called from <see cref="SentryNative.Configure"/> before native SDK initialization.
/// If PLS is not available (e.g. not configured in MicrosoftGame.config), the cache directory
/// is left unset. The SDK will operate without offline caching, session persistence, or native crash reporting.
/// </remarks>
internal static void ResolveStoragePath(SentryUnityOptions options, IDiagnosticLogger? logger)
{
if (!string.IsNullOrEmpty(options.CacheDirectoryPath))
{
logger?.LogWarning("The 'CacheDirectoryPath' has already been set by the user. " +
"Storage path resolution will be skipped.");
return;
}

string? plsPath = null;
try
{
var plsPathPtr = sentry_xbox_utils_get_pls_path();
plsPath = Marshal.PtrToStringAnsi(plsPathPtr);
}
catch (EntryPointNotFoundException)
{
logger?.LogWarning("Failed to find 'sentry_xbox_utils_get_pls_path' in sentry.dll.");
}

if (!string.IsNullOrEmpty(plsPath))
{
logger?.LogDebug("Setting Persistent Local Storage as cache directory path: '{0}'", plsPath);
options.CacheDirectoryPath = plsPath;
}
else
{
logger?.LogWarning("Failed to retrieve Xbox Persistent Local Storage path. " +
"Ensure 'PersistentLocalStorage' is configured in MicrosoftGame.config. " +
"Offline caching, session persistence, and native crash support will be disabled.");
}
}
}
#endif
1 change: 1 addition & 0 deletions src/Sentry.Unity/Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
[assembly: InternalsVisibleTo("Sentry.Unity.Native")]
[assembly: InternalsVisibleTo("Sentry.Unity.Native.PlayStation")]
[assembly: InternalsVisibleTo("Sentry.Unity.Native.Switch")]
[assembly: InternalsVisibleTo("Sentry.Unity.Native.Xbox")]
[assembly: InternalsVisibleTo("Sentry.Unity.Tests")]
[assembly: InternalsVisibleTo("Sentry.Unity.Editor")]
[assembly: InternalsVisibleTo("Sentry.Unity.Editor.Tests")]
Expand Down
9 changes: 6 additions & 3 deletions src/Sentry.Unity/SentryUnityOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -501,9 +501,12 @@ or RuntimePlatform.PS5
};

// Only assign the cache directory path if we're on a "known" platform.
// Special casing Switch here: Accessing `Application.persistentDataPath` implicitly creates a directory
// and leads to a crash.
if (IsKnownPlatform(application.Platform) && application.Platform is not RuntimePlatform.Switch)
// Special casing Switch: `Application.persistentDataPath` implicitly creates a directory and crashes.
// Special casing Xbox: `Application.persistentDataPath` returns an empty string on packaged builds.
if (IsKnownPlatform(application.Platform)
&& application.Platform is not RuntimePlatform.Switch
&& application.Platform is not RuntimePlatform.GameCoreXboxSeries
&& application.Platform is not RuntimePlatform.GameCoreXboxOne)
{
CacheDirectoryPath = application.PersistentDataPath;
}
Expand Down
4 changes: 4 additions & 0 deletions test/Scripts.Tests/package-release.zip.snapshot
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,10 @@ Runtime/Sentry.Unity.Native.Switch.dll
Runtime/Sentry.Unity.Native.Switch.dll.meta
Runtime/Sentry.Unity.Native.Switch.pdb
Runtime/Sentry.Unity.Native.Switch.pdb.meta
Runtime/Sentry.Unity.Native.Xbox.dll
Runtime/Sentry.Unity.Native.Xbox.dll.meta
Runtime/Sentry.Unity.Native.Xbox.pdb
Runtime/Sentry.Unity.Native.Xbox.pdb.meta
Runtime/Sentry.Unity.pdb
Runtime/Sentry.Unity.pdb.meta
Runtime/Sentry.xml
Expand Down
Loading