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() {