diff --git a/.github/workflows/test-run-android.yml b/.github/workflows/test-run-android.yml
index 6400e761d..8d90dc546 100644
--- a/.github/workflows/test-run-android.yml
+++ b/.github/workflows/test-run-android.yml
@@ -32,6 +32,7 @@ jobs:
HOMEBREW_NO_INSTALL_CLEANUP: 1
SENTRY_DSN: ${{ secrets.SENTRY_TEST_DSN }}
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
+ SENTRY_TEST_UNITY_VERSION: ${{ inputs.unity-version }}
steps:
- name: Checkout
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 252fc315b..738ea3049 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,11 @@
# Changelog
+## Unreleased
+
+### Fixes
+
+- The SDK no longer throws a `NullReferenceException` during startup on Android and iOS when it can't load its options, for example when the configuration lives in an OBB file that isn't available yet. ([#2931](https://github.com/getsentry/sentry-unity/pull/2931))
+
## 4.12.0
### Behavioral Changes
diff --git a/src/Sentry.Unity.Android/SentryNativeAndroid.cs b/src/Sentry.Unity.Android/SentryNativeAndroid.cs
index 082be4ab3..b77d081ee 100644
--- a/src/Sentry.Unity.Android/SentryNativeAndroid.cs
+++ b/src/Sentry.Unity.Android/SentryNativeAndroid.cs
@@ -224,11 +224,21 @@ void Refresh()
///
/// Closes the native Android support.
///
- public static void Close(SentryUnityOptions options)
+ public static void Close(SentryUnityOptions? options) =>
+ Close(options, ApplicationAdapter.Instance.Platform);
+
+ // For testing
+ internal static void Close(SentryUnityOptions? options, RuntimePlatform platform)
{
Logger?.LogInfo("Attempting to close the Android SDK");
- if (!options.IsNativeSupportEnabled())
+ if (options is null)
+ {
+ Logger?.LogDebug("No options available. Skipping closing the Android SDK");
+ return;
+ }
+
+ if (!options.IsNativeSupportEnabled(platform))
{
Logger?.LogDebug("Android Native Support is not enabled. Skipping closing the Android SDK");
return;
diff --git a/src/Sentry.Unity.MacOS/SentryNativeMacos.cs b/src/Sentry.Unity.MacOS/SentryNativeMacos.cs
index 8e8d3071a..ac11148b7 100644
--- a/src/Sentry.Unity.MacOS/SentryNativeMacos.cs
+++ b/src/Sentry.Unity.MacOS/SentryNativeMacos.cs
@@ -26,7 +26,7 @@ public static void Configure(SentryUnityOptions options)
SentryNativeCocoa.Configure(options);
}
- public static void Close(SentryUnityOptions options)
+ public static void Close(SentryUnityOptions? options)
{
if (options is null)
{
diff --git a/src/Sentry.Unity.iOS/SentryNativeCocoa.cs b/src/Sentry.Unity.iOS/SentryNativeCocoa.cs
index ea913e04d..4e3bb8f9c 100644
--- a/src/Sentry.Unity.iOS/SentryNativeCocoa.cs
+++ b/src/Sentry.Unity.iOS/SentryNativeCocoa.cs
@@ -132,11 +132,21 @@ internal static void Configure(SentryUnityOptions options, RuntimePlatform platf
///
/// Closes the native Cocoa support.
///
- public static void Close(SentryUnityOptions options)
+ public static void Close(SentryUnityOptions? options) =>
+ Close(options, ApplicationAdapter.Instance.Platform);
+
+ // For testing
+ internal static void Close(SentryUnityOptions? options, RuntimePlatform platform)
{
Logger?.LogInfo("Attempting to close the Cocoa SDK");
- if (!options.IsNativeSupportEnabled())
+ if (options is null)
+ {
+ Logger?.LogDebug("No options available. Skipping closing the Cocoa SDK");
+ return;
+ }
+
+ if (!options.IsNativeSupportEnabled(platform))
{
Logger?.LogDebug("Cocoa Native Support is not enable. Skipping closing the Cocoa SDK");
return;
diff --git a/test/IntegrationTest/Integration.Tests.ps1 b/test/IntegrationTest/Integration.Tests.ps1
index 6e9f39c20..9f39a191d 100644
--- a/test/IntegrationTest/Integration.Tests.ps1
+++ b/test/IntegrationTest/Integration.Tests.ps1
@@ -447,6 +447,10 @@ Describe "Unity $($env:SENTRY_TEST_PLATFORM) Integration Tests" {
Set-ItResult -Skipped -Because "line numbers come from the IL2CPP mappings, which a Mono player does not produce"
return
}
+ if ($script:Platform -eq "Android" -and $script:TestSetup.UnityVersion -like "2021.3*") {
+ Set-ItResult -Skipped -Because "on the Android 2021.3 x86_64 emulator, IL2CPP intermittently reports no stack frames for the thrown exception, so the event carries only the throwing frame without a native address"
+ return
+ }
$frame = $runEvent.exception.values[0].stacktrace.frames |
Where-Object { $_.module -eq "IntegrationTester" -and $_.function -eq "ThrowException" } |
diff --git a/test/Sentry.Unity.Android.Tests/SentryNativeAndroidTests.cs b/test/Sentry.Unity.Android.Tests/SentryNativeAndroidTests.cs
index 73ca5e915..0634514d7 100644
--- a/test/Sentry.Unity.Android.Tests/SentryNativeAndroidTests.cs
+++ b/test/Sentry.Unity.Android.Tests/SentryNativeAndroidTests.cs
@@ -4,6 +4,7 @@
using NUnit.Framework;
using Sentry.Unity.Tests.SharedClasses;
using Sentry.Unity.Tests.Stubs;
+using UnityEngine;
namespace Sentry.Unity.Android.Tests;
@@ -36,6 +37,15 @@ public void TearDown() =>
Interlocked.Exchange(ref SentryNative.ReinstallSentryNativeBackendStrategy!,
_originalReinstallSentryNativeBackendStrategy)!;
+ [Test]
+ public void Close_OptionsNull_DoesNotCloseSentryJava()
+ {
+ _testSentryJava.SentryPresent = true;
+
+ Assert.DoesNotThrow(() => SentryNativeAndroid.Close(null, RuntimePlatform.Android));
+ Assert.False(_testSentryJava.CloseCalled);
+ }
+
[Test]
public void Configure_DefaultConfiguration_SetsScopeObserver()
{
diff --git a/test/Sentry.Unity.iOS.Tests/SentryNativeIosTests.cs b/test/Sentry.Unity.iOS.Tests/SentryNativeIosTests.cs
index eac8b89de..0e15269bd 100644
--- a/test/Sentry.Unity.iOS.Tests/SentryNativeIosTests.cs
+++ b/test/Sentry.Unity.iOS.Tests/SentryNativeIosTests.cs
@@ -7,6 +7,12 @@ namespace Sentry.Unity.iOS.Tests;
public class SentryNativeCocoaTests
{
+ [Test]
+ public void Close_OptionsNull_DoesNotThrow()
+ {
+ Assert.DoesNotThrow(() => SentryNativeCocoa.Close(null, RuntimePlatform.IPhonePlayer));
+ }
+
[Test]
public void Configure_DefaultConfiguration_iOS()
{