-
-
Notifications
You must be signed in to change notification settings - Fork 62
fix: Screenshot Capture #2240
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix: Screenshot Capture #2240
Changes from all commits
7c90568
98a7988
a3a70a4
f204618
8f74147
8f852e0
35a172d
11548fe
91aa77f
113e40e
271ef13
c4c5a96
7e183a1
41d69fc
521298d
8dfd665
e2e83a8
072d2d3
176de44
778e03d
34b03bd
f4ed1fa
38d2738
9015cd5
4e634d1
a9dfcb1
e05a579
26be76b
1cd0c2c
b8fdb41
2e24049
8043f3c
6c9b8c8
c0f38f0
73d3589
8d675e7
3a704c1
172e8ae
bb18109
e0856f6
65516a1
a2fe576
240d0ba
7910b8c
060c3c5
d3615e7
e132867
12e4315
6c7695a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,64 +1,85 @@ | ||
| using System; | ||
| using System.Collections; | ||
| using System.Threading; | ||
| using Sentry.Extensibility; | ||
| using Sentry.Unity.Integrations; | ||
| using Sentry.Internal; | ||
| using UnityEngine; | ||
|
|
||
| namespace Sentry.Unity; | ||
|
|
||
| public class ScreenshotEventProcessor : ISentryEventProcessorWithHint | ||
| public class ScreenshotEventProcessor : ISentryEventProcessor | ||
| { | ||
| private readonly SentryUnityOptions _options; | ||
| private readonly IApplication _application; | ||
| public ScreenshotEventProcessor(SentryUnityOptions sentryOptions) : this(sentryOptions, null) { } | ||
| private readonly ISentryMonoBehaviour _sentryMonoBehaviour; | ||
| private volatile int _isCapturingScreenshot; | ||
|
|
||
| internal ScreenshotEventProcessor(SentryUnityOptions sentryOptions, IApplication? application) | ||
| public ScreenshotEventProcessor(SentryUnityOptions sentryOptions) : this(sentryOptions, SentryMonoBehaviour.Instance) { } | ||
|
|
||
| internal ScreenshotEventProcessor(SentryUnityOptions sentryOptions, ISentryMonoBehaviour sentryMonoBehaviour) | ||
| { | ||
| _options = sentryOptions; | ||
| _application = application ?? ApplicationAdapter.Instance; | ||
| _sentryMonoBehaviour = sentryMonoBehaviour; | ||
| } | ||
|
|
||
| public SentryEvent? Process(SentryEvent @event) | ||
| public SentryEvent Process(SentryEvent @event) | ||
| { | ||
| // Only ever capture one screenshot per frame | ||
| if (Interlocked.CompareExchange(ref _isCapturingScreenshot, 1, 0) == 0) | ||
| { | ||
| _sentryMonoBehaviour.StartCoroutine(CaptureScreenshotCoroutine(@event.EventId)); | ||
|
bitsandfoxes marked this conversation as resolved.
|
||
| } | ||
|
|
||
| return @event; | ||
| } | ||
|
|
||
| public SentryEvent? Process(SentryEvent @event, SentryHint hint) | ||
| internal IEnumerator CaptureScreenshotCoroutine(SentryId eventId) | ||
| { | ||
| // save event id | ||
| // wait for end of frame | ||
| // check if last id is event it | ||
| // send screenshot | ||
|
|
||
| // add workitem: screentshot for ID xxx | ||
| // sdk integration checking for work: if ID got sent, follow up with screenshot | ||
| _options.LogDebug("Screenshot capture triggered. Waiting for End of Frame."); | ||
|
|
||
|
bitsandfoxes marked this conversation as resolved.
|
||
| if (!MainThreadData.IsMainThread()) | ||
| { | ||
| _options.DiagnosticLogger?.LogDebug("Screenshot capture skipped. Can't capture screenshots on other than the main thread."); | ||
| return @event; | ||
| } | ||
| // WaitForEndOfFrame does not work in headless mode so we're making it configurable for CI. | ||
| // See https://docs.unity3d.com/6000.1/Documentation/ScriptReference/WaitForEndOfFrame.html | ||
| yield return WaitForEndOfFrame(); | ||
|
|
||
| if (_options.BeforeCaptureScreenshotInternal?.Invoke() is not false) | ||
| try | ||
| { | ||
| if (_application.IsEditor) | ||
| if (_options.BeforeCaptureScreenshotInternal?.Invoke() is false) | ||
| { | ||
| _options.DiagnosticLogger?.LogInfo("Screenshot capture skipped. Capturing screenshots it not supported in the Editor"); | ||
| return @event; | ||
| yield break; | ||
| } | ||
|
|
||
| if (Screen.width == 0 || Screen.height == 0) | ||
| var screenshotBytes = CaptureScreenshot(_options); | ||
| if (screenshotBytes.Length == 0) | ||
| { | ||
| _options.DiagnosticLogger?.LogWarning("Can't capture screenshots on a screen with a resolution of '{0}x{1}'.", Screen.width, Screen.height); | ||
| } | ||
| else | ||
| { | ||
| hint.AddAttachment(SentryScreenshot.Capture(_options), "screenshot.jpg", contentType: "image/jpeg"); | ||
| _options.LogWarning("Screenshot capture returned empty data for event {0}", eventId); | ||
| yield break; | ||
| } | ||
|
|
||
| var attachment = new SentryAttachment( | ||
| AttachmentType.Default, | ||
| new ByteAttachmentContent(screenshotBytes), | ||
| "screenshot.jpg", | ||
| "image/jpeg"); | ||
|
|
||
| _options.LogDebug("Screenshot captured for event {0}", eventId); | ||
|
|
||
| CaptureAttachment(eventId, attachment); | ||
| } | ||
| else | ||
| catch (Exception e) | ||
| { | ||
| _options.DiagnosticLogger?.LogInfo("Screenshot capture skipped by BeforeAttachScreenshot callback."); | ||
| _options.LogError(e, "Failed to capture screenshot."); | ||
| } | ||
| finally | ||
| { | ||
| Interlocked.Exchange(ref _isCapturingScreenshot, 0); | ||
| } | ||
|
|
||
| return @event; | ||
| } | ||
|
|
||
| internal virtual byte[] CaptureScreenshot(SentryUnityOptions options) | ||
| => SentryScreenshot.Capture(options); | ||
|
|
||
| internal virtual void CaptureAttachment(SentryId eventId, SentryAttachment attachment) | ||
| => (Sentry.SentrySdk.CurrentHub as Hub)?.CaptureAttachment(eventId, attachment); | ||
|
|
||
| internal virtual YieldInstruction WaitForEndOfFrame() | ||
| => new WaitForEndOfFrame(); | ||
|
Comment on lines
+77
to
+84
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm making these virtual so I can create a |
||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -22,6 +22,8 @@ public static void BuildIl2CPPPlayer(BuildTarget target, BuildTargetGroup group, | |
| EditorUserBuildSettings.selectedBuildTargetGroup = group; | ||
| EditorUserBuildSettings.allowDebugging = false; | ||
| PlayerSettings.SetScriptingBackend(group, ScriptingImplementation.IL2CPP); | ||
| // Making sure that the app keeps on running in the background. Linux CI is very unhappy with coroutines otherwise. | ||
| PlayerSettings.runInBackground = true; | ||
|
|
||
| DisableUnityAudio(); | ||
| DisableProgressiveLightMapper(); | ||
|
|
@@ -41,14 +43,6 @@ public static void BuildIl2CPPPlayer(BuildTarget target, BuildTargetGroup group, | |
| PlayerSettings.SetManagedStrippingLevel(group, ManagedStrippingLevel.Low); | ||
| #endif | ||
|
|
||
|
|
||
| // This is a workaround for build issues with Unity 2022.3. and newer. | ||
| // https://discussions.unity.com/t/gradle-build-issues-for-android-api-sdk-35-in-unity-2022-3lts/1502187/10 | ||
| #if UNITY_2022_3_OR_NEWER | ||
| Debug.Log("Builder: Setting Android target API level to 33"); | ||
| PlayerSettings.Android.targetSdkVersion = AndroidSdkVersions.AndroidApiLevel33; | ||
| #endif | ||
|
|
||
|
Comment on lines
-44
to
-51
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Workaround that is no longer needed. |
||
| Debug.Log("Builder: Updating BuildPlayerOptions"); | ||
| var buildPlayerOptions = new BuildPlayerOptions | ||
| { | ||
|
|
@@ -75,6 +69,9 @@ public static void BuildIl2CPPPlayer(BuildTarget target, BuildTargetGroup group, | |
|
|
||
| if (target == BuildTarget.Android) | ||
| { | ||
| Debug.Log("Builder: Setting application identifier"); | ||
| PlayerSettings.SetApplicationIdentifier(BuildTargetGroup.Android, "io.sentry.unity.integrationtest"); | ||
|
|
||
| // Android does not support appending builds. We make sure the directory is clean | ||
| var outputDir = Path.GetDirectoryName(args["buildPath"]); | ||
| if (Directory.Exists(outputDir)) | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
With Unity 6 integration tests seem to fail to have their proper identifier set, causing the build to fail. We're setting this now explicitly in the
Builder.csand making use of the hardcoded name here.