Skip to content

Commit 5012808

Browse files
authored
fix: Screenshot Capture (#2240)
1 parent a26b362 commit 5012808

16 files changed

Lines changed: 319 additions & 204 deletions

File tree

.github/workflows/ci.yml

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ jobs:
8787
strategy:
8888
fail-fast: false
8989
matrix:
90-
unity-version: ["2020", "2022", "6000"]
90+
unity-version: ["2020", "2022", "6000", "6100"]
9191
uses: ./.github/workflows/smoke-test-create.yml
9292
with:
9393
unity-version: ${{ matrix.unity-version }}
@@ -101,7 +101,7 @@ jobs:
101101
strategy:
102102
fail-fast: false
103103
matrix:
104-
unity-version: ["2020", "2022", "6000"]
104+
unity-version: ["2020", "2022", "6000", "6100"]
105105
platform: ["WebGL", "Linux"]
106106
include:
107107
- platform: WebGL
@@ -205,7 +205,7 @@ jobs:
205205
strategy:
206206
fail-fast: false
207207
matrix:
208-
unity-version: ["2020", "2022", "6000"]
208+
unity-version: ["2020", "2022", "6000", "6100"]
209209
uses: ./.github/workflows/smoke-test-build-android.yml
210210
with:
211211
unity-version: ${{ matrix.unity-version }}
@@ -224,7 +224,7 @@ jobs:
224224
matrix:
225225
api-level: [30, 31, 34] # last updated January 2025
226226
init-type: ["runtime", "buildtime"]
227-
unity-version: ["2020", "2022", "6000"]
227+
unity-version: ["2020", "2022", "6000", "6100"]
228228

229229
smoke-test-build-ios:
230230
name: Build iOS ${{ matrix.unity-version }} Smoke Test
@@ -234,7 +234,7 @@ jobs:
234234
strategy:
235235
fail-fast: false
236236
matrix:
237-
unity-version: ["2020", "2022", "6000"]
237+
unity-version: ["2020", "2022", "6000", "6100"]
238238
uses: ./.github/workflows/smoke-test-build-ios.yml
239239
with:
240240
unity-version: ${{ matrix.unity-version }}
@@ -247,7 +247,7 @@ jobs:
247247
strategy:
248248
fail-fast: false
249249
matrix:
250-
unity-version: ["2020", "2022", "6000"]
250+
unity-version: ["2020", "2022", "6000", "6100"]
251251
init-type: ["runtime", "buildtime"]
252252
uses: ./.github/workflows/smoke-test-compile-ios.yml
253253
with:
@@ -266,7 +266,7 @@ jobs:
266266
strategy:
267267
fail-fast: false
268268
matrix:
269-
unity-version: ["2020", "2022", "6000"]
269+
unity-version: ["2020", "2022", "6000", "6100"]
270270
# Check https://support.apple.com/en-us/HT201222 for the latest minor version for a given major one.
271271
# https://developer.apple.com/support/app-store/ shows that of all iOS devices
272272
# - `iOS 17`: 86 %
@@ -287,7 +287,7 @@ jobs:
287287
strategy:
288288
fail-fast: false
289289
matrix:
290-
unity-version: ["2020", "2022", "6000"]
290+
unity-version: ["2020", "2022", "6000", "6100"]
291291
platform: ["WebGL", "Linux"]
292292
steps:
293293
- name: Checkout
@@ -325,7 +325,7 @@ jobs:
325325
strategy:
326326
fail-fast: false
327327
matrix:
328-
unity-version: ["2020", "2022", "6000"]
328+
unity-version: ["2020", "2022", "6000", "6100"]
329329
# os: ["windows", "macos"]
330330
os: ["windows"]
331331
include:

CHANGELOG.md

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

33
## Unreleased
44

5+
### Fixes
6+
7+
- The SDK now waits for 'End of Frame' before capturing a screenshot. This should address any blank or malformed
8+
screenshots previously attached to events. The SDK now also only captures one screenshot for the first error event in
9+
each individual frame. ([#2240](https://github.com/getsentry/sentry-unity/pull/2240))
10+
511
### Dependencies
612

713
- Bump CLI from v2.47.1 to v2.50.2 ([#2245](https://github.com/getsentry/sentry-unity/pull/2245), [#2250](https://github.com/getsentry/sentry-unity/pull/2250))

samples/unity-of-bugs/Assets/Resources/Sentry/SentryOptions.asset

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,10 @@ MonoBehaviour:
2828
<ReleaseOverride>k__BackingField:
2929
<EnvironmentOverride>k__BackingField:
3030
<AttachStacktrace>k__BackingField: 1
31-
<AttachScreenshot>k__BackingField: 0
31+
<AttachScreenshot>k__BackingField: 1
3232
<ScreenshotQuality>k__BackingField: 1
3333
<ScreenshotCompression>k__BackingField: 75
34-
<AttachViewHierarchy>k__BackingField: 0
34+
<AttachViewHierarchy>k__BackingField: 1
3535
<MaxViewHierarchyRootObjects>k__BackingField: 100
3636
<MaxViewHierarchyObjectChildCount>k__BackingField: 20
3737
<MaxViewHierarchyDepth>k__BackingField: 10

scripts/ci-env.ps1

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@ switch ($name) {
1919
"unity6000" {
2020
return "6000.0.49f1"
2121
}
22+
"unity6100" {
23+
return "6000.1.12f1"
24+
}
2225
Default {
2326
throw "Unkown variable '$name'"
2427
}

scripts/smoke-test-android.ps1

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ Write-Host "#####################################################"
2424

2525
$BuildDir = $(GetNewProjectBuildPath)
2626
$ApkFileName = "test.apk"
27-
$ProcessName = "com.DefaultCompany.$(GetNewProjectName)"
27+
$ProcessName = "io.sentry.unity.integrationtest"
2828
$TestActivityName = "$ProcessName/com.unity3d.player.UnityPlayerActivity"
2929
$FallBackTestActivityName = "$ProcessName/com.unity3d.player.UnityPlayerGameActivity"
3030

Lines changed: 55 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,64 +1,85 @@
1+
using System;
2+
using System.Collections;
3+
using System.Threading;
14
using Sentry.Extensibility;
2-
using Sentry.Unity.Integrations;
5+
using Sentry.Internal;
36
using UnityEngine;
47

58
namespace Sentry.Unity;
69

7-
public class ScreenshotEventProcessor : ISentryEventProcessorWithHint
10+
public class ScreenshotEventProcessor : ISentryEventProcessor
811
{
912
private readonly SentryUnityOptions _options;
10-
private readonly IApplication _application;
11-
public ScreenshotEventProcessor(SentryUnityOptions sentryOptions) : this(sentryOptions, null) { }
13+
private readonly ISentryMonoBehaviour _sentryMonoBehaviour;
14+
private volatile int _isCapturingScreenshot;
1215

13-
internal ScreenshotEventProcessor(SentryUnityOptions sentryOptions, IApplication? application)
16+
public ScreenshotEventProcessor(SentryUnityOptions sentryOptions) : this(sentryOptions, SentryMonoBehaviour.Instance) { }
17+
18+
internal ScreenshotEventProcessor(SentryUnityOptions sentryOptions, ISentryMonoBehaviour sentryMonoBehaviour)
1419
{
1520
_options = sentryOptions;
16-
_application = application ?? ApplicationAdapter.Instance;
21+
_sentryMonoBehaviour = sentryMonoBehaviour;
1722
}
1823

19-
public SentryEvent? Process(SentryEvent @event)
24+
public SentryEvent Process(SentryEvent @event)
2025
{
26+
// Only ever capture one screenshot per frame
27+
if (Interlocked.CompareExchange(ref _isCapturingScreenshot, 1, 0) == 0)
28+
{
29+
_sentryMonoBehaviour.StartCoroutine(CaptureScreenshotCoroutine(@event.EventId));
30+
}
31+
2132
return @event;
2233
}
2334

24-
public SentryEvent? Process(SentryEvent @event, SentryHint hint)
35+
internal IEnumerator CaptureScreenshotCoroutine(SentryId eventId)
2536
{
26-
// save event id
27-
// wait for end of frame
28-
// check if last id is event it
29-
// send screenshot
30-
31-
// add workitem: screentshot for ID xxx
32-
// sdk integration checking for work: if ID got sent, follow up with screenshot
37+
_options.LogDebug("Screenshot capture triggered. Waiting for End of Frame.");
3338

34-
if (!MainThreadData.IsMainThread())
35-
{
36-
_options.DiagnosticLogger?.LogDebug("Screenshot capture skipped. Can't capture screenshots on other than the main thread.");
37-
return @event;
38-
}
39+
// WaitForEndOfFrame does not work in headless mode so we're making it configurable for CI.
40+
// See https://docs.unity3d.com/6000.1/Documentation/ScriptReference/WaitForEndOfFrame.html
41+
yield return WaitForEndOfFrame();
3942

40-
if (_options.BeforeCaptureScreenshotInternal?.Invoke() is not false)
43+
try
4144
{
42-
if (_application.IsEditor)
45+
if (_options.BeforeCaptureScreenshotInternal?.Invoke() is false)
4346
{
44-
_options.DiagnosticLogger?.LogInfo("Screenshot capture skipped. Capturing screenshots it not supported in the Editor");
45-
return @event;
47+
yield break;
4648
}
4749

48-
if (Screen.width == 0 || Screen.height == 0)
50+
var screenshotBytes = CaptureScreenshot(_options);
51+
if (screenshotBytes.Length == 0)
4952
{
50-
_options.DiagnosticLogger?.LogWarning("Can't capture screenshots on a screen with a resolution of '{0}x{1}'.", Screen.width, Screen.height);
51-
}
52-
else
53-
{
54-
hint.AddAttachment(SentryScreenshot.Capture(_options), "screenshot.jpg", contentType: "image/jpeg");
53+
_options.LogWarning("Screenshot capture returned empty data for event {0}", eventId);
54+
yield break;
5555
}
56+
57+
var attachment = new SentryAttachment(
58+
AttachmentType.Default,
59+
new ByteAttachmentContent(screenshotBytes),
60+
"screenshot.jpg",
61+
"image/jpeg");
62+
63+
_options.LogDebug("Screenshot captured for event {0}", eventId);
64+
65+
CaptureAttachment(eventId, attachment);
5666
}
57-
else
67+
catch (Exception e)
5868
{
59-
_options.DiagnosticLogger?.LogInfo("Screenshot capture skipped by BeforeAttachScreenshot callback.");
69+
_options.LogError(e, "Failed to capture screenshot.");
70+
}
71+
finally
72+
{
73+
Interlocked.Exchange(ref _isCapturingScreenshot, 0);
6074
}
61-
62-
return @event;
6375
}
76+
77+
internal virtual byte[] CaptureScreenshot(SentryUnityOptions options)
78+
=> SentryScreenshot.Capture(options);
79+
80+
internal virtual void CaptureAttachment(SentryId eventId, SentryAttachment attachment)
81+
=> (Sentry.SentrySdk.CurrentHub as Hub)?.CaptureAttachment(eventId, attachment);
82+
83+
internal virtual YieldInstruction WaitForEndOfFrame()
84+
=> new WaitForEndOfFrame();
6485
}

src/Sentry.Unity/SentryMonoBehaviour.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Collections;
23
using Sentry.Unity.Integrations;
34
using UnityEngine;
45

@@ -7,6 +8,7 @@ namespace Sentry.Unity;
78
internal interface ISentryMonoBehaviour
89
{
910
event Action? ApplicationResuming;
11+
public Coroutine StartCoroutine(IEnumerator routine);
1012
}
1113

1214
/// <summary>

src/Sentry.Unity/SentryUnitySdk.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ internal static void AddIntegrations(SentryUnityOptions options)
157157
{
158158
options.AddEventProcessor(new ViewHierarchyEventProcessor(options));
159159
}
160-
if (options.AttachScreenshot)
160+
if (!ApplicationAdapter.Instance.IsEditor && options.AttachScreenshot)
161161
{
162162
options.AddEventProcessor(new ScreenshotEventProcessor(options));
163163
}

test/Scripts.Integration.Test/Editor/Builder.cs

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ public static void BuildIl2CPPPlayer(BuildTarget target, BuildTargetGroup group,
2222
EditorUserBuildSettings.selectedBuildTargetGroup = group;
2323
EditorUserBuildSettings.allowDebugging = false;
2424
PlayerSettings.SetScriptingBackend(group, ScriptingImplementation.IL2CPP);
25+
// Making sure that the app keeps on running in the background. Linux CI is very unhappy with coroutines otherwise.
26+
PlayerSettings.runInBackground = true;
2527

2628
DisableUnityAudio();
2729
DisableProgressiveLightMapper();
@@ -41,14 +43,6 @@ public static void BuildIl2CPPPlayer(BuildTarget target, BuildTargetGroup group,
4143
PlayerSettings.SetManagedStrippingLevel(group, ManagedStrippingLevel.Low);
4244
#endif
4345

44-
45-
// This is a workaround for build issues with Unity 2022.3. and newer.
46-
// https://discussions.unity.com/t/gradle-build-issues-for-android-api-sdk-35-in-unity-2022-3lts/1502187/10
47-
#if UNITY_2022_3_OR_NEWER
48-
Debug.Log("Builder: Setting Android target API level to 33");
49-
PlayerSettings.Android.targetSdkVersion = AndroidSdkVersions.AndroidApiLevel33;
50-
#endif
51-
5246
Debug.Log("Builder: Updating BuildPlayerOptions");
5347
var buildPlayerOptions = new BuildPlayerOptions
5448
{
@@ -75,6 +69,9 @@ public static void BuildIl2CPPPlayer(BuildTarget target, BuildTargetGroup group,
7569

7670
if (target == BuildTarget.Android)
7771
{
72+
Debug.Log("Builder: Setting application identifier");
73+
PlayerSettings.SetApplicationIdentifier(BuildTargetGroup.Android, "io.sentry.unity.integrationtest");
74+
7875
// Android does not support appending builds. We make sure the directory is clean
7976
var outputDir = Path.GetDirectoryName(args["buildPath"]);
8077
if (Directory.Exists(outputDir))

0 commit comments

Comments
 (0)