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
20 changes: 12 additions & 8 deletions Sentry.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@
0A2D8D8728992260008720F6 /* SentryBaseIntegrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A2D8D8628992260008720F6 /* SentryBaseIntegrationTests.swift */; };
0A2D8D9628997845008720F6 /* NSLocale+Sentry.m in Sources */ = {isa = PBXBuildFile; fileRef = 0A2D8D9428997845008720F6 /* NSLocale+Sentry.m */; };
0A2D8D9828997887008720F6 /* NSLocale+Sentry.h in Headers */ = {isa = PBXBuildFile; fileRef = 0A2D8D9728997887008720F6 /* NSLocale+Sentry.h */; };
0A2D8DA8289BC905008720F6 /* SentryViewHierarchyProvider.h in Headers */ = {isa = PBXBuildFile; fileRef = 0A2D8DA6289BC905008720F6 /* SentryViewHierarchyProvider.h */; };
0A2D8DA9289BC905008720F6 /* SentryViewHierarchyProvider.m in Sources */ = {isa = PBXBuildFile; fileRef = 0A2D8DA7289BC905008720F6 /* SentryViewHierarchyProvider.m */; };
0A2D8DA8289BC905008720F6 /* SentryViewHierarchyProviderHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = 0A2D8DA6289BC905008720F6 /* SentryViewHierarchyProviderHelper.h */; };
0A2D8DA9289BC905008720F6 /* SentryViewHierarchyProviderHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 0A2D8DA7289BC905008720F6 /* SentryViewHierarchyProviderHelper.m */; };
0A5370A128A3EC2400B2DCDE /* SentryViewHierarchyProviderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A5370A028A3EC2400B2DCDE /* SentryViewHierarchyProviderTests.swift */; };
0A56DA5F28ABA01B00C400D5 /* SentryTransactionContext+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 0A56DA5E28ABA01B00C400D5 /* SentryTransactionContext+Private.h */; };
0A80E433291017C300095219 /* SentryWatchdogTerminationScopeObserver.m in Sources */ = {isa = PBXBuildFile; fileRef = 0A80E432291017C300095219 /* SentryWatchdogTerminationScopeObserver.m */; };
Expand Down Expand Up @@ -1123,6 +1123,7 @@
FAE80C242E4695B40010A595 /* SentryEvent+Serialize.h in Headers */ = {isa = PBXBuildFile; fileRef = FAE80C232E4695AE0010A595 /* SentryEvent+Serialize.h */; };
FAEC270E2DF3526000878871 /* SentryUserFeedback.swift in Sources */ = {isa = PBXBuildFile; fileRef = FAEC270D2DF3526000878871 /* SentryUserFeedback.swift */; };
FAEC273D2DF3933A00878871 /* NSData+Unzip.m in Sources */ = {isa = PBXBuildFile; fileRef = FAEC273C2DF3933200878871 /* NSData+Unzip.m */; };
FAEEBFE22E736D4B00E79CA9 /* SentryViewHierarchyProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = FAEEBFDC2E736D4100E79CA9 /* SentryViewHierarchyProvider.swift */; };
FAEFA12F2E4FAE1900C431D9 /* SentrySDKSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = FAEFA1292E4FAE1700C431D9 /* SentrySDKSettings.swift */; };
FAF120182E70C08F006E1DA3 /* SentryEnvelopeHeaderHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = FAF120122E70C088006E1DA3 /* SentryEnvelopeHeaderHelper.h */; };
FAF1201A2E70C0EE006E1DA3 /* SentryEnvelopeHeaderHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = FAF120192E70C0EA006E1DA3 /* SentryEnvelopeHeaderHelper.m */; };
Expand Down Expand Up @@ -1274,8 +1275,8 @@
0A2D8D8628992260008720F6 /* SentryBaseIntegrationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SentryBaseIntegrationTests.swift; sourceTree = "<group>"; };
0A2D8D9428997845008720F6 /* NSLocale+Sentry.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "NSLocale+Sentry.m"; sourceTree = "<group>"; };
0A2D8D9728997887008720F6 /* NSLocale+Sentry.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "NSLocale+Sentry.h"; path = "include/NSLocale+Sentry.h"; sourceTree = "<group>"; };
0A2D8DA6289BC905008720F6 /* SentryViewHierarchyProvider.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SentryViewHierarchyProvider.h; path = include/SentryViewHierarchyProvider.h; sourceTree = "<group>"; };
0A2D8DA7289BC905008720F6 /* SentryViewHierarchyProvider.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SentryViewHierarchyProvider.m; sourceTree = "<group>"; };
0A2D8DA6289BC905008720F6 /* SentryViewHierarchyProviderHelper.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SentryViewHierarchyProviderHelper.h; path = include/SentryViewHierarchyProviderHelper.h; sourceTree = "<group>"; };
0A2D8DA7289BC905008720F6 /* SentryViewHierarchyProviderHelper.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SentryViewHierarchyProviderHelper.m; sourceTree = "<group>"; };
0A5370A028A3EC2400B2DCDE /* SentryViewHierarchyProviderTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SentryViewHierarchyProviderTests.swift; sourceTree = "<group>"; };
0A56DA5E28ABA01B00C400D5 /* SentryTransactionContext+Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "SentryTransactionContext+Private.h"; path = "include/SentryTransactionContext+Private.h"; sourceTree = "<group>"; };
0A80E432291017C300095219 /* SentryWatchdogTerminationScopeObserver.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SentryWatchdogTerminationScopeObserver.m; sourceTree = "<group>"; };
Expand Down Expand Up @@ -2471,6 +2472,7 @@
FAEC270D2DF3526000878871 /* SentryUserFeedback.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SentryUserFeedback.swift; sourceTree = "<group>"; };
FAEC273C2DF3933200878871 /* NSData+Unzip.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "NSData+Unzip.m"; sourceTree = "<group>"; };
FAEC273E2DF393E000878871 /* NSData+Unzip.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "NSData+Unzip.h"; sourceTree = "<group>"; };
FAEEBFDC2E736D4100E79CA9 /* SentryViewHierarchyProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SentryViewHierarchyProvider.swift; sourceTree = "<group>"; };
FAEFA1292E4FAE1700C431D9 /* SentrySDKSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SentrySDKSettings.swift; sourceTree = "<group>"; };
FAF120122E70C088006E1DA3 /* SentryEnvelopeHeaderHelper.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SentryEnvelopeHeaderHelper.h; path = include/SentryEnvelopeHeaderHelper.h; sourceTree = "<group>"; };
FAF120192E70C0EA006E1DA3 /* SentryEnvelopeHeaderHelper.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SentryEnvelopeHeaderHelper.m; sourceTree = "<group>"; };
Expand Down Expand Up @@ -4138,8 +4140,8 @@
children = (
D8F6A24A2885515B00320515 /* SentryPredicateDescriptor.h */,
D8F6A2452885512100320515 /* SentryPredicateDescriptor.m */,
0A2D8DA6289BC905008720F6 /* SentryViewHierarchyProvider.h */,
0A2D8DA7289BC905008720F6 /* SentryViewHierarchyProvider.m */,
0A2D8DA6289BC905008720F6 /* SentryViewHierarchyProviderHelper.h */,
0A2D8DA7289BC905008720F6 /* SentryViewHierarchyProviderHelper.m */,
D83D07992B7F9D1C00CC9674 /* SentryMsgPackSerializer.h */,
D83D079A2B7F9D1C00CC9674 /* SentryMsgPackSerializer.m */,
D43A2A0F2DD47FB700114724 /* SentryWeakMap.h */,
Expand Down Expand Up @@ -4489,6 +4491,7 @@
D856272A2A374A6800FB8062 /* Tools */ = {
isa = PBXGroup;
children = (
FAEEBFDC2E736D4100E79CA9 /* SentryViewHierarchyProvider.swift */,
FA94E6B12E6D265500576666 /* SentryEnvelope.swift */,
FA94E68B2E6B92BE00576666 /* SentryClientReport.swift */,
FA3AEE772E68E2830092283E /* SentryEnvelopeHeader.swift */,
Expand Down Expand Up @@ -4946,7 +4949,7 @@
84354E1129BF944900CDBB8B /* SentryProfileTimeseries.h in Headers */,
D8ACE3CD2762187D00F5A213 /* SentryNSDataSwizzling.h in Headers */,
7B08A3452924CF6C0059603A /* SentryMetricKitIntegration.h in Headers */,
0A2D8DA8289BC905008720F6 /* SentryViewHierarchyProvider.h in Headers */,
0A2D8DA8289BC905008720F6 /* SentryViewHierarchyProviderHelper.h in Headers */,
8EAE980C261E9F530073B6B3 /* SentryUIViewControllerPerformanceTracker.h in Headers */,
63FE717D20DA4C1100CDBAE8 /* SentryCrashCachedData.h in Headers */,
03BCC38A27E1BF49003232C7 /* SentryTime.h in Headers */,
Expand Down Expand Up @@ -5707,6 +5710,7 @@
84E13B842CBF1D91003B52EC /* SentryUserFeedbackWidgetButtonMegaphoneIconView.swift in Sources */,
63FE715920DA4C1100CDBAE8 /* SentryCrashCPU_x86_32.c in Sources */,
92235CAE2E15549C00865983 /* SentryLogger.swift in Sources */,
FAEEBFE22E736D4B00E79CA9 /* SentryViewHierarchyProvider.swift in Sources */,
D8C66A372A77B1F70015696A /* SentryPropagationContext.m in Sources */,
7BE912AD272162D900E49E62 /* SentryNoOpSpan.m in Sources */,
63FE710D20DA4C1000CDBAE8 /* SentryCrashStackCursor_MachineContext.c in Sources */,
Expand Down Expand Up @@ -5897,7 +5901,7 @@
7BA61CBB247BC5D800C130A8 /* SentryCrashDefaultBinaryImageProvider.m in Sources */,
63FE713120DA4C1100CDBAE8 /* SentryCrashDynamicLinker.c in Sources */,
03F84D3527DD4191008FE43F /* SentryThreadHandle.cpp in Sources */,
0A2D8DA9289BC905008720F6 /* SentryViewHierarchyProvider.m in Sources */,
0A2D8DA9289BC905008720F6 /* SentryViewHierarchyProviderHelper.m in Sources */,
D84D2CDD2C2BF7370011AF8A /* SentryReplayEvent.swift in Sources */,
D8BC28CC2BFF78220054DA4D /* SentryRRWebTouchEvent.swift in Sources */,
D452FC592DDB4B1700AFF56F /* SentryWatchdogTerminationBreadcrumbProcessor.m in Sources */,
Expand Down
1 change: 0 additions & 1 deletion Sources/Sentry/PrivateSentrySDKOnly.m
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
#import "SentrySessionReplayIntegration+Private.h"
#import "SentrySwift.h"
#import "SentryUser+Private.h"
#import "SentryViewHierarchyProvider.h"
#import <SentryBreadcrumb.h>
#import <SentryDependencyContainer.h>
#import <SentryFramesTracker.h>
Expand Down
1 change: 0 additions & 1 deletion Sources/Sentry/SentryDependencyContainer.m
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@
#if SENTRY_HAS_UIKIT
# import "SentryANRTrackerV2.h"
# import "SentryFramesTracker.h"
# import <SentryViewHierarchyProvider.h>
# import <SentryWatchdogTerminationBreadcrumbProcessor.h>
#endif // SENTRY_HAS_UIKIT

Expand Down
2 changes: 1 addition & 1 deletion Sources/Sentry/SentryViewHierarchyIntegration.m
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
# import "SentryHub+Private.h"
# import "SentryOptions.h"
# import "SentrySDK+Private.h"
# import "SentryViewHierarchyProvider.h"
# import "SentrySwift.h"
# if SENTRY_HAS_METRIC_KIT
# import "SentryMetricKitIntegration.h"
# endif // SENTRY_HAS_METRIC_KIT
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#import "SentryViewHierarchyProvider.h"
#import "SentryViewHierarchyProviderHelper.h"

#if SENTRY_HAS_UIKIT

Expand All @@ -24,66 +24,37 @@
return SentryCrashJSON_OK;
}

@interface SentryViewHierarchyProvider ()
@implementation SentryViewHierarchyProviderHelper

@property (nonatomic, strong) SentryDispatchQueueWrapper *dispatchQueueWrapper;
@property (nonatomic, strong) id<SentryApplication> sentryUIApplication;

@end

@implementation SentryViewHierarchyProvider

- (instancetype)initWithDispatchQueueWrapper:(SentryDispatchQueueWrapper *)dispatchQueueWrapper
sentryUIApplication:(id<SentryApplication>)sentryUIApplication
+ (BOOL)saveViewHierarchy:(NSString *)filePath
windows:(NSArray<UIWindow *> *)windows
reportAccessibilityIdentifier:(BOOL)reportAccessibilityIdentifier
{
if (self = [super init]) {
self.reportAccessibilityIdentifier = YES;
self.dispatchQueueWrapper = dispatchQueueWrapper;
self.sentryUIApplication = sentryUIApplication;
}
return self;
}

- (BOOL)saveViewHierarchy:(NSString *)filePath
{
NSArray<UIWindow *> *windows = [self.sentryUIApplication getWindows];

const char *path = [filePath UTF8String];
int fd = open(path, O_RDWR | O_CREAT | O_TRUNC, 0644);
if (fd < 0) {
SENTRY_LOG_DEBUG(@"Could not open file %s for writing: %s", path, strerror(errno));
return NO;
}

BOOL result = [self processViewHierarchy:windows addFunction:writeJSONDataToFile userData:&fd];
BOOL result = [self processViewHierarchy:windows
reportAccessibilityIdentifier:reportAccessibilityIdentifier
addFunction:writeJSONDataToFile
userData:&fd];

close(fd);
return result;
}

- (NSData *)appViewHierarchyFromMainThread
{
__block NSData *result;

void (^fetchViewHierarchy)(void) = ^{ result = [self appViewHierarchy]; };

SENTRY_LOG_INFO(@"Starting to fetch the view hierarchy from the main thread.");

[self.dispatchQueueWrapper dispatchSyncOnMainQueue:fetchViewHierarchy];

SENTRY_LOG_INFO(@"Finished fetching the view hierarchy from the main thread.");

return result;
}

- (NSData *)appViewHierarchy
+ (NSData *)appViewHierarchyFrom:(NSArray<UIWindow *> *)windows
reportAccessibilityIdentifier:(BOOL)reportAccessibilityIdentifier
{
NSMutableData *result = [[NSMutableData alloc] init];
NSArray<UIWindow *> *windows = [self.sentryUIApplication getWindows];

if (![self processViewHierarchy:windows
addFunction:writeJSONDataToMemory
userData:(__bridge void *)(result)]) {
reportAccessibilityIdentifier:reportAccessibilityIdentifier
addFunction:writeJSONDataToMemory
userData:(__bridge void *)(result)]) {

result = nil;
}
Expand All @@ -95,9 +66,10 @@ - (NSData *)appViewHierarchy
if ((result = (code)) != SentryCrashJSON_OK) \
return result;

- (BOOL)processViewHierarchy:(NSArray<UIView *> *)windows
addFunction:(SentryCrashJSONAddDataFunc)addJSONDataFunc
userData:(void *const)userData
+ (BOOL)processViewHierarchy:(NSArray<UIView *> *)windows
reportAccessibilityIdentifier:(BOOL)reportAccessibilityIdentifier
addFunction:(SentryCrashJSONAddDataFunc)addJSONDataFunc
userData:(void *const)userData
{

__block SentryCrashJSONEncodeContext JSONContext;
Expand All @@ -113,7 +85,9 @@ - (BOOL)processViewHierarchy:(NSArray<UIView *> *)windows
tryJson(sentrycrashjson_beginArray(&JSONContext, "windows"));

for (UIView *window in windows) {
tryJson([self viewHierarchyFromView:window intoContext:&JSONContext]);
tryJson([self viewHierarchyFromView:window
intoContext:&JSONContext
reportAccessibilityIdentifier:reportAccessibilityIdentifier]);
}

tryJson(sentrycrashjson_endContainer(&JSONContext));
Expand All @@ -131,7 +105,9 @@ - (BOOL)processViewHierarchy:(NSArray<UIView *> *)windows
return YES;
}

- (int)viewHierarchyFromView:(UIView *)view intoContext:(SentryCrashJSONEncodeContext *)context
+ (int)viewHierarchyFromView:(UIView *)view
intoContext:(SentryCrashJSONEncodeContext *)context
reportAccessibilityIdentifier:(BOOL)reportAccessibilityIdentifier
{
SENTRY_LOG_DEBUG(@"Processing view hierarchy of view: %@", view);

Expand All @@ -141,7 +117,7 @@ - (int)viewHierarchyFromView:(UIView *)view intoContext:(SentryCrashJSONEncodeCo
tryJson(sentrycrashjson_addStringElement(
context, "type", viewClassName, SentryCrashJSON_SIZE_AUTOMATIC));

if (self.reportAccessibilityIdentifier && view.accessibilityIdentifier
if (reportAccessibilityIdentifier && view.accessibilityIdentifier
&& view.accessibilityIdentifier.length != 0) {
tryJson(sentrycrashjson_addStringElement(context, "identifier",
view.accessibilityIdentifier.UTF8String, SentryCrashJSON_SIZE_AUTOMATIC));
Expand All @@ -166,7 +142,9 @@ - (int)viewHierarchyFromView:(UIView *)view intoContext:(SentryCrashJSONEncodeCo

tryJson(sentrycrashjson_beginArray(context, "children"));
for (UIView *child in view.subviews) {
tryJson([self viewHierarchyFromView:child intoContext:context]);
tryJson([self viewHierarchyFromView:child
intoContext:context
reportAccessibilityIdentifier:reportAccessibilityIdentifier]);
}
tryJson(sentrycrashjson_endContainer(context));
tryJson(sentrycrashjson_endContainer(context));
Expand Down
1 change: 1 addition & 0 deletions Sources/Sentry/include/SentryPrivate.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#import "SentrySDK+Private.h"
#import "SentryTime.h"
#import "SentryUserAccess.h"
#import "SentryViewHierarchyProviderHelper.h"
#import "_SentryDispatchQueueWrapperInternal.h"

// Headers that also import SentryDefines should be at the end of this list
Expand Down
40 changes: 0 additions & 40 deletions Sources/Sentry/include/SentryViewHierarchyProvider.h

This file was deleted.

33 changes: 33 additions & 0 deletions Sources/Sentry/include/SentryViewHierarchyProviderHelper.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#import "SentryDefines.h"

#if SENTRY_HAS_UIKIT

@class UIWindow;

NS_ASSUME_NONNULL_BEGIN

@interface SentryViewHierarchyProviderHelper : NSObject

/**
* Get the view hierarchy in a json format.
*
* @param windows The app windows.
* @param reportAccessibilityIdentifier Whether or not to report accessibility identifiers.
*/
+ (nullable NSData *)appViewHierarchyFrom:(NSArray<UIWindow *> *)windows
reportAccessibilityIdentifier:(BOOL)reportAccessibilityIdentifier;

/**
* Save the current app view hierarchy in the given file path.
*
* @param filePath The full path where the view hierarchy should be saved.
* @param windows The app windows.
* @param reportAccessibilityIdentifier Whether or not to report accessibility identifiers.
*/
+ (BOOL)saveViewHierarchy:(NSString *)filePath
windows:(NSArray<UIWindow *> *)windows
reportAccessibilityIdentifier:(BOOL)reportAccessibilityIdentifier;
@end

NS_ASSUME_NONNULL_END
#endif
52 changes: 52 additions & 0 deletions Sources/Swift/Tools/SentryViewHierarchyProvider.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
#if (os(iOS) || os(tvOS) || (swift(>=5.9) && os(visionOS))) && !SENTRY_NO_UIKIT

@_implementationOnly import _SentryPrivate
import UIKit

@_spi(Private) @objc public class SentryViewHierarchyProvider: NSObject {
@objc public init(dispatchQueueWrapper: SentryDispatchQueueWrapper, sentryUIApplication: SentryApplication) {
self.reportAccessibilityIdentifier = true
self.dispatchQueueWrapper = dispatchQueueWrapper
self.sentryUIApplication = sentryUIApplication
}

private let dispatchQueueWrapper: SentryDispatchQueueWrapper
private let sentryUIApplication: SentryApplication

/**
* Whether we should add `accessibilityIdentifier` to the view hierarchy.
*/
@objc public var reportAccessibilityIdentifier: Bool

/**
Get the view hierarchy in a json format.
Always runs in the main thread.
*/
@objc public func appViewHierarchyFromMainThread() -> Data? {
var result: Data?

let fetchViewHierarchy = {
result = self.appViewHierarchy()
}

SentrySDKLog.info("Starting to fetch the view hierarchy from the main thread.")

dispatchQueueWrapper.dispatchSyncOnMainQueue(block: fetchViewHierarchy)

SentrySDKLog.info("Finished fetching the view hierarchy from the main thread.")

return result
}

@objc public func appViewHierarchy() -> Data? {
let windows = self.sentryUIApplication.getWindows() ?? []
return SentryViewHierarchyProviderHelper.appViewHierarchy(from: windows, reportAccessibilityIdentifier: reportAccessibilityIdentifier)
}

@discardableResult @objc(saveViewHierarchy:) public func saveViewHierarchy(_ filePath: String) -> Bool {
let windows = sentryUIApplication.getWindows() ?? []
return SentryViewHierarchyProviderHelper.saveViewHierarchy(filePath, windows: windows, reportAccessibilityIdentifier: reportAccessibilityIdentifier)
}
}

#endif
Loading
Loading