Skip to content
Open
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 @@ -5,6 +5,7 @@
### Fixes

- Fixed a `NoSuchFieldError` during initialization on Android when setting the `sample rate`. ([#2838](https://github.com/getsentry/sentry-unity/issues/2838))
- Fixed a potential startup crash when targeting Android. The SDK would still set up native support even without a DSN provided. This would cause `sentry-java` to auto-initialize during startup via the `SentryInitProvider`. The SDK now verifies the presence of a DSN at build time, skipping native support when it's missing and logs accordingly. ([#2846](https://github.com/getsentry/sentry-unity/issues/2846))

## 4.10.0

Expand Down
66 changes: 46 additions & 20 deletions src/Sentry.Unity.Editor/Android/AndroidManifestConfiguration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ public class AndroidManifestConfiguration
private readonly bool _isDevelopmentBuild;
private readonly ScriptingImplementation _scriptingImplementation;

private bool? _androidSdkEnabled;

public AndroidManifestConfiguration()
: this(
SentryScriptableObject.LoadOptions,
Expand Down Expand Up @@ -111,43 +113,60 @@ public void OnPostGenerateGradleAndroidProject(string basePath)
SetupProguard(gradleProjectPath);
}

internal void ModifyManifest(string basePath)
{
var manifestPath = GetManifestPath(basePath);
if (!File.Exists(manifestPath))
{
throw new FileNotFoundException("Can't configure native Android SDK nor set auto-init:false.",
manifestPath);
}
/// <summary>
/// Whether this build ships the Android SDK. Shared with <see cref="ModifyManifest"/> because an app that
/// carries `sentry-android-core` without the matching manifest entries auto-initializes without a DSN,
/// which crashes it on startup.
/// </summary>
private bool AndroidSdkEnabled => _androidSdkEnabled ??= EvaluateAndroidSdkEnabled();

var enableNativeSupport = true;
private bool EvaluateAndroidSdkEnabled()
{
if (_options is null)
{
_logger.LogWarning("Android native support disabled because Sentry has not been configured. " +
"You can do that through the editor: {0}", SentryWindow.EditorMenuPath);
enableNativeSupport = false;
return false;
}
else if (!_options.IsValid())

if (!_options.IsValid())
{
_logger.LogDebug("Android native support disabled.");
enableNativeSupport = false;
return false;
}
else if (!_options.AndroidNativeSupportEnabled)

if (!_options.AndroidNativeSupportEnabled)
{
_logger.LogDebug("Android native support disabled through the options.");
enableNativeSupport = false;
return false;
}

return true;
}

internal void ModifyManifest(string basePath)
{
var manifestPath = GetManifestPath(basePath);
if (!File.Exists(manifestPath))
{
throw new FileNotFoundException("Can't configure native Android SDK nor set auto-init:false.",
manifestPath);
}

var androidManifest = new AndroidManifest(manifestPath, _logger);
androidManifest.RemovePreviousConfigurations();
androidManifest.AddDisclaimerComment();

if (!enableNativeSupport)
if (!AndroidSdkEnabled)
{
// Should the SDK end up in the app regardless, this keeps it from crashing on startup.
_logger.LogDebug("Setting 'auto-init' to 'false'. The Android SDK is not part of this build.");
androidManifest.SetAutoInit(false);
_ = androidManifest.Save();

return;
}

androidManifest.AddDisclaimerComment();

if (_options?.AndroidNativeInitializationType is NativeInitializationType.Runtime)
{
_logger.LogDebug("Setting 'auto-init' to 'false'. The Android SDK will be initialized at runtime.");
Expand Down Expand Up @@ -239,7 +258,7 @@ internal void CopyAndroidSdkToGradleProject(string unityProjectPath, string grad
var androidSdkPath = Path.Combine(unityProjectPath, "Packages", SentryPackageInfo.GetName(), "Plugins", "Android", "Sentry~");
var targetPath = Path.Combine(gradlePath, "unityLibrary", "libs");

if (_options is { Enabled: true, AndroidNativeSupportEnabled: true })
if (AndroidSdkEnabled)
{
if (!Directory.Exists(androidSdkPath))
{
Expand All @@ -260,6 +279,13 @@ internal void CopyAndroidSdkToGradleProject(string unityProjectPath, string grad
}
else
{
if (!Directory.Exists(androidSdkPath))
{
// A build that does not ship the SDK has no reason to fail over a missing SDK.
_logger.LogDebug("Failed to find the Android SDK at '{0}'. Nothing to remove.", androidSdkPath);
return;
}

_logger.LogInfo("Removing the Android SDK from the output project.");
foreach (var file in Directory.GetFiles(androidSdkPath))
{
Expand All @@ -275,7 +301,7 @@ internal void CopyAndroidSdkToGradleProject(string unityProjectPath, string grad
internal void AddAndroidSdkDependencies(string gradleProjectPath)
{
var tool = new GradleSetup(_logger, gradleProjectPath);
var nativeSupportEnabled = _options is { Enabled: true, AndroidNativeSupportEnabled: true };
var nativeSupportEnabled = AndroidSdkEnabled;

try
{
Comment thread
sentry[bot] marked this conversation as resolved.
Expand Down Expand Up @@ -358,7 +384,7 @@ internal void SetupSymbolsUpload(string unityProjectPath, string gradleProjectPa
private void SetupProguard(string gradleProjectPath)
{
var tool = new ProguardSetup(_logger, gradleProjectPath);
var nativeSupportEnabled = _options is { Enabled: true, AndroidNativeSupportEnabled: true };
var nativeSupportEnabled = AndroidSdkEnabled;

try
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,38 @@ public void ModifyManifest_UnityOptions_EnabledWithoutDsn_LogWarningAndDoesNotAd
Assert.False(manifest.Contains("io.sentry.dsn"));
}

[Test]
[TestCase(null)]
[TestCase("")]
public void ModifyManifest_AndroidSdkDisabled_SetsAutoInitToFalse(string? dsn)
{
_fixture.SentryUnityOptions!.Dsn = dsn;
var sut = _fixture.GetSut();
var manifest = WithAndroidManifest(basePath => sut.ModifyManifest(basePath));

StringAssert.Contains("<meta-data android:name=\"io.sentry.auto-init\" android:value=\"False\" />", manifest);
}

[Test]
public void CopyAndroidSdkToGradleProject_EnabledWithoutDsn_RemovesAndroidSdkFromGradleProject()
{
var fakeProjectPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
var unityProjectPath = Path.Combine(fakeProjectPath, "UnityProject");
var gradleProjectPath = Path.Combine(fakeProjectPath, "GradleProject");
DebugSymbolUploadTests.SetupFakeProject(fakeProjectPath);
var androidSdk = Path.Combine(gradleProjectPath, "unityLibrary", "libs", "androidSdk.jar");
File.Create(androidSdk).Close();

_fixture.SentryUnityOptions!.Dsn = string.Empty;
var sut = _fixture.GetSut();

sut.CopyAndroidSdkToGradleProject(unityProjectPath, gradleProjectPath);

Assert.IsFalse(File.Exists(androidSdk));

Directory.Delete(fakeProjectPath, true);
}

[Test]
public void ModifyManifest_UnityOptions_AndroidNativeSupportEnabledFalse_LogDebugAndDoesNotAddSentry()
{
Expand Down Expand Up @@ -514,6 +546,25 @@ public void CopyAndroidSdkToGradleProject_AndroidNativeSupportDisabledButSdkAlre
Directory.Delete(fakeProjectPath, true);
}

[Test]
public void CopyAndroidSdkToGradleProject_AndroidSdkDisabledAndSourceMissing_DoesNotThrow()
{
var fakeProjectPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
var unityProjectPath = Path.Combine(fakeProjectPath, "UnityProject");
var gradleProjectPath = Path.Combine(fakeProjectPath, "GradleProject");
DebugSymbolUploadTests.SetupFakeProject(fakeProjectPath);
Directory.Delete(
Path.Combine(unityProjectPath, "Packages", SentryPackageInfo.GetName(), "Plugins", "Android", "Sentry~"),
true);

_fixture.SentryUnityOptions!.AndroidNativeSupportEnabled = false;
var sut = _fixture.GetSut();

Assert.DoesNotThrow(() => sut.CopyAndroidSdkToGradleProject(unityProjectPath, gradleProjectPath));

Directory.Delete(fakeProjectPath, true);
}

[Test]
public void CopyAndroidSdkToGradleProject_SdkAlreadyExists_OverwritesExistingSdk()
{
Expand Down
Loading