diff --git a/platform/swift/source/CoreLogger.swift b/platform/swift/source/CoreLogger.swift index b79eba11..95c8cb61 100644 --- a/platform/swift/source/CoreLogger.swift +++ b/platform/swift/source/CoreLogger.swift @@ -87,9 +87,10 @@ extension CoreLogger: CoreLogging { ) } - func logSessionReplayScreenshot(screen: SessionReplayCapture, duration: TimeInterval) { + func logSessionReplayScreenshot(screen: SessionReplayCapture?, duration: TimeInterval) { + let fields = screen.flatMap { screen in self.convertFields(fields: ["screen_px": screen]) } ?? [] self.underlyingLogger.logSessionReplayScreenshot( - fields: self.convertFields(fields: ["screen": screen]), + fields: fields, duration: duration ) } diff --git a/platform/swift/source/CoreLogging.swift b/platform/swift/source/CoreLogging.swift index 03695d2d..700f7fc4 100644 --- a/platform/swift/source/CoreLogging.swift +++ b/platform/swift/source/CoreLogging.swift @@ -55,9 +55,9 @@ protocol CoreLogging: AnyObject { /// Writes a session replay screen log. /// - /// - parameter screen: The captured screenshot. + /// - parameter screen: The captured screenshot. `nil` if screenshot couldn't be taken. /// - parameter duration: The duration of time the preparation of the log took. - func logSessionReplayScreenshot(screen: SessionReplayCapture, duration: TimeInterval) + func logSessionReplayScreenshot(screen: SessionReplayCapture?, duration: TimeInterval) /// Writes a resource utilization log. /// diff --git a/platform/swift/source/replay/SessionReplayTarget.swift b/platform/swift/source/replay/SessionReplayTarget.swift index 0cc5d908..96997178 100644 --- a/platform/swift/source/replay/SessionReplayTarget.swift +++ b/platform/swift/source/replay/SessionReplayTarget.swift @@ -7,6 +7,7 @@ @_implementationOnly import CapturePassable import Foundation +import UIKit final class SessionReplayTarget { private let queue = DispatchQueue.serial(withLabelSuffix: "ReplayController", target: .default) @@ -41,14 +42,32 @@ extension SessionReplayTarget: CapturePassable.SessionReplayTarget { } func captureScreenshot() { - // TODO: Implement - // DispatchQueue.main.async { [weak self] in - // self?.queue.async { - // self?.logger?.logSessionReplayScreenshot( - // screen: SessionReplayCapture(data: Data()), - // duration: 0 - // ) - // } - // } + DispatchQueue.main.async { + guard let window = UIApplication.shared.sessionReplayWindows().first else { + self.logger?.logSessionReplayScreenshot( + screen: nil, + duration: 0 + ) + return + } + + let layer = window.layer + let bounds = UIScreen.main.bounds.size + + self.queue.async { [weak self] in + let start = Uptime() + let format = UIGraphicsImageRendererFormat() + format.scale = 1.0 + + let renderer = UIGraphicsImageRenderer(size: bounds, format: format) + let jpeg = renderer.jpegData(withCompressionQuality: 0.1) { context in + layer.render(in: context.cgContext) + } + self?.logger?.logSessionReplayScreenshot( + screen: SessionReplayCapture(data: jpeg), + duration: Uptime().timeIntervalSince(start) + ) + } + } } } diff --git a/test/platform/swift/unit_integration/core/bridge/SessionReplayTargetTests.swift b/test/platform/swift/unit_integration/core/bridge/SessionReplayTargetTests.swift index 75af888b..fcc8743c 100644 --- a/test/platform/swift/unit_integration/core/bridge/SessionReplayTargetTests.swift +++ b/test/platform/swift/unit_integration/core/bridge/SessionReplayTargetTests.swift @@ -30,7 +30,7 @@ final class SessionReplayTargetTests: XCTestCase { func testEmitsSessionReplayScreenLog() { let expectation = self.expectation(description: "screen log is emitted") - self.logger.logSessionReplayScreen = expectation + self.logger.logSessionReplayScreenExpectation = expectation self.target.captureScreen() XCTAssertEqual(.completed, XCTWaiter().wait(for: [expectation], timeout: 0.5)) diff --git a/test/platform/swift/unit_integration/mocks/MockCoreLogging.swift b/test/platform/swift/unit_integration/mocks/MockCoreLogging.swift index 34a95214..0b63d80f 100644 --- a/test/platform/swift/unit_integration/mocks/MockCoreLogging.swift +++ b/test/platform/swift/unit_integration/mocks/MockCoreLogging.swift @@ -44,7 +44,7 @@ public final class MockCoreLogging { public var logResourceUtilizationExpectation: XCTestExpectation? public private(set) var sessionReplayScreenLogs = [SessionReplayScreenLog]() - public var logSessionReplayScreen: XCTestExpectation? + public var logSessionReplayScreenExpectation: XCTestExpectation? public var shouldLogAppUpdateEvent = false @@ -115,10 +115,10 @@ extension MockCoreLogging: CoreLogging { self.sessionReplayScreenLogs.append(SessionReplayScreenLog( screen: screen, duration: duration) ) - self.logSessionReplayScreen?.fulfill() + self.logSessionReplayScreenExpectation?.fulfill() } - public func logSessionReplayScreenshot(screen _: SessionReplayCapture, duration _: TimeInterval) {} + public func logSessionReplayScreenshot(screen _: SessionReplayCapture?, duration _: TimeInterval) {} public func logResourceUtilization(fields: Fields, duration: TimeInterval) { self.resourceUtilizationLogs.append(ResourceUtilizationLog(fields: fields, duration: duration))