diff --git a/Samples/iOS-Swift/iOS-Swift/Tools/SentryExposure.h b/Samples/iOS-Swift/iOS-Swift/Tools/SentryExposure.h index 66643ef8816..13c5ce9893a 100644 --- a/Samples/iOS-Swift/iOS-Swift/Tools/SentryExposure.h +++ b/Samples/iOS-Swift/iOS-Swift/Tools/SentryExposure.h @@ -6,13 +6,6 @@ NS_ASSUME_NONNULL_BEGIN -@interface SentryBreadcrumbTracker : NSObject - -+ (nullable NSDictionary *)extractDataFromView:(UIView *)view - withAccessibilityIdentifier:(BOOL)includeIdentifier; - -@end - @interface SentryClientInternal : NSObject @property (nonatomic) SentryOptions *options; diff --git a/Samples/iOS-Swift/iOS-Swift/ViewControllers/InfoForBreadcrumbController.swift b/Samples/iOS-Swift/iOS-Swift/ViewControllers/InfoForBreadcrumbController.swift index 849a1c0aee9..42c65b382c2 100644 --- a/Samples/iOS-Swift/iOS-Swift/ViewControllers/InfoForBreadcrumbController.swift +++ b/Samples/iOS-Swift/iOS-Swift/ViewControllers/InfoForBreadcrumbController.swift @@ -1,5 +1,5 @@ import Foundation -import Sentry +@_spi(Private) import Sentry import UIKit class InfoForBreadcrumbController: UIViewController { @@ -13,13 +13,12 @@ class InfoForBreadcrumbController: UIViewController { } @IBAction func buttonPressed(_ sender: Any) { - guard let view = self.view, - let viewInfo = SentryBreadcrumbTracker.extractData(from: view, withAccessibilityIdentifier: true), - let buttonInfo = SentryBreadcrumbTracker.extractData(from: button, withAccessibilityIdentifier: true) - else { + guard let view = self.view else { label?.text = "ERROR" return } + let viewInfo = SentryBreadcrumbTracker.extractData(from: view, includeAccessibilityIdentifier: true) + let buttonInfo = SentryBreadcrumbTracker.extractData(from: button, includeAccessibilityIdentifier: true) let hasCorrectData = String(describing: view) == viewInfo["view"] as? String && viewInfo["tag"] == nil && diff --git a/Sentry.xcodeproj/project.pbxproj b/Sentry.xcodeproj/project.pbxproj index cfea7773ca1..23a20254204 100644 --- a/Sentry.xcodeproj/project.pbxproj +++ b/Sentry.xcodeproj/project.pbxproj @@ -110,7 +110,6 @@ 62CFD9AD2C99770B00834E1B /* SentryInvalidJSONString.m in Sources */ = {isa = PBXBuildFile; fileRef = 62CFD9AC2C99770B00834E1B /* SentryInvalidJSONString.m */; }; 62CFD9AE2C99770B00834E1B /* SentryInvalidJSONString.m in Sources */ = {isa = PBXBuildFile; fileRef = 62CFD9AC2C99770B00834E1B /* SentryInvalidJSONString.m */; }; 62D6B2A72CCA354B004DDBF1 /* SentryUncaughtNSExceptionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62D6B2A62CCA354B004DDBF1 /* SentryUncaughtNSExceptionsTests.swift */; }; - 62E081A929ED4260000F69FC /* SentryBreadcrumbDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 62E081A829ED4260000F69FC /* SentryBreadcrumbDelegate.h */; }; 62E081AB29ED4322000F69FC /* SentryBreadcrumbTestDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62E081AA29ED4322000F69FC /* SentryBreadcrumbTestDelegate.swift */; }; 62E2119A2DAE99FC007D7262 /* SentryAsyncSafeLog.m in Sources */ = {isa = PBXBuildFile; fileRef = 62E211992DAE99FC007D7262 /* SentryAsyncSafeLog.m */; }; 62E5325B2DEEC862000B2DD5 /* TestCurrentDateProviderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 624729172DE5980500DFEE00 /* TestCurrentDateProviderTests.swift */; }; @@ -152,8 +151,6 @@ 6383953623ABA42C000C1594 /* SentryHttpTransport.h in Headers */ = {isa = PBXBuildFile; fileRef = 6383953523ABA42C000C1594 /* SentryHttpTransport.h */; }; 638DC9A01EBC6B6400A66E41 /* SentryRequestOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = 638DC99E1EBC6B6400A66E41 /* SentryRequestOperation.h */; settings = {ATTRIBUTES = (Private, ); }; }; 638DC9A11EBC6B6400A66E41 /* SentryRequestOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 638DC99F1EBC6B6400A66E41 /* SentryRequestOperation.m */; }; - 639889B71EDECFA800EA7442 /* SentryBreadcrumbTracker.h in Headers */ = {isa = PBXBuildFile; fileRef = 639889B51EDECFA800EA7442 /* SentryBreadcrumbTracker.h */; }; - 639889B81EDECFA800EA7442 /* SentryBreadcrumbTracker.m in Sources */ = {isa = PBXBuildFile; fileRef = 639889B61EDECFA800EA7442 /* SentryBreadcrumbTracker.m */; }; 639889BB1EDED18400EA7442 /* SentrySwizzle.h in Headers */ = {isa = PBXBuildFile; fileRef = 639889B91EDED18400EA7442 /* SentrySwizzle.h */; settings = {ATTRIBUTES = (Private, ); }; }; 639889BD1EDED18400EA7442 /* SentrySwizzle.m in Sources */ = {isa = PBXBuildFile; fileRef = 639889BA1EDED18400EA7442 /* SentrySwizzle.m */; }; 639FCF981EBC7B9700778193 /* SentryEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = 639FCF961EBC7B9700778193 /* SentryEvent.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -462,7 +459,7 @@ 7BDB03BB2513652900BAE198 /* _SentryDispatchQueueWrapperInternal.m in Sources */ = {isa = PBXBuildFile; fileRef = 7BDB03BA2513652900BAE198 /* _SentryDispatchQueueWrapperInternal.m */; }; 7BDDE3CC2966BD4700EB9177 /* SentryMXManagerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BDDE3CB2966BD4700EB9177 /* SentryMXManagerTests.swift */; }; 7BE0DC29272A9E1C004FA8B7 /* SentryBreadcrumbTrackerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BE0DC28272A9E1C004FA8B7 /* SentryBreadcrumbTrackerTests.swift */; }; - 7BE0DC2F272ABAF6004FA8B7 /* SentryAutoBreadcrumbTrackingIntegrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BE0DC2E272ABAF6004FA8B7 /* SentryAutoBreadcrumbTrackingIntegrationTests.swift */; }; + 7BE0DC2F272ABAF6004FA8B7 /* SentryBreadcrumbTrackingIntegrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BE0DC2E272ABAF6004FA8B7 /* SentryBreadcrumbTrackingIntegrationTests.swift */; }; 7BE2C7F8257000A4003B66C7 /* SentryTestIntegration.m in Sources */ = {isa = PBXBuildFile; fileRef = 7BE2C7F72570009F003B66C7 /* SentryTestIntegration.m */; }; 7BE3C7752445C82300A38442 /* SentryCurrentDateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BE3C7742445C82300A38442 /* SentryCurrentDateTests.swift */; }; 7BE3C78724472E9800A38442 /* TestRequestManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BE3C78624472E9800A38442 /* TestRequestManager.swift */; }; @@ -502,8 +499,6 @@ 7D65260E237F649E00113EA2 /* SentryScope.m in Sources */ = {isa = PBXBuildFile; fileRef = 7D65260B237F649E00113EA2 /* SentryScope.m */; }; 7D9B07A023D1E89900C5FC8E /* SentryMeta.h in Headers */ = {isa = PBXBuildFile; fileRef = 7D9B079F23D1E89800C5FC8E /* SentryMeta.h */; }; 7DB3A687238EA75E00A2D442 /* SentryHttpTransport.m in Sources */ = {isa = PBXBuildFile; fileRef = 7DB3A684238EA75E00A2D442 /* SentryHttpTransport.m */; }; - 7DC27EC523997EB7006998B5 /* SentryAutoBreadcrumbTrackingIntegration.h in Headers */ = {isa = PBXBuildFile; fileRef = 7DC27EC323997EB7006998B5 /* SentryAutoBreadcrumbTrackingIntegration.h */; }; - 7DC27EC723997EB7006998B5 /* SentryAutoBreadcrumbTrackingIntegration.m in Sources */ = {isa = PBXBuildFile; fileRef = 7DC27EC423997EB7006998B5 /* SentryAutoBreadcrumbTrackingIntegration.m */; }; 81BC357F116F0147283DA824 /* PropertyExtractorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E69CEDDF745ECE10243A13FA /* PropertyExtractorTests.swift */; }; 840A11122B61E27500650D02 /* SentrySamplerDecision.m in Sources */ = {isa = PBXBuildFile; fileRef = 840A11102B61E27500650D02 /* SentrySamplerDecision.m */; }; 841325BC2BF4184B0029228F /* TestHub.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B944FAD2469B43700A10721 /* TestHub.swift */; }; @@ -654,8 +649,6 @@ 92ECD7202E05A7DF0063EC10 /* SentryLogC.h in Headers */ = {isa = PBXBuildFile; fileRef = D8AE48B12C5786AA0092A2A6 /* SentryLogC.h */; settings = {ATTRIBUTES = (Private, ); }; }; 92F6726B29C8B7B100BFD34D /* SentryUser+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 92F6726A29C8B7B000BFD34D /* SentryUser+Private.h */; settings = {ATTRIBUTES = (Private, ); }; }; A811D867248E2770008A41EA /* SentrySystemEventBreadcrumbsTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = A811D866248E2770008A41EA /* SentrySystemEventBreadcrumbsTest.swift */; }; - A839D89824864B80003B7AFD /* SentrySystemEventBreadcrumbs.h in Headers */ = {isa = PBXBuildFile; fileRef = A839D89724864B80003B7AFD /* SentrySystemEventBreadcrumbs.h */; }; - A839D89A24864BA8003B7AFD /* SentrySystemEventBreadcrumbs.m in Sources */ = {isa = PBXBuildFile; fileRef = A839D89924864BA8003B7AFD /* SentrySystemEventBreadcrumbs.m */; }; A8AFFCCD29069C3E00967CD7 /* SentryHttpStatusCodeRange.h in Headers */ = {isa = PBXBuildFile; fileRef = A8AFFCCC29069C3E00967CD7 /* SentryHttpStatusCodeRange.h */; settings = {ATTRIBUTES = (Public, ); }; }; A8AFFCCF2906C03700967CD7 /* SentryRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = A8AFFCCE2906C03700967CD7 /* SentryRequest.h */; settings = {ATTRIBUTES = (Public, ); }; }; A8AFFCD22907DA7600967CD7 /* SentryHttpStatusCodeRangeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8AFFCD12907DA7600967CD7 /* SentryHttpStatusCodeRangeTests.swift */; }; @@ -1172,7 +1165,6 @@ 62CFD9AA2C9976E700834E1B /* SentryInvalidJSONString.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SentryInvalidJSONString.h; sourceTree = ""; }; 62CFD9AC2C99770B00834E1B /* SentryInvalidJSONString.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SentryInvalidJSONString.m; sourceTree = ""; }; 62D6B2A62CCA354B004DDBF1 /* SentryUncaughtNSExceptionsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SentryUncaughtNSExceptionsTests.swift; sourceTree = ""; }; - 62E081A829ED4260000F69FC /* SentryBreadcrumbDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SentryBreadcrumbDelegate.h; path = include/SentryBreadcrumbDelegate.h; sourceTree = ""; }; 62E081AA29ED4322000F69FC /* SentryBreadcrumbTestDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SentryBreadcrumbTestDelegate.swift; sourceTree = ""; }; 62E211992DAE99FC007D7262 /* SentryAsyncSafeLog.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SentryAsyncSafeLog.m; sourceTree = ""; }; 62E59A522E8FB70000DB7A7B /* SentryTracePropagation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SentryTracePropagation.h; path = include/SentryTracePropagation.h; sourceTree = ""; }; @@ -1216,8 +1208,6 @@ 6387B82F1ED851970045A84C /* libz.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = usr/lib/libz.tbd; sourceTree = SDKROOT; }; 638DC99E1EBC6B6400A66E41 /* SentryRequestOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SentryRequestOperation.h; path = include/SentryRequestOperation.h; sourceTree = ""; }; 638DC99F1EBC6B6400A66E41 /* SentryRequestOperation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SentryRequestOperation.m; sourceTree = ""; }; - 639889B51EDECFA800EA7442 /* SentryBreadcrumbTracker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SentryBreadcrumbTracker.h; path = include/SentryBreadcrumbTracker.h; sourceTree = ""; }; - 639889B61EDECFA800EA7442 /* SentryBreadcrumbTracker.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SentryBreadcrumbTracker.m; sourceTree = ""; }; 639889B91EDED18400EA7442 /* SentrySwizzle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SentrySwizzle.h; path = include/SentrySwizzle.h; sourceTree = ""; }; 639889BA1EDED18400EA7442 /* SentrySwizzle.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SentrySwizzle.m; sourceTree = ""; }; 639889D21EDF06C100EA7442 /* SentryTests-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "SentryTests-Bridging-Header.h"; sourceTree = ""; }; @@ -1556,8 +1546,7 @@ 7BDB03BE25136A7D00BAE198 /* TestSentryDispatchQueueWrapper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestSentryDispatchQueueWrapper.swift; sourceTree = ""; }; 7BDDE3CB2966BD4700EB9177 /* SentryMXManagerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SentryMXManagerTests.swift; sourceTree = ""; }; 7BE0DC28272A9E1C004FA8B7 /* SentryBreadcrumbTrackerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SentryBreadcrumbTrackerTests.swift; sourceTree = ""; }; - 7BE0DC2E272ABAF6004FA8B7 /* SentryAutoBreadcrumbTrackingIntegrationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SentryAutoBreadcrumbTrackingIntegrationTests.swift; sourceTree = ""; }; - 7BE0DC30272ABCEC004FA8B7 /* SentryAutoBreadcrumbTrackingIntegration+Test.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "SentryAutoBreadcrumbTrackingIntegration+Test.h"; sourceTree = ""; }; + 7BE0DC2E272ABAF6004FA8B7 /* SentryBreadcrumbTrackingIntegrationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SentryBreadcrumbTrackingIntegrationTests.swift; sourceTree = ""; }; 7BE2C7F625700093003B66C7 /* SentryTestIntegration.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SentryTestIntegration.h; sourceTree = ""; }; 7BE2C7F72570009F003B66C7 /* SentryTestIntegration.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SentryTestIntegration.m; sourceTree = ""; }; 7BE3C7742445C82300A38442 /* SentryCurrentDateTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SentryCurrentDateTests.swift; sourceTree = ""; }; @@ -1606,8 +1595,6 @@ 7D9B079F23D1E89800C5FC8E /* SentryMeta.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SentryMeta.h; path = include/SentryMeta.h; sourceTree = ""; }; 7DB3A684238EA75E00A2D442 /* SentryHttpTransport.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SentryHttpTransport.m; sourceTree = ""; }; 7DC27E9823995F97006998B5 /* Sentry.modulemap */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.module-map"; name = Sentry.modulemap; path = ../Resources/Sentry.modulemap; sourceTree = ""; }; - 7DC27EC323997EB7006998B5 /* SentryAutoBreadcrumbTrackingIntegration.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SentryAutoBreadcrumbTrackingIntegration.h; path = include/SentryAutoBreadcrumbTrackingIntegration.h; sourceTree = ""; }; - 7DC27EC423997EB7006998B5 /* SentryAutoBreadcrumbTrackingIntegration.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SentryAutoBreadcrumbTrackingIntegration.m; sourceTree = ""; }; 840A11102B61E27500650D02 /* SentrySamplerDecision.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SentrySamplerDecision.m; sourceTree = ""; }; 840B7EEA2BBF2ABA008B8120 /* .slather.yml */ = {isa = PBXFileReference; lastKnownFileType = text.yaml; path = .slather.yml; sourceTree = ""; }; 840B7EEC2BBF2AFE008B8120 /* .gitattributes */ = {isa = PBXFileReference; lastKnownFileType = text; path = .gitattributes; sourceTree = ""; }; @@ -1793,8 +1780,6 @@ 92D957762E05A4F300E20E66 /* SentryAsyncLog.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SentryAsyncLog.h; path = include/SentryAsyncLog.h; sourceTree = ""; }; 92F6726A29C8B7B000BFD34D /* SentryUser+Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "SentryUser+Private.h"; path = "include/SentryUser+Private.h"; sourceTree = ""; }; A811D866248E2770008A41EA /* SentrySystemEventBreadcrumbsTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SentrySystemEventBreadcrumbsTest.swift; sourceTree = ""; }; - A839D89724864B80003B7AFD /* SentrySystemEventBreadcrumbs.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SentrySystemEventBreadcrumbs.h; path = include/SentrySystemEventBreadcrumbs.h; sourceTree = ""; }; - A839D89924864BA8003B7AFD /* SentrySystemEventBreadcrumbs.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SentrySystemEventBreadcrumbs.m; sourceTree = ""; }; A8AFFCCC29069C3E00967CD7 /* SentryHttpStatusCodeRange.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SentryHttpStatusCodeRange.h; path = Public/SentryHttpStatusCodeRange.h; sourceTree = ""; }; A8AFFCCE2906C03700967CD7 /* SentryRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SentryRequest.h; path = Public/SentryRequest.h; sourceTree = ""; }; A8AFFCD12907DA7600967CD7 /* SentryHttpStatusCodeRangeTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SentryHttpStatusCodeRangeTests.swift; sourceTree = ""; }; @@ -1804,6 +1789,7 @@ D4009EB12D771BB90007AF30 /* SentryFileIOTrackerSwiftHelpersTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SentryFileIOTrackerSwiftHelpersTests.swift; sourceTree = ""; }; D41909922D48FFF6002B83D0 /* SentryNSDictionarySanitize+Tests.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "SentryNSDictionarySanitize+Tests.h"; sourceTree = ""; }; D41909942D490006002B83D0 /* SentryNSDictionarySanitize+Tests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "SentryNSDictionarySanitize+Tests.m"; sourceTree = ""; }; + D41D89E42F15555D00AD9E88 /* SentryAutoBreadcrumbTrackingIntegration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SentryAutoBreadcrumbTrackingIntegration.swift; sourceTree = ""; }; D4291A6C2DD62AC800772088 /* SentryDispatchFactoryTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SentryDispatchFactoryTests.m; sourceTree = ""; }; D42E48562D48DF1600D251BC /* SentryBuildAppStartSpansTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SentryBuildAppStartSpansTests.swift; sourceTree = ""; }; D42E48582D48FC8F00D251BC /* SentryNSDictionarySanitizeTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SentryNSDictionarySanitizeTests.swift; sourceTree = ""; }; @@ -2416,7 +2402,6 @@ isa = PBXGroup; children = ( 7B127B0B27CF6EF600A71ED2 /* ANR */, - 7BE0DC33272AE74A004FA8B7 /* Breadcrumbs */, 7BE0DC34272AE78C004FA8B7 /* WatchdogTerminations */, 7BE0DC39272AE8B3004FA8B7 /* Performance */, 7BE0DC36272AE80A004FA8B7 /* Session */, @@ -3126,20 +3111,6 @@ path = Helper; sourceTree = ""; }; - 7BE0DC33272AE74A004FA8B7 /* Breadcrumbs */ = { - isa = PBXGroup; - children = ( - 7DC27EC323997EB7006998B5 /* SentryAutoBreadcrumbTrackingIntegration.h */, - 7DC27EC423997EB7006998B5 /* SentryAutoBreadcrumbTrackingIntegration.m */, - A839D89724864B80003B7AFD /* SentrySystemEventBreadcrumbs.h */, - A839D89924864BA8003B7AFD /* SentrySystemEventBreadcrumbs.m */, - 639889B51EDECFA800EA7442 /* SentryBreadcrumbTracker.h */, - 639889B61EDECFA800EA7442 /* SentryBreadcrumbTracker.m */, - 62E081A829ED4260000F69FC /* SentryBreadcrumbDelegate.h */, - ); - name = Breadcrumbs; - sourceTree = ""; - }; 7BE0DC34272AE78C004FA8B7 /* WatchdogTerminations */ = { isa = PBXGroup; children = ( @@ -3245,8 +3216,7 @@ 7BE0DC3C272AE9C2004FA8B7 /* Breadcrumbs */ = { isa = PBXGroup; children = ( - 7BE0DC2E272ABAF6004FA8B7 /* SentryAutoBreadcrumbTrackingIntegrationTests.swift */, - 7BE0DC30272ABCEC004FA8B7 /* SentryAutoBreadcrumbTrackingIntegration+Test.h */, + 7BE0DC2E272ABAF6004FA8B7 /* SentryBreadcrumbTrackingIntegrationTests.swift */, 7BE0DC28272A9E1C004FA8B7 /* SentryBreadcrumbTrackerTests.swift */, A811D866248E2770008A41EA /* SentrySystemEventBreadcrumbsTest.swift */, 62E081AA29ED4322000F69FC /* SentryBreadcrumbTestDelegate.swift */, @@ -4207,7 +4177,6 @@ 63295AF51EF3C7DB002D4490 /* SentryNSDictionarySanitize.h in Headers */, 8E4A037825F6F52100000D77 /* SentrySampleDecision.h in Headers */, 63FE717920DA4C1100CDBAE8 /* SentryCrashReportStore.h in Headers */, - A839D89824864B80003B7AFD /* SentrySystemEventBreadcrumbs.h in Headers */, 7B14089624878F090035403D /* SentryCrashStackEntryMapper.h in Headers */, 63FE714920DA4C1100CDBAE8 /* SentryCrashStackCursor_Backtrace.h in Headers */, 7BFC169B2524995700FF6266 /* SentryMessage.h in Headers */, @@ -4259,7 +4228,6 @@ 7B7D873224864BB900D2ECFF /* SentryCrashMachineContextWrapper.h in Headers */, 861265F92404EC1500C4AFDE /* SentryArray.h in Headers */, 63FE712320DA4C1000CDBAE8 /* SentryCrashID.h in Headers */, - 7DC27EC523997EB7006998B5 /* SentryAutoBreadcrumbTrackingIntegration.h in Headers */, 63FE707F20DA4C1000CDBAE8 /* SentryCrashVarArgs.h in Headers */, 03F84D2627DD414C008FE43F /* SentryThreadMetadataCache.hpp in Headers */, FA3734842E0F086C0091EF24 /* SentryDependencyContainerSwiftHelper.h in Headers */, @@ -4304,7 +4272,6 @@ 7BC852332458802C005A70F0 /* SentryDataCategoryMapper.h in Headers */, 7BDB03B7251364F800BAE198 /* _SentryDispatchQueueWrapperInternal.h in Headers */, 621AE74B2C626C230012E730 /* SentryANRTrackerV2.h in Headers */, - 639889B71EDECFA800EA7442 /* SentryBreadcrumbTracker.h in Headers */, 632331F9240506DF008D91D6 /* SentryScope+Private.h in Headers */, D8603DD8284F894C000E1227 /* SentryBaggage.h in Headers */, 03F84D2127DD414C008FE43F /* SentrySamplingProfiler.hpp in Headers */, @@ -4359,7 +4326,6 @@ 7BF9EF722722A84800B5BBEF /* SentryClassRegistrator.h in Headers */, 84A898552E163072009A551E /* SentryProfileConfiguration.h in Headers */, 63FE715520DA4C1100CDBAE8 /* SentryCrashStackCursor_MachineContext.h in Headers */, - 62E081A929ED4260000F69FC /* SentryBreadcrumbDelegate.h in Headers */, 15360CF02433A16D00112302 /* SentryInstallation.h in Headers */, FA24E02A2EBBF6F900EFD92E /* SentryOptionsObjC.h in Headers */, 63FE714720DA4C1100CDBAE8 /* SentryCrashMachineContext.h in Headers */, @@ -4783,7 +4749,8 @@ 7BFC16A125249A9D00FF6266 /* SentryMessage.m in Sources */, 7BCFBD6F2681D0EE00BC27D8 /* SentryCrashScopeObserver.m in Sources */, 7BD86ED1264A7CF6005439DB /* SentryAppStartMeasurement.m in Sources */, - 7DC27EC723997EB7006998B5 /* SentryAutoBreadcrumbTrackingIntegration.m in Sources */, + FAEEC0522E75E55F00E79CA9 /* SentrySerializationSwift.swift in Sources */, + D84D2CDF2C2BF9370011AF8A /* SentryReplayType.swift in Sources */, 63FE717B20DA4C1100CDBAE8 /* SentryCrashReport.c in Sources */, 7B3398652459C15200BD9C96 /* SentryEnvelopeRateLimit.m in Sources */, 0A2D8D9628997845008720F6 /* NSLocale+Sentry.m in Sources */, @@ -4852,11 +4819,14 @@ 84354E1229BF944900CDBB8B /* SentryProfileTimeseries.m in Sources */, 7D5C441C237C2E1F00DAB0A3 /* SentryHub.m in Sources */, 63FE715920DA4C1100CDBAE8 /* SentryCrashCPU_x86_32.c in Sources */, + 92235CAE2E15549C00865983 /* SentryLogger.swift in Sources */, + FAEEBFE22E736D4B00E79CA9 /* SentryViewHierarchyProvider.swift in Sources */, + D40870872F22310D003894F8 /* SentrySystemEventBreadcrumbs.swift in Sources */, 7BE912AD272162D900E49E62 /* SentryNoOpSpan.m in Sources */, 63FE710D20DA4C1000CDBAE8 /* SentryCrashStackCursor_MachineContext.c in Sources */, 63FE70E120DA4C1000CDBAE8 /* SentryCrashMonitor_CPPException.cpp in Sources */, D8F6A2472885512100320515 /* SentryPredicateDescriptor.m in Sources */, - A839D89A24864BA8003B7AFD /* SentrySystemEventBreadcrumbs.m in Sources */, + D41D89E62F15555D00AD9E88 /* SentryAutoBreadcrumbTrackingIntegration.swift in Sources */, 84A305582BC9EF8C00D84283 /* SentryTraceProfiler.mm in Sources */, 7D082B8323C628790029866B /* SentryMeta.m in Sources */, 63FE710720DA4C1000CDBAE8 /* SentryCrashStackCursor_SelfThread.m in Sources */, @@ -4912,7 +4882,7 @@ 63FE70DF20DA4C1000CDBAE8 /* SentryCrashMonitorType.c in Sources */, 7BC3936E25B1AB72004F03D3 /* SentryLevelMapper.m in Sources */, 6304360B1EC0595B00C4D3FA /* SentryNSDataUtils.m in Sources */, - 639889B81EDECFA800EA7442 /* SentryBreadcrumbTracker.m in Sources */, + D81988C52BEC18CA0020E36C /* SentryRRWebCustomEvent.swift in Sources */, 84AF45A729A7FFA500FBB177 /* SentryProfiledTracerConcurrency.mm in Sources */, 03F84D3227DD4191008FE43F /* SentryProfiler.mm in Sources */, 635B3F391EBC6E2500A6176D /* SentryAsynchronousOperation.m in Sources */, @@ -4946,6 +4916,8 @@ 63FE711720DA4C1000CDBAE8 /* SentryCrashStackCursor_Backtrace.c in Sources */, 63FE70CB20DA4C1000CDBAE8 /* SentryCrashReportFixer.c in Sources */, 63FE710F20DA4C1000CDBAE8 /* SentryCrashNSErrorUtil.m in Sources */, + FA34C1A32E692A5000BC52AA /* SentryEnvelopeItem.swift in Sources */, + D40870C92F224DED003894F8 /* SentryBreadcrumbTracker.swift in Sources */, 8ECC674925C23A20000E2BF6 /* SentrySpanId.m in Sources */, 6344DDB51EC309E000D9160D /* SentryCrashReportSink.m in Sources */, D43B26D62D70964C007747FD /* SentrySpanOperation.m in Sources */, @@ -4966,6 +4938,7 @@ 03F84D3327DD4191008FE43F /* SentryMachLogging.cpp in Sources */, FAB3599A2E05D8080083D5E3 /* SentryEventSwiftHelper.m in Sources */, 7B4E375F258231FC00059C93 /* SentryAttachment.m in Sources */, + D40870C72F224DE5003894F8 /* SentryBreadcrumbDelegate.swift in Sources */, 636085141ED47BE600E8599E /* SentryFileManagerHelper.m in Sources */, 63FE710B20DA4C1000CDBAE8 /* SentryCrashMach.c in Sources */, 63FE707720DA4C1000CDBAE8 /* SentryDictionaryDeepSearch.m in Sources */, @@ -5228,7 +5201,7 @@ 6281C5742D3E50DF009D0978 /* ArbitraryDataTests.swift in Sources */, FAC880B62EE5FA31007B4796 /* TestNSURLRequestBuilder.swift in Sources */, FAD882762EDA6EF50055AA44 /* SentrySDKInfo+Equality.swift in Sources */, - 7BE0DC2F272ABAF6004FA8B7 /* SentryAutoBreadcrumbTrackingIntegrationTests.swift in Sources */, + 7BE0DC2F272ABAF6004FA8B7 /* SentryBreadcrumbTrackingIntegrationTests.swift in Sources */, 7B869EBE249B964D004F4FDB /* SentryThreadEquality.swift in Sources */, 6205CF262D549D8A001E6049 /* SentryDateCodableTests.swift in Sources */, 7BC6EBF8255C05060059822A /* TestData.swift in Sources */, diff --git a/Sources/Sentry/SentryAutoBreadcrumbTrackingIntegration.m b/Sources/Sentry/SentryAutoBreadcrumbTrackingIntegration.m deleted file mode 100644 index 6755dc98b9d..00000000000 --- a/Sources/Sentry/SentryAutoBreadcrumbTrackingIntegration.m +++ /dev/null @@ -1,101 +0,0 @@ -#import "SentryAutoBreadcrumbTrackingIntegration.h" -#import "SentryBreadcrumbTracker.h" -#import "SentryLogC.h" -#import "SentrySDKInternal.h" -#import "SentrySwift.h" -#import "SentrySystemEventBreadcrumbs.h" - -NS_ASSUME_NONNULL_BEGIN - -@interface SentryAutoBreadcrumbTrackingIntegration () - -@property (nonatomic, strong) SentryBreadcrumbTracker *breadcrumbTracker; - -#if TARGET_OS_IOS && SENTRY_HAS_UIKIT -@property (nonatomic, strong) SentrySystemEventBreadcrumbs *systemEventBreadcrumbs; -#endif // TARGET_OS_IOS && SENTRY_HAS_UIKIT - -@end - -@implementation SentryAutoBreadcrumbTrackingIntegration - -- (BOOL)installWithOptions:(SentryOptions *)options -{ - if (![super installWithOptions:options]) { - return NO; - } - - SentryFileManager *_Nullable fileManager = SentryDependencyContainer.sharedInstance.fileManager; - if (!fileManager) { - SENTRY_LOG_FATAL(@"File manager is not available"); - return NO; - } - -#if TARGET_OS_IOS && SENTRY_HAS_UIKIT - [self installWithOptions:options - breadcrumbTracker:[[SentryBreadcrumbTracker alloc] initReportAccessibilityIdentifier: - options.reportAccessibilityIdentifier] - systemEventBreadcrumbs:[[SentrySystemEventBreadcrumbs alloc] - initWithFileManager:SENTRY_UNWRAP_NULLABLE( - SentryFileManager, fileManager) - andNotificationCenterWrapper:SentryDependencyContainer - .sharedInstance - .notificationCenterWrapper]]; -#else - [self installWithOptions:options - breadcrumbTracker:[[SentryBreadcrumbTracker alloc] - initReportAccessibilityIdentifier:false]]; -#endif // TARGET_OS_IOS && SENTRY_HAS_UIKIT - - return YES; -} - -- (SentryIntegrationOption)integrationOptions -{ - return kIntegrationOptionEnableAutoBreadcrumbTracking; -} - -/** - * For testing. - */ -- (void)installWithOptions:(nonnull SentryOptions *)options - breadcrumbTracker:(SentryBreadcrumbTracker *)breadcrumbTracker -#if TARGET_OS_IOS && SENTRY_HAS_UIKIT - systemEventBreadcrumbs:(SentrySystemEventBreadcrumbs *)systemEventBreadcrumbs -#endif // TARGET_OS_IOS && SENTRY_HAS_UIKIT -{ - self.breadcrumbTracker = breadcrumbTracker; - [self.breadcrumbTracker startWithDelegate:self]; - -#if SENTRY_HAS_UIKIT - if (options.enableSwizzling) { - [self.breadcrumbTracker startSwizzle]; - } -#endif // SENTRY_HAS_UIKIT - -#if TARGET_OS_IOS && SENTRY_HAS_UIKIT - self.systemEventBreadcrumbs = systemEventBreadcrumbs; - [self.systemEventBreadcrumbs startWithDelegate:self]; -#endif // TARGET_OS_IOS && SENTRY_HAS_UIKIT -} - -- (void)uninstall -{ - if (nil != self.breadcrumbTracker) { - [self.breadcrumbTracker stop]; - } -#if TARGET_OS_IOS && SENTRY_HAS_UIKIT - if (nil != self.systemEventBreadcrumbs) { - [self.systemEventBreadcrumbs stop]; - } -#endif // TARGET_OS_IOS && SENTRY_HAS_UIKIT -} - -- (void)addBreadcrumb:(SentryBreadcrumb *)crumb -{ - [SentrySDKInternal addBreadcrumb:crumb]; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/Sources/Sentry/SentryBreadcrumbTracker.m b/Sources/Sentry/SentryBreadcrumbTracker.m deleted file mode 100644 index 4754600d576..00000000000 --- a/Sources/Sentry/SentryBreadcrumbTracker.m +++ /dev/null @@ -1,332 +0,0 @@ -#import "SentryBreadcrumbTracker.h" -#import "SentryBreadcrumb.h" -#import "SentryBreadcrumbDelegate.h" -#import "SentryClient.h" -#import "SentryDefines.h" -#import "SentryHub.h" -#import "SentryInternalDefines.h" -#import "SentryLogC.h" -#import "SentryScope.h" -#import "SentrySwift.h" -#import "SentrySwizzle.h" - -#if SENTRY_TARGET_MACOS_HAS_UI -# import -#endif // SENTRY_TARGET_MACOS_HAS_UI - -#if SENTRY_HAS_UIKIT -# import -#endif // SENTRY_HAS_UIKIT - -NS_ASSUME_NONNULL_BEGIN - -static NSString *const SentryBreadcrumbTrackerSwizzleSendAction - = @"SentryBreadcrumbTrackerSwizzleSendAction"; - -@interface SentryBreadcrumbTracker () - -@property (nonatomic, weak) id delegate; - -@end - -@implementation SentryBreadcrumbTracker { - BOOL _reportAccessibilityIdentifier; -} - -- (void)dealloc -{ - [SentryDependencyContainer.sharedInstance.reachability removeObserver:self]; -} - -- (instancetype)initReportAccessibilityIdentifier:(BOOL)report -{ - if (self = [super init]) { - _reportAccessibilityIdentifier = report; - } - return self; -} - -- (void)startWithDelegate:(id)delegate -{ - _delegate = delegate; - [self addEnabledCrumb]; - [self trackApplicationNotifications]; - [self trackNetworkConnectivityChanges]; -} - -#if SENTRY_HAS_UIKIT -- (void)startSwizzle -{ - [self swizzleSendAction]; - [self swizzleViewDidAppear]; -} -#endif // SENTRY_HAS_UIKIT - -- (void)stop -{ - // All breadcrumbs are guarded by checking the client of the current hub, which we remove when - // uninstalling the SDK. Therefore, we don't clean up everything. -#if SENTRY_HAS_UIKIT - [SentryDependencyContainer.sharedInstance.swizzleWrapper - removeSwizzleSendActionForKey:SentryBreadcrumbTrackerSwizzleSendAction]; -#endif // SENTRY_HAS_UIKIT - _delegate = nil; - [self stopTrackNetworkConnectivityChanges]; -} - -- (void)trackApplicationNotifications -{ -#if SENTRY_HAS_UIKIT - NSNotificationName foregroundNotificationName = UIApplicationDidBecomeActiveNotification; - NSNotificationName backgroundNotificationName = UIApplicationDidEnterBackgroundNotification; -#elif SENTRY_TARGET_MACOS_HAS_UI - NSNotificationName foregroundNotificationName = NSApplicationDidBecomeActiveNotification; - // Will resign Active notification is the nearest one to - // UIApplicationDidEnterBackgroundNotification - NSNotificationName backgroundNotificationName = NSApplicationWillResignActiveNotification; -#else // TARGET_OS_WATCH - SENTRY_LOG_DEBUG(@"NO UIKit, OSX and Catalyst -> [SentryBreadcrumbTracker " - @"trackApplicationNotifications] does nothing."); -#endif // !TARGET_OS_WATCH - - // not available for macOS -#if SENTRY_HAS_UIKIT - [NSNotificationCenter.defaultCenter - addObserverForName:UIApplicationDidReceiveMemoryWarningNotification - object:nil - queue:nil - usingBlock:^(NSNotification *notification) { - SentryBreadcrumb *crumb = - [[SentryBreadcrumb alloc] initWithLevel:kSentryLevelWarning - category:@"device.event"]; - crumb.type = @"system"; - crumb.data = @ { @"action" : @"LOW_MEMORY" }; - crumb.message = @"Low memory"; - [self.delegate addBreadcrumb:crumb]; - }]; -#endif // SENTRY_HAS_UIKIT - -#if SENTRY_HAS_UIKIT || SENTRY_TARGET_MACOS_HAS_UI - [NSNotificationCenter.defaultCenter addObserverForName:backgroundNotificationName - object:nil - queue:nil - usingBlock:^(NSNotification *notification) { - [self addBreadcrumbWithType:@"navigation" - withCategory:@"app.lifecycle" - withLevel:kSentryLevelInfo - withDataKey:@"state" - withDataValue:@"background"]; - }]; - - [NSNotificationCenter.defaultCenter addObserverForName:foregroundNotificationName - object:nil - queue:nil - usingBlock:^(NSNotification *notification) { - [self addBreadcrumbWithType:@"navigation" - withCategory:@"app.lifecycle" - withLevel:kSentryLevelInfo - withDataKey:@"state" - withDataValue:@"foreground"]; - }]; -#endif // SENTRY_HAS_UIKIT || SENTRY_TARGET_MACOS_HAS_UI -} - -- (void)trackNetworkConnectivityChanges -{ - [SentryDependencyContainer.sharedInstance.reachability addObserver:self]; -} - -- (void)stopTrackNetworkConnectivityChanges -{ - [SentryDependencyContainer.sharedInstance.reachability removeObserver:self]; -} - -- (void)connectivityChanged:(BOOL)connected typeDescription:(nonnull NSString *)typeDescription -{ - SentryBreadcrumb *crumb = [[SentryBreadcrumb alloc] initWithLevel:kSentryLevelInfo - category:@"device.connectivity"]; - crumb.type = @"connectivity"; - crumb.data = [NSDictionary dictionaryWithObject:typeDescription forKey:@"connectivity"]; - [self.delegate addBreadcrumb:crumb]; -} - -- (void)addBreadcrumbWithType:(NSString *)type - withCategory:(NSString *)category - withLevel:(SentryLevel)level - withDataKey:(NSString *)key - withDataValue:(NSString *)value -{ - SentryBreadcrumb *crumb = [[SentryBreadcrumb alloc] initWithLevel:level category:category]; - crumb.type = type; - crumb.data = @{ key : value }; - [self.delegate addBreadcrumb:crumb]; -} - -- (void)addEnabledCrumb -{ - SentryBreadcrumb *crumb = [[SentryBreadcrumb alloc] initWithLevel:kSentryLevelInfo - category:@"started"]; - crumb.type = @"debug"; - crumb.message = @"Breadcrumb Tracking"; - [self.delegate addBreadcrumb:crumb]; -} - -#if SENTRY_HAS_UIKIT -+ (BOOL)avoidSender:(id)sender forTarget:(id)target action:(NSString *)action -{ - if (sender == nil || target == nil) { - return YES; - } - - if ([sender isKindOfClass:UITextField.self]) { - // This is required to avoid creating breadcrumbs for every key pressed in a text field. - // Textfield may invoke many types of event, in order to check if is a - // `UIControlEventEditingChanged` we need to compare the current action to all events - // attached to the control. This may cause a false negative if the developer is using the - // same action for different events, but this trade off is acceptable because using the same - // action for `.editingChanged` and another event is not supposed to happen. - UITextField *textField = sender; - NSArray *actions = [textField actionsForTarget:target - forControlEvent:UIControlEventEditingChanged]; - return [actions containsObject:action]; - } - return NO; -} -#endif // SENTRY_HAS_UIKIT - -#if SENTRY_HAS_UIKIT -- (void)swizzleSendAction -{ - SentryBreadcrumbTracker *__weak weakSelf = self; - [SentryDependencyContainer.sharedInstance.swizzleWrapper - swizzleSendAction:^(NSString *action, id target, id sender, UIEvent *event) { - if ([SentryBreadcrumbTracker avoidSender:sender forTarget:target action:action]) { - return; - } - - NSDictionary *data = nil; - for (UITouch *touch in event.allTouches) { - if (touch.view != nil - && (touch.phase == UITouchPhaseCancelled || touch.phase == UITouchPhaseEnded)) { - data = [SentryBreadcrumbTracker - extractDataFromView:SENTRY_UNWRAP_NULLABLE_VALUE(id, touch.view) - withAccessibilityIdentifier:self->_reportAccessibilityIdentifier]; - } - } - - SentryBreadcrumb *crumb = [[SentryBreadcrumb alloc] initWithLevel:kSentryLevelInfo - category:@"touch"]; - crumb.type = @"user"; - crumb.message = action; - crumb.data = data; - [weakSelf.delegate addBreadcrumb:crumb]; - } - forKey:SentryBreadcrumbTrackerSwizzleSendAction]; -} -#endif // SENTRY_HAS_UIKIT - -#if SENTRY_HAS_UIKIT -- (void)swizzleViewDidAppear -{ - - // SentrySwizzleInstanceMethod declaration shadows a local variable. The swizzling is working - // fine and we accept this warning. -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wshadow" - - static const void *swizzleViewDidAppearKey = &swizzleViewDidAppearKey; - SEL selector = NSSelectorFromString(@"viewDidAppear:"); - SentryBreadcrumbTracker *__weak weakSelf = self; - - SentrySwizzleMode mode = SentrySwizzleModeOncePerClassAndSuperclasses; - -# if defined(SENTRY_TEST) || defined(SENTRY_TEST_CI) - // some tests need to swizzle multiple times, once for each test case. but since they're in the - // same process, if they set something other than "always", subsequent swizzles fail. override - // it here for tests - mode = SentrySwizzleModeAlways; -# endif // defined(SENTRY_TEST) || defined(SENTRY_TEST_CI) - - SentrySwizzleInstanceMethod(UIViewController.class, selector, SentrySWReturnType(void), - SentrySWArguments(BOOL animated), SentrySWReplacement({ - SentryBreadcrumb *crumb = [[SentryBreadcrumb alloc] initWithLevel:kSentryLevelInfo - category:@"ui.lifecycle"]; - crumb.type = @"navigation"; - crumb.data = [SentryBreadcrumbTracker fetchInfoAboutViewController:self]; - - [weakSelf.delegate addBreadcrumb:crumb]; - - SentrySWCallOriginal(animated); - }), - mode, swizzleViewDidAppearKey); -# pragma clang diagnostic pop -} - -+ (NSDictionary *)extractDataFromView:(UIView *)view - withAccessibilityIdentifier:(BOOL)includeIdentifier -{ - NSMutableDictionary *result = - @{ @"view" : [NSString stringWithFormat:@"%@", view] }.mutableCopy; - - if (view.tag > 0) { - [result setValue:[NSNumber numberWithInteger:view.tag] forKey:@"tag"]; - } - - if (includeIdentifier && view.accessibilityIdentifier - && ![view.accessibilityIdentifier isEqualToString:@""]) { - [result setValue:view.accessibilityIdentifier forKey:@"accessibilityIdentifier"]; - } - - if ([view isKindOfClass:UIButton.class]) { - UIButton *button = (UIButton *)view; - if (button.currentTitle && ![button.currentTitle isEqual:@""]) { - [result setValue:[button currentTitle] forKey:@"title"]; - } - } - - return result; -} - -+ (NSDictionary *)fetchInfoAboutViewController:(UIViewController *)controller -{ - NSMutableDictionary *info = @{}.mutableCopy; - - info[@"screen"] = [SwiftDescriptor getViewControllerClassName:controller]; - - if ([controller.navigationItem.title length] != 0) { - info[@"title"] = controller.navigationItem.title; - } else if ([controller.title length] != 0) { - info[@"title"] = controller.title; - } - - info[@"beingPresented"] = controller.beingPresented ? @"true" : @"false"; - - if (controller.presentingViewController != nil) { - info[@"presentingViewController"] = - [SwiftDescriptor getViewControllerClassName:SENTRY_UNWRAP_NULLABLE(UIViewController, - controller.presentingViewController)]; - } - - if (controller.parentViewController != nil) { - info[@"parentViewController"] = - [SwiftDescriptor getViewControllerClassName:SENTRY_UNWRAP_NULLABLE(UIViewController, - controller.parentViewController)]; - } - - if (controller.view.window != nil) { - info[@"window"] = controller.view.window.description; - info[@"window_isKeyWindow"] = controller.view.window.isKeyWindow ? @"true" : @"false"; - info[@"window_windowLevel"] = - [NSString stringWithFormat:@"%f", controller.view.window.windowLevel]; - info[@"is_window_rootViewController"] - = controller.view.window.rootViewController == controller ? @"true" : @"false"; - } - - return info; -} - -#endif // SENTRY_HAS_UIKIT - -@end - -NS_ASSUME_NONNULL_END diff --git a/Sources/Sentry/SentrySDKInternal.m b/Sources/Sentry/SentrySDKInternal.m index 196b3712431..77dd778919c 100644 --- a/Sources/Sentry/SentrySDKInternal.m +++ b/Sources/Sentry/SentrySDKInternal.m @@ -1,7 +1,6 @@ #import "SentrySDKInternal.h" #import "PrivateSentrySDKOnly.h" #import "SentryAppStartMeasurement.h" -#import "SentryAutoBreadcrumbTrackingIntegration.h" #import "SentryBreadcrumb.h" #import "SentryClient+Private.h" #import "SentryCoreDataTrackingIntegration.h" @@ -501,8 +500,7 @@ + (void)endSession #if SENTRY_HAS_UIKIT [SentryAppStartTrackingIntegration class], [SentryPerformanceTrackingIntegration class], #endif // SENTRY_HAS_UIKIT - [SentryAutoBreadcrumbTrackingIntegration class], [SentryCoreDataTrackingIntegration class], - nil]; + [SentryCoreDataTrackingIntegration class], nil]; return defaultIntegrations; } diff --git a/Sources/Sentry/SentrySwizzleWrapperHelper.m b/Sources/Sentry/SentrySwizzleWrapperHelper.m index 095a5de7d09..fb7188ab85b 100644 --- a/Sources/Sentry/SentrySwizzleWrapperHelper.m +++ b/Sources/Sentry/SentrySwizzleWrapperHelper.m @@ -28,6 +28,31 @@ + (void)swizzle:(void (^)(SEL action, _Nullable id target, _Nullable id sender, # pragma clang diagnostic pop } ++ (void)swizzleViewDidAppear:(void (^)(UIViewController *viewController))callback + forKey:(const void *)key +{ +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wshadow" + SEL selector = NSSelectorFromString(@"viewDidAppear:"); + + SentrySwizzleMode mode = SentrySwizzleModeOncePerClassAndSuperclasses; + +# if defined(SENTRY_TEST) || defined(SENTRY_TEST_CI) + // some tests need to swizzle multiple times, once for each test case. but since they're in the + // same process, if they set something other than "always", subsequent swizzles fail. override + // it here for tests + mode = SentrySwizzleModeAlways; +# endif // defined(SENTRY_TEST) || defined(SENTRY_TEST_CI) + + SentrySwizzleInstanceMethod(UIViewController.class, selector, SentrySWReturnType(void), + SentrySWArguments(BOOL animated), SentrySWReplacement({ + callback(self); + SentrySWCallOriginal(animated); + }), + mode, key); +# pragma clang diagnostic pop +} + + (void)swizzleSendEvent:(void (^)(UIEvent *_Nullable event))callback; { # pragma clang diagnostic push diff --git a/Sources/Sentry/SentrySystemEventBreadcrumbs.m b/Sources/Sentry/SentrySystemEventBreadcrumbs.m deleted file mode 100644 index 0f66099ef59..00000000000 --- a/Sources/Sentry/SentrySystemEventBreadcrumbs.m +++ /dev/null @@ -1,315 +0,0 @@ -#import "SentrySystemEventBreadcrumbs.h" -#import "SentryBreadcrumb.h" -#import "SentryBreadcrumbDelegate.h" -#import "SentryDefines.h" -#import "SentryLogC.h" -#import "SentrySwift.h" - -#if TARGET_OS_IOS && SENTRY_HAS_UIKIT - -# import - -@interface SentrySystemEventBreadcrumbs () -@property (nonatomic, weak) id delegate; -@property (nonatomic, strong) SentryFileManager *fileManager; -@property (nonatomic, strong) id notificationCenterWrapper; -@end - -@implementation SentrySystemEventBreadcrumbs - -- (instancetype)initWithFileManager:(SentryFileManager *)fileManager - andNotificationCenterWrapper:(id)notificationCenterWrapper -{ - if (self = [super init]) { - _fileManager = fileManager; - _notificationCenterWrapper = notificationCenterWrapper; - } - return self; -} - -- (void)startWithDelegate:(id)delegate -{ - UIDevice *currentDevice = [UIDevice currentDevice]; - [self startWithDelegate:delegate currentDevice:currentDevice]; -} - -- (void)stop -{ - // Remove the observers with the most specific detail possible, see - // https://developer.apple.com/documentation/foundation/nsnotificationcenter/1413994-removeobserver - [self.notificationCenterWrapper removeObserver:self - name:UIKeyboardDidShowNotification - object:nil]; - [self.notificationCenterWrapper removeObserver:self - name:UIKeyboardDidHideNotification - object:nil]; - [self.notificationCenterWrapper removeObserver:self - name:UIApplicationUserDidTakeScreenshotNotification - object:nil]; - [self.notificationCenterWrapper removeObserver:self - name:UIDeviceBatteryLevelDidChangeNotification - object:nil]; - [self.notificationCenterWrapper removeObserver:self - name:UIDeviceBatteryStateDidChangeNotification - object:nil]; - [self.notificationCenterWrapper removeObserver:self - name:UIDeviceOrientationDidChangeNotification - object:nil]; - [self.notificationCenterWrapper removeObserver:self - name:UIApplicationSignificantTimeChangeNotification - object:nil]; -} - -- (void)dealloc -{ - // In dealloc it's safe to unsubscribe for all, see - // https://developer.apple.com/documentation/foundation/nsnotificationcenter/1413994-removeobserver - [self.notificationCenterWrapper removeObserver:self name:nil object:nil]; -} - -/** - * Only used for testing, call startWithDelegate instead. - */ -- (void)startWithDelegate:(id)delegate - currentDevice:(nullable UIDevice *)currentDevice -{ - _delegate = delegate; - if (currentDevice != nil) { - [self initBatteryObserver:currentDevice]; - [self initOrientationObserver:currentDevice]; - } else { - SENTRY_LOG_DEBUG(@"currentDevice is null, it won't be able to record breadcrumbs for " - @"device battery and orientation."); - } - [self initKeyboardVisibilityObserver]; - [self initScreenshotObserver]; - [self initTimezoneObserver]; - [self initSignificantTimeChangeObserver]; -} - -- (void)initBatteryObserver:(UIDevice *)currentDevice -{ - if (currentDevice.batteryMonitoringEnabled == NO) { - currentDevice.batteryMonitoringEnabled = YES; - } - - // Posted when the battery level changes. - [self.notificationCenterWrapper addObserver:self - selector:@selector(batteryStateChanged:) - name:UIDeviceBatteryLevelDidChangeNotification - object:currentDevice]; - - // Posted when battery state changes. - [self.notificationCenterWrapper addObserver:self - selector:@selector(batteryStateChanged:) - name:UIDeviceBatteryStateDidChangeNotification - object:currentDevice]; -} - -- (void)batteryStateChanged:(NSNotification *)notification -{ - // Notifications for battery level change are sent no more frequently than once per minute - UIDevice *currentDevice = notification.object; - // The object of an NSNotification may be nil. - if (currentDevice == nil) { - SENTRY_LOG_DEBUG( - @"UIDevice of NSNotification was nil. Won't create battery changed breadcrumb."); - return; - } - - NSDictionary *batteryData = [self getBatteryStatus:notification.object]; - - SentryBreadcrumb *crumb = [[SentryBreadcrumb alloc] initWithLevel:kSentryLevelInfo - category:@"device.event"]; - crumb.type = @"system"; - crumb.data = batteryData; - [_delegate addBreadcrumb:crumb]; -} - -- (NSDictionary *)getBatteryStatus:(UIDevice *)currentDevice -{ - // borrowed and adapted from - // https://github.com/apache/cordova-plugin-battery-status/blob/master/src/ios/CDVBattery.m - UIDeviceBatteryState currentState = [currentDevice batteryState]; - - BOOL isPlugged = NO; // UIDeviceBatteryStateUnknown or UIDeviceBatteryStateUnplugged - if ((currentState == UIDeviceBatteryStateCharging) - || (currentState == UIDeviceBatteryStateFull)) { - isPlugged = YES; - } - float currentLevel = [currentDevice batteryLevel]; - NSMutableDictionary *batteryData = - [NSMutableDictionary dictionaryWithCapacity:3]; - - // W3C spec says level must be null if it is unknown - if ((currentState != UIDeviceBatteryStateUnknown) && (currentLevel != -1.0)) { - float w3cLevel = (currentLevel * 100); - batteryData[@"level"] = @(w3cLevel); - } else { - SENTRY_LOG_DEBUG(@"batteryLevel is unknown."); - } - - batteryData[@"plugged"] = @(isPlugged); - batteryData[@"action"] = @"BATTERY_STATE_CHANGE"; - - return batteryData; -} - -- (void)initOrientationObserver:(UIDevice *)currentDevice -{ - if (currentDevice.isGeneratingDeviceOrientationNotifications == NO) { - [currentDevice beginGeneratingDeviceOrientationNotifications]; - } - - // Posted when the orientation of the device changes. - [self.notificationCenterWrapper addObserver:self - selector:@selector(orientationChanged:) - name:UIDeviceOrientationDidChangeNotification - object:currentDevice]; -} - -- (void)orientationChanged:(NSNotification *)notification -{ - UIDevice *currentDevice = notification.object; - SentryBreadcrumb *crumb = [[SentryBreadcrumb alloc] initWithLevel:kSentryLevelInfo - category:@"device.orientation"]; - - UIDeviceOrientation currentOrientation = currentDevice.orientation; - - // Ignore changes in device orientation if unknown, face up, or face down. - if (!UIDeviceOrientationIsValidInterfaceOrientation(currentOrientation)) { - SENTRY_LOG_DEBUG(@"currentOrientation is unknown."); - return; - } - - if (UIDeviceOrientationIsLandscape(currentOrientation)) { - crumb.data = @{ @"position" : @"landscape" }; - } else { - crumb.data = @{ @"position" : @"portrait" }; - } - crumb.type = @"navigation"; - [_delegate addBreadcrumb:crumb]; -} - -- (void)initKeyboardVisibilityObserver -{ - // Posted immediately after the display of the keyboard. - [self.notificationCenterWrapper addObserver:self - selector:@selector(systemEventTriggered:) - name:UIKeyboardDidShowNotification - object:nil]; - - // Posted immediately after the dismissal of the keyboard. - [self.notificationCenterWrapper addObserver:self - selector:@selector(systemEventTriggered:) - name:UIKeyboardDidHideNotification - object:nil]; -} - -- (void)systemEventTriggered:(NSNotification *)notification -{ - SentryBreadcrumb *crumb = [[SentryBreadcrumb alloc] initWithLevel:kSentryLevelInfo - category:@"device.event"]; - crumb.type = @"system"; - crumb.data = @{ @"action" : notification.name }; - [_delegate addBreadcrumb:crumb]; -} - -- (void)initScreenshotObserver -{ - // it's only about the action, but not the SS itself - [self.notificationCenterWrapper addObserver:self - selector:@selector(systemEventTriggered:) - name:UIApplicationUserDidTakeScreenshotNotification - object:nil]; -} - -- (void)initTimezoneObserver -{ - // Detect if the stored timezone is different from the current one; - // if so, then we also send a breadcrumb - NSNumber *_Nullable storedTimezoneOffset = [self.fileManager readTimezoneOffset]; - - if (storedTimezoneOffset == nil) { - [self updateStoredTimezone]; - } else if (storedTimezoneOffset.doubleValue - != SentryDependencyContainer.sharedInstance.dateProvider.timezoneOffset) { - [self timezoneEventTriggered:storedTimezoneOffset]; - } - - // Posted when the timezone of the device changed - [self.notificationCenterWrapper addObserver:self - selector:@selector(timezoneEventTriggered) - name:NSSystemTimeZoneDidChangeNotification - object:nil]; -} - -- (void)timezoneEventTriggered -{ - [self timezoneEventTriggered:nil]; -} - -- (void)timezoneEventTriggered:(NSNumber *)storedTimezoneOffset -{ - if (storedTimezoneOffset == nil) { - storedTimezoneOffset = [self.fileManager readTimezoneOffset]; - } - - SentryBreadcrumb *crumb = [[SentryBreadcrumb alloc] initWithLevel:kSentryLevelInfo - category:@"device.event"]; - - NSInteger offset = SentryDependencyContainer.sharedInstance.dateProvider.timezoneOffset; - - crumb.type = @"system"; - - NSMutableDictionary *dataDict = - [@{ @"action" : @"TIMEZONE_CHANGE", @"current_seconds_from_gmt" : @(offset) } mutableCopy]; - - if (storedTimezoneOffset != nil) { - dataDict[@"previous_seconds_from_gmt"] = storedTimezoneOffset; - } - - crumb.data = dataDict; - [_delegate addBreadcrumb:crumb]; - - [self updateStoredTimezone]; -} - -- (void)updateStoredTimezone -{ - [self.fileManager - storeTimezoneOffset:SentryDependencyContainer.sharedInstance.dateProvider.timezoneOffset]; -} - -- (void)initSignificantTimeChangeObserver -{ - - [self.notificationCenterWrapper addObserver:self - selector:@selector(significantTimeChangeTriggered:) - name:UIApplicationSignificantTimeChangeNotification - object:nil]; -} - -/** - * The system posts this notification when, for example, there’s a change to a new day (midnight), a - * carrier time update, or a change to, or from, daylight savings time. The notification doesn’t - * contain a user info dictionary. - * - * @see - * https://developer.apple.com/documentation/uikit/uiapplication/significanttimechangenotification#Discussion - */ -- (void)significantTimeChangeTriggered:(NSNotification *)notification -{ - SentryBreadcrumb *crumb = [[SentryBreadcrumb alloc] initWithLevel:kSentryLevelInfo - category:@"device.event"]; - crumb.type = @"system"; - - // We don't add the timezone here, because we already add it in timezoneEventTriggered. - crumb.data = @{ @"action" : @"SIGNIFICANT_TIME_CHANGE" }; - - [_delegate addBreadcrumb:crumb]; -} - -@end - -#endif // TARGET_OS_IOS && SENTRY_HAS_UIKIT diff --git a/Sources/Sentry/include/SentryAutoBreadcrumbTrackingIntegration.h b/Sources/Sentry/include/SentryAutoBreadcrumbTrackingIntegration.h deleted file mode 100644 index 8834c765da7..00000000000 --- a/Sources/Sentry/include/SentryAutoBreadcrumbTrackingIntegration.h +++ /dev/null @@ -1,14 +0,0 @@ -#import "SentryBaseIntegration.h" -#import "SentryBreadcrumbDelegate.h" - -NS_ASSUME_NONNULL_BEGIN - -/** - * This automatically adds breadcrumbs for different user actions. - */ -@interface SentryAutoBreadcrumbTrackingIntegration - : SentryBaseIntegration - -@end - -NS_ASSUME_NONNULL_END diff --git a/Sources/Sentry/include/SentryBreadcrumbTracker.h b/Sources/Sentry/include/SentryBreadcrumbTracker.h deleted file mode 100644 index 6b10dea36a4..00000000000 --- a/Sources/Sentry/include/SentryBreadcrumbTracker.h +++ /dev/null @@ -1,21 +0,0 @@ -#import "SentryDefines.h" - -NS_ASSUME_NONNULL_BEGIN - -@protocol SentryBreadcrumbDelegate; - -@interface SentryBreadcrumbTracker : NSObject - -SENTRY_NO_INIT - -- (instancetype)initReportAccessibilityIdentifier:(BOOL)report; - -- (void)startWithDelegate:(id)delegate; -#if SENTRY_HAS_UIKIT -- (void)startSwizzle; -#endif // SENTRY_HAS_UIKIT -- (void)stop; - -@end - -NS_ASSUME_NONNULL_END diff --git a/Sources/Sentry/include/SentrySwizzleWrapperHelper.h b/Sources/Sentry/include/SentrySwizzleWrapperHelper.h index 0a76ecffcf8..baeb89449a5 100644 --- a/Sources/Sentry/include/SentrySwizzleWrapperHelper.h +++ b/Sources/Sentry/include/SentrySwizzleWrapperHelper.h @@ -15,6 +15,11 @@ NS_ASSUME_NONNULL_BEGIN #if SENTRY_HAS_UIKIT + (void)swizzle:(void (^)(SEL action, _Nullable id target, _Nullable id sender, UIEvent *_Nullable event))callback; + +// Swizzle [UIViewController viewDidAppear:] to track view controller lifecycle ++ (void)swizzleViewDidAppear:(void (^)(UIViewController *viewController))callback + forKey:(const void *)key; + // Swizzle [UIApplication sendEvent:] + (void)swizzleSendEvent:(void (^)(UIEvent *_Nullable event))callback; #endif // SENTRY_HAS_UIKIT diff --git a/Sources/Sentry/include/SentrySystemEventBreadcrumbs.h b/Sources/Sentry/include/SentrySystemEventBreadcrumbs.h deleted file mode 100644 index 3e27da37ca9..00000000000 --- a/Sources/Sentry/include/SentrySystemEventBreadcrumbs.h +++ /dev/null @@ -1,32 +0,0 @@ -#import "SentryDefines.h" - -#if TARGET_OS_IOS && SENTRY_HAS_UIKIT - -# import - -NS_ASSUME_NONNULL_BEGIN - -@class SentryFileManager; -@protocol SentryNSNotificationCenterWrapper; -@protocol SentryBreadcrumbDelegate; - -@interface SentrySystemEventBreadcrumbs : NSObject -SENTRY_NO_INIT - -- (instancetype)initWithFileManager:(SentryFileManager *)fileManager - andNotificationCenterWrapper: - (id)notificationCenterWrapper; - -- (void)startWithDelegate:(id)delegate; - -- (void)startWithDelegate:(id)delegate - currentDevice:(nullable UIDevice *)currentDevice; -- (void)timezoneEventTriggered; - -- (void)stop; - -@end - -NS_ASSUME_NONNULL_END - -#endif // TARGET_OS_IOS && SENTRY_HAS_UIKIT diff --git a/Sources/Swift/Core/Helper/SentryUIDeviceWrapper.swift b/Sources/Swift/Core/Helper/SentryUIDeviceWrapper.swift index c7177c0f0e9..73d49bfebec 100644 --- a/Sources/Swift/Core/Helper/SentryUIDeviceWrapper.swift +++ b/Sources/Swift/Core/Helper/SentryUIDeviceWrapper.swift @@ -6,6 +6,7 @@ import UIKit func start() func stop() func getSystemVersion() -> String + var currentDevice: UIDevice { get } #if os(iOS) var orientation: UIDeviceOrientation { get } @@ -96,6 +97,10 @@ import UIKit systemVersion } + @objc public var currentDevice: UIDevice { + UIDevice.current + } + } #endif // swiftlint:enable missing_docs diff --git a/Sources/Swift/Core/Integrations/Integrations.swift b/Sources/Swift/Core/Integrations/Integrations.swift index 62d69046e43..6b410859829 100644 --- a/Sources/Swift/Core/Integrations/Integrations.swift +++ b/Sources/Swift/Core/Integrations/Integrations.swift @@ -52,6 +52,7 @@ private struct AnyIntegration { .init(SentryAutoSessionTrackingIntegration.self), .init(SentryNetworkTrackingIntegration.self), .init(SentryHangTrackerIntegrationObjC.self), + .init(SentryAutoBreadcrumbTrackingIntegration.self), .init(SentryMetricsIntegration.self), .init(SentryFileIOTrackingIntegration.self) ]) diff --git a/Sources/Swift/Integrations/Breadcrumbs/SentryAutoBreadcrumbTrackingIntegration.swift b/Sources/Swift/Integrations/Breadcrumbs/SentryAutoBreadcrumbTrackingIntegration.swift new file mode 100644 index 00000000000..38b953c1701 --- /dev/null +++ b/Sources/Swift/Integrations/Breadcrumbs/SentryAutoBreadcrumbTrackingIntegration.swift @@ -0,0 +1,80 @@ +@_implementationOnly import _SentryPrivate + +#if canImport(UIKit) && !SENTRY_NO_UIKIT +import UIKit +#endif + +#if os(iOS) && !SENTRY_NO_UIKIT +typealias AutoBreadcrumbTrackingIntegrationProvider = SentryUIDeviceWrapperProvider & FileManagerProvider & NotificationCenterProvider +#else +typealias AutoBreadcrumbTrackingIntegrationProvider = FileManagerProvider +#endif + +final class SentryAutoBreadcrumbTrackingIntegration: NSObject, SwiftIntegration, SentryBreadcrumbDelegate { + private var breadcrumbTracker: SentryBreadcrumbTracker? + + #if os(iOS) && !SENTRY_NO_UIKIT + private var systemEventBreadcrumbs: SentrySystemEventBreadcrumbs? + #endif // os(iOS) && !SENTRY_NO_UIKIT + + init?(with options: Options, dependencies: Dependencies) { + guard options.enableAutoBreadcrumbTracking else { + SentrySDKLog.debug("Not going to enable \(Self.name) because enableAutoBreadcrumbTracking is disabled.") + return nil + } + + guard let fileManager = dependencies.fileManager else { + SentrySDKLog.fatal("File manager is not available") + return nil + } + + super.init() + + // Create breadcrumb tracker +#if os(iOS) && !SENTRY_NO_UIKIT + let reportAccessibilityIdentifier = options.reportAccessibilityIdentifier + #else + let reportAccessibilityIdentifier = false +#endif // os(iOS) && !SENTRY_NO_UIKIT + let breadcrumbTracker = SentryBreadcrumbTracker(reportAccessibilityIdentifier: reportAccessibilityIdentifier) + self.breadcrumbTracker = breadcrumbTracker + breadcrumbTracker.start(with: self) + + #if (os(iOS) || os(tvOS) || os(visionOS)) && !SENTRY_NO_UIKIT + if options.enableSwizzling { + breadcrumbTracker.startSwizzle() + } + #endif // (os(iOS) || os(tvOS) || os(visionOS)) && !SENTRY_NO_UIKIT + + #if os(iOS) && !SENTRY_NO_UIKIT + let systemEventBreadcrumbs = SentrySystemEventBreadcrumbs( + currentDeviceProvider: dependencies, + fileManager: fileManager, + notificationCenterWrapper: dependencies.notificationCenterWrapper + ) + self.systemEventBreadcrumbs = systemEventBreadcrumbs + systemEventBreadcrumbs.start(with: self) + #endif // os(iOS) && !SENTRY_NO_UIKIT + } + + func uninstall() { + breadcrumbTracker?.stop() + breadcrumbTracker = nil + + #if os(iOS) && !SENTRY_NO_UIKIT + systemEventBreadcrumbs?.stop() + systemEventBreadcrumbs = nil + #endif // os(iOS) && !SENTRY_NO_UIKIT + } + + static var name: String { + "SentryAutoBreadcrumbTrackingIntegration" + } + + // MARK: - SentryBreadcrumbDelegate + + @objc(addBreadcrumb:) + func add(_ crumb: Breadcrumb) { + SentrySDKInternal.addBreadcrumb(crumb) + } +} diff --git a/Sources/Swift/Integrations/Breadcrumbs/SentryBreadcrumbDelegate.swift b/Sources/Swift/Integrations/Breadcrumbs/SentryBreadcrumbDelegate.swift new file mode 100644 index 00000000000..2789ac0eb29 --- /dev/null +++ b/Sources/Swift/Integrations/Breadcrumbs/SentryBreadcrumbDelegate.swift @@ -0,0 +1,10 @@ +@_implementationOnly import _SentryPrivate + +// swiftlint:disable missing_docs +@objc +@_spi(Private) +public protocol SentryBreadcrumbDelegate: NSObjectProtocol { + @objc(addBreadcrumb:) + func add(_ crumb: Breadcrumb) +} +// swiftlint:enable missing_docs diff --git a/Sources/Swift/Integrations/Breadcrumbs/SentryBreadcrumbTracker.swift b/Sources/Swift/Integrations/Breadcrumbs/SentryBreadcrumbTracker.swift new file mode 100644 index 00000000000..b7002ab028f --- /dev/null +++ b/Sources/Swift/Integrations/Breadcrumbs/SentryBreadcrumbTracker.swift @@ -0,0 +1,299 @@ +// swiftlint:disable missing_docs +@_implementationOnly import _SentryPrivate + +#if (os(iOS) || os(tvOS) || os(visionOS)) && !SENTRY_NO_UIKIT +import UIKit +#endif + +#if (os(macOS) || targetEnvironment(macCatalyst)) && !SENTRY_NO_UIKIT +import Cocoa +#endif + +@objc @_spi(Private) public final class SentryBreadcrumbTracker: NSObject { + + private static let swizzleSendActionKey = "SentryBreadcrumbTrackerSwizzleSendAction" + // Use a static variable to hold a unique pointer for the swizzle key + // Similar to Objective-C's `static const void *key = &key;` pattern + private static var swizzleViewDidAppearKeyStorage: UInt8 = 0 + private static var swizzleViewDidAppearKey: UnsafeRawPointer = { + return withUnsafePointer(to: &swizzleViewDidAppearKeyStorage) { UnsafeRawPointer($0) } + }() + + private weak var delegate: SentryBreadcrumbDelegate? + private let reportAccessibilityIdentifier: Bool + + // Store notification observer tokens for cleanup + private var notificationObservers: [NSObjectProtocol] = [] + + @objc(initReportAccessibilityIdentifier:) + init(reportAccessibilityIdentifier: Bool) { + self.reportAccessibilityIdentifier = reportAccessibilityIdentifier + super.init() + } + + deinit { + SentryDependencyContainer.sharedInstance().reachability.remove(self) + } + + @objc(startWithDelegate:) + func start(with delegate: SentryBreadcrumbDelegate) { + self.delegate = delegate + addEnabledCrumb() + trackApplicationNotifications() + trackNetworkConnectivityChanges() + } + +#if (os(iOS) || os(tvOS) || os(visionOS)) && !SENTRY_NO_UIKIT + @objc + func startSwizzle() { + swizzleSendAction() + swizzleViewDidAppear() + } +#endif // (os(iOS) || os(tvOS) || os(visionOS)) && !SENTRY_NO_UIKIT + + @objc + func stop() { +#if (os(iOS) || os(tvOS) || os(visionOS)) && !SENTRY_NO_UIKIT + SentryDependencyContainer.sharedInstance().swizzleWrapper.removeSwizzleSendAction(forKey: Self.swizzleSendActionKey) +#endif // (os(iOS) || os(tvOS) || os(visionOS)) && !SENTRY_NO_UIKIT + + // Remove all notification observers + let notificationCenter = NotificationCenter.default + for observer in notificationObservers { + notificationCenter.removeObserver(observer) + } + notificationObservers.removeAll() + + delegate = nil + stopTrackNetworkConnectivityChanges() + } + + private func trackApplicationNotifications() { +#if (os(iOS) || os(tvOS) || os(visionOS)) && !SENTRY_NO_UIKIT + trackApplicationNotificationsUIKit() +#elseif os(macOS) + trackApplicationNotificationsMacOS() +#else // watchOS or other platforms + SentrySDKLog.debug("NO UIKit, macOS and Catalyst -> [SentryBreadcrumbTracker trackApplicationNotifications] does nothing.") +#endif + } + +#if (os(iOS) || os(tvOS) || os(visionOS)) && !SENTRY_NO_UIKIT + private func trackApplicationNotificationsUIKit() { + let notificationCenter = NotificationCenter.default + + // not available for macOS + let memoryWarningObserver = notificationCenter.addObserver( + forName: UIApplication.didReceiveMemoryWarningNotification, + object: nil, + queue: nil + ) { [weak self] _ in + guard let self = self else { return } + let crumb = Breadcrumb(level: .warning, category: "device.event") + crumb.type = "system" + crumb.data = ["action": "LOW_MEMORY"] + crumb.message = "Low memory" + self.delegate?.add(crumb) + } + notificationObservers.append(memoryWarningObserver) + + let backgroundObserver = notificationCenter.addObserver( + forName: UIApplication.didEnterBackgroundNotification, + object: nil, + queue: nil + ) { [weak self] _ in + guard let self = self else { return } + self.addBreadcrumb(type: "navigation", category: "app.lifecycle", level: .info, dataKey: "state", dataValue: "background") + } + notificationObservers.append(backgroundObserver) + + let foregroundObserver = notificationCenter.addObserver( + forName: UIApplication.didBecomeActiveNotification, + object: nil, + queue: nil + ) { [weak self] _ in + guard let self = self else { return } + self.addBreadcrumb(type: "navigation", category: "app.lifecycle", level: .info, dataKey: "state", dataValue: "foreground") + } + notificationObservers.append(foregroundObserver) + } +#endif // (os(iOS) || os(tvOS) || os(visionOS)) && !SENTRY_NO_UIKIT + +#if os(macOS) + private func trackApplicationNotificationsMacOS() { + let notificationCenter = NotificationCenter.default + + // Will resign Active notification is the nearest one to + // UIApplicationDidEnterBackgroundNotification + let backgroundObserver = notificationCenter.addObserver( + forName: NSApplication.willResignActiveNotification, + object: nil, + queue: nil + ) { [weak self] _ in + guard let self = self else { return } + self.addBreadcrumb(type: "navigation", category: "app.lifecycle", level: .info, dataKey: "state", dataValue: "background") + } + notificationObservers.append(backgroundObserver) + + let foregroundObserver = notificationCenter.addObserver( + forName: NSApplication.didBecomeActiveNotification, + object: nil, + queue: nil + ) { [weak self] _ in + guard let self = self else { return } + self.addBreadcrumb(type: "navigation", category: "app.lifecycle", level: .info, dataKey: "state", dataValue: "foreground") + } + notificationObservers.append(foregroundObserver) + } +#endif // os(macOS) + + private func trackNetworkConnectivityChanges() { + SentryDependencyContainer.sharedInstance().reachability.add(self) + } + + private func stopTrackNetworkConnectivityChanges() { + SentryDependencyContainer.sharedInstance().reachability.remove(self) + } + + private func addBreadcrumb(type: String, category: String, level: SentryLevel, dataKey: String, dataValue: String) { + let crumb = Breadcrumb(level: level, category: category) + crumb.type = type + crumb.data = [dataKey: dataValue] + delegate?.add(crumb) + } + + private func addEnabledCrumb() { + let crumb = Breadcrumb(level: .info, category: "started") + crumb.type = "debug" + crumb.message = "Breadcrumb Tracking" + delegate?.add(crumb) + } + +#if (os(iOS) || os(tvOS) || os(visionOS)) && !SENTRY_NO_UIKIT + private static func avoidSender(_ sender: Any?, forTarget target: Any?, action: String) -> Bool { + guard let sender = sender, let target = target else { + return true + } + + if let textField = sender as? UITextField { + // This is required to avoid creating breadcrumbs for every key pressed in a text field. + // Textfield may invoke many types of event, in order to check if is a + // `UIControlEventEditingChanged` we need to compare the current action to all events + // attached to the control. This may cause a false negative if the developer is using the + // same action for different events, but this trade off is acceptable because using the same + // action for `.editingChanged` and another event is not supposed to happen. + let actions = textField.actions(forTarget: target, forControlEvent: .editingChanged) + return actions?.contains(action) ?? false + } + return false + } + + private func swizzleSendAction() { + SentryDependencyContainer.sharedInstance().swizzleWrapper.swizzleSendAction( + { [weak self] action, target, sender, event in + guard let self = self else { return } + + if Self.avoidSender(sender, forTarget: target, action: action) { + return + } + + var data: [String: Any]? + if let event = event { + for touch in event.allTouches ?? [] { + if let view = touch.view, + touch.phase == .cancelled || touch.phase == .ended { + data = Self.extractData(from: view, includeAccessibilityIdentifier: self.reportAccessibilityIdentifier) + } + } + } + + let crumb = Breadcrumb(level: .info, category: "touch") + crumb.type = "user" + crumb.message = action + crumb.data = data + self.delegate?.add(crumb) + }, + forKey: Self.swizzleSendActionKey + ) + } + + private func swizzleViewDidAppear() { + SentrySwizzleWrapperHelper.swizzleViewDidAppear( + { [weak self] viewController in + guard let self = self else { return } + + let crumb = Breadcrumb(level: .info, category: "ui.lifecycle") + crumb.type = "navigation" + crumb.data = Self.fetchInfo(about: viewController) + self.delegate?.add(crumb) + }, + forKey: Self.swizzleViewDidAppearKey + ) + } + + @_spi(Private) + public static func extractData(from view: UIView, includeAccessibilityIdentifier: Bool) -> [String: Any] { + var result: [String: Any] = ["view": String(describing: view)] + + if view.tag > 0 { + result["tag"] = view.tag + } + + if includeAccessibilityIdentifier, + let identifier = view.accessibilityIdentifier, + !identifier.isEmpty { + result["accessibilityIdentifier"] = identifier + } + + if let button = view as? UIButton, + let title = button.currentTitle, + !title.isEmpty { + result["title"] = title + } + + return result + } + + private static func fetchInfo(about controller: UIViewController) -> [String: Any] { + var info: [String: Any] = [:] + + info["screen"] = SwiftDescriptor.getViewControllerClassName(controller) + + if let title = controller.navigationItem.title, !title.isEmpty { + info["title"] = controller.navigationItem.title + } else if let title = controller.title, !title.isEmpty { + info["title"] = title + } + + info["beingPresented"] = controller.isBeingPresented ? "true" : "false" + + if let presentingViewController = controller.presentingViewController { + info["presentingViewController"] = SwiftDescriptor.getViewControllerClassName(presentingViewController) + } + + if let parentViewController = controller.parent { + info["parentViewController"] = SwiftDescriptor.getViewControllerClassName(parentViewController) + } + + if let window = controller.view.window { + info["window"] = window.description + info["window_isKeyWindow"] = window.isKeyWindow ? "true" : "false" + info["window_windowLevel"] = String(describing: window.windowLevel.rawValue) + info["is_window_rootViewController"] = (window.rootViewController == controller) ? "true" : "false" + } + + return info + } +#endif // (os(iOS) || os(tvOS) || os(visionOS)) && !SENTRY_NO_UIKIT +} + +extension SentryBreadcrumbTracker: SentryReachabilityObserver { + @objc + public func connectivityChanged(_ connected: Bool, typeDescription: String) { + let crumb = Breadcrumb(level: .info, category: "device.connectivity") + crumb.type = "connectivity" + crumb.data = ["connectivity": typeDescription] + delegate?.add(crumb) + } +} +// swiftlint:enable missing_docs diff --git a/Sources/Swift/Integrations/Breadcrumbs/SentrySystemEventBreadcrumbs.swift b/Sources/Swift/Integrations/Breadcrumbs/SentrySystemEventBreadcrumbs.swift new file mode 100644 index 00000000000..2a3905146a8 --- /dev/null +++ b/Sources/Swift/Integrations/Breadcrumbs/SentrySystemEventBreadcrumbs.swift @@ -0,0 +1,313 @@ +@_implementationOnly import _SentryPrivate + +#if (os(iOS) || os(tvOS) || os(visionOS)) && !SENTRY_NO_UIKIT +import UIKit + +final class SentrySystemEventBreadcrumbs: NSObject { + private weak var delegate: SentryBreadcrumbDelegate? + + private let currentDeviceProvider: SentryUIDeviceWrapperProvider + private let fileManager: SentryFileManager + private let notificationCenterWrapper: SentryNSNotificationCenterWrapper + private let dateProvider: SentryCurrentDateProvider + + #if os(iOS) + // Track whether we enabled these device notifications so we can disable them on stop + private var didEnableBatteryMonitoring = false + private var didBeginGeneratingOrientationNotifications = false + #endif + + init( + currentDeviceProvider: SentryUIDeviceWrapperProvider, + fileManager: SentryFileManager, + notificationCenterWrapper: SentryNSNotificationCenterWrapper, + dateProvider: SentryCurrentDateProvider = SentryDependencyContainer.sharedInstance().dateProvider + ) { + self.currentDeviceProvider = currentDeviceProvider + self.fileManager = fileManager + self.notificationCenterWrapper = notificationCenterWrapper + self.dateProvider = dateProvider + super.init() + } + + deinit { + // In dealloc it's safe to unsubscribe for all, see + // https://developer.apple.com/documentation/foundation/nsnotificationcenter/1413994-removeobserver + notificationCenterWrapper.removeObserver(self, name: nil, object: nil) + } + + func start(with delegate: SentryBreadcrumbDelegate) { + self.delegate = delegate + #if os(iOS) + initBatteryObserver(currentDeviceProvider.uiDeviceWrapper.currentDevice) + initOrientationObserver(currentDeviceProvider.uiDeviceWrapper.currentDevice) + initKeyboardVisibilityObserver() + #endif + initScreenshotObserver() + initTimezoneObserver() + initSignificantTimeChangeObserver() + } + + func timezoneEventTriggered() { + timezoneEventTriggered(storedTimezoneOffset: nil) + } + + func stop() { + // Remove the observers with the most specific detail possible, see + // https://developer.apple.com/documentation/foundation/nsnotificationcenter/1413994-removeobserver + + notificationCenterWrapper.removeObserver(self, name: UIApplication.userDidTakeScreenshotNotification, object: nil) + notificationCenterWrapper.removeObserver(self, name: UIApplication.significantTimeChangeNotification, object: nil) + notificationCenterWrapper.removeObserver(self, name: NSNotification.Name.NSSystemTimeZoneDidChange, object: nil) + #if os(iOS) + notificationCenterWrapper.removeObserver(self, name: UIDevice.batteryLevelDidChangeNotification, object: nil) + notificationCenterWrapper.removeObserver(self, name: UIDevice.batteryStateDidChangeNotification, object: nil) + notificationCenterWrapper.removeObserver(self, name: UIResponder.keyboardDidShowNotification, object: nil) + notificationCenterWrapper.removeObserver(self, name: UIResponder.keyboardDidHideNotification, object: nil) + notificationCenterWrapper.removeObserver(self, name: UIDevice.orientationDidChangeNotification, object: nil) + + // Disable device notifications that we enabled + let currentDevice = currentDeviceProvider.uiDeviceWrapper.currentDevice + if didEnableBatteryMonitoring { + currentDevice.isBatteryMonitoringEnabled = false + didEnableBatteryMonitoring = false + } + if didBeginGeneratingOrientationNotifications { + currentDevice.endGeneratingDeviceOrientationNotifications() + didBeginGeneratingOrientationNotifications = false + } + #endif + } + + // MARK: - Battery Observer + + #if os(iOS) + private func initBatteryObserver(_ currentDevice: UIDevice) { + if !currentDevice.isBatteryMonitoringEnabled { + currentDevice.isBatteryMonitoringEnabled = true + didEnableBatteryMonitoring = true + } + + // Posted when the battery level changes. + notificationCenterWrapper.addObserver( + self, + selector: #selector(batteryStateChanged(_:)), + name: UIDevice.batteryLevelDidChangeNotification, + object: currentDevice + ) + + // Posted when battery state changes. + notificationCenterWrapper.addObserver( + self, + selector: #selector(batteryStateChanged(_:)), + name: UIDevice.batteryStateDidChangeNotification, + object: currentDevice + ) + } + + @objc private func batteryStateChanged(_ notification: Notification) { + // Notifications for battery level change are sent no more frequently than once per minute + guard let currentDevice = notification.object as? UIDevice else { + SentrySDKLog.debug("UIDevice of NSNotification was nil. Won't create battery changed breadcrumb.") + return + } + + let batteryData = getBatteryStatus(currentDevice) + + let crumb = Breadcrumb(level: .info, category: "device.event") + crumb.type = "system" + crumb.data = batteryData + delegate?.add(crumb) + } + + private func getBatteryStatus(_ currentDevice: UIDevice) -> [String: Any] { + // borrowed and adapted from + // https://github.com/apache/cordova-plugin-battery-status/blob/master/src/ios/CDVBattery.m + let currentState = currentDevice.batteryState + + var isPlugged = false // UIDeviceBatteryStateUnknown or UIDeviceBatteryStateUnplugged + if currentState == .charging || currentState == .full { + isPlugged = true + } + let currentLevel = currentDevice.batteryLevel + var batteryData: [String: Any] = [:] + + // W3C spec says level must be null if it is unknown + if currentState != .unknown && currentLevel != -1.0 { + let w3cLevel = currentLevel * 100 + batteryData["level"] = NSNumber(value: w3cLevel) + } else { + SentrySDKLog.debug("batteryLevel is unknown.") + } + + batteryData["plugged"] = isPlugged + batteryData["action"] = "BATTERY_STATE_CHANGE" + + return batteryData + } + + // MARK: - Orientation Observer + + private func initOrientationObserver(_ currentDevice: UIDevice) { + if !currentDevice.isGeneratingDeviceOrientationNotifications { + currentDevice.beginGeneratingDeviceOrientationNotifications() + didBeginGeneratingOrientationNotifications = true + } + + // Posted when the orientation of the device changes. + notificationCenterWrapper.addObserver( + self, + selector: #selector(orientationChanged(_:)), + name: UIDevice.orientationDidChangeNotification, + object: currentDevice + ) + } + + @objc private func orientationChanged(_ notification: Notification) { + guard let currentDevice = notification.object as? UIDevice else { + return + } + + let crumb = Breadcrumb(level: .info, category: "device.orientation") + let currentOrientation = currentDevice.orientation + + // Ignore changes in device orientation if unknown, face up, or face down. + if !currentOrientation.isValidInterfaceOrientation { + SentrySDKLog.debug("currentOrientation is unknown.") + return + } + + if currentOrientation.isLandscape { + crumb.data = ["position": "landscape"] + } else { + crumb.data = ["position": "portrait"] + } + crumb.type = "navigation" + delegate?.add(crumb) + } + + // MARK: - Keyboard Visibility Observer + + private func initKeyboardVisibilityObserver() { + // Posted immediately after the display of the keyboard. + notificationCenterWrapper.addObserver( + self, + selector: #selector(systemEventTriggered(_:)), + name: UIResponder.keyboardDidShowNotification, + object: nil + ) + + // Posted immediately after the dismissal of the keyboard. + notificationCenterWrapper.addObserver( + self, + selector: #selector(systemEventTriggered(_:)), + name: UIResponder.keyboardDidHideNotification, + object: nil + ) + } + #endif + + @objc private func systemEventTriggered(_ notification: Notification) { + let crumb = Breadcrumb(level: .info, category: "device.event") + crumb.type = "system" + crumb.data = ["action": notification.name.rawValue] + delegate?.add(crumb) + } + + // MARK: - Screenshot Observer + + private func initScreenshotObserver() { + // it's only about the action, but not the SS itself + notificationCenterWrapper.addObserver( + self, + selector: #selector(systemEventTriggered(_:)), + name: UIApplication.userDidTakeScreenshotNotification, + object: nil + ) + } + + // MARK: - Timezone Observer + + private func initTimezoneObserver() { + // Detect if the stored timezone is different from the current one; + // if so, then we also send a breadcrumb + let storedTimezoneOffset = fileManager.readTimezoneOffset() + + if storedTimezoneOffset == nil { + updateStoredTimezone() + } else if let storedOffset = storedTimezoneOffset?.intValue, + storedOffset != dateProvider.timezoneOffset() { + timezoneEventTriggered(storedTimezoneOffset: storedTimezoneOffset) + } + + // Posted when the timezone of the device changed + notificationCenterWrapper.addObserver( + self, + selector: #selector(timezoneEventTriggeredNotification), + name: NSNotification.Name.NSSystemTimeZoneDidChange, + object: nil + ) + } + + @objc private func timezoneEventTriggeredNotification() { + timezoneEventTriggered(storedTimezoneOffset: nil) + } + + private func timezoneEventTriggered(storedTimezoneOffset: NSNumber?) { + let storedOffset = storedTimezoneOffset ?? fileManager.readTimezoneOffset() + + let crumb = Breadcrumb(level: .info, category: "device.event") + let offset = dateProvider.timezoneOffset() + + crumb.type = "system" + + var dataDict: [String: Any] = [ + "action": "TIMEZONE_CHANGE", + "current_seconds_from_gmt": Int64(offset) + ] + + if let storedOffset = storedOffset { + dataDict["previous_seconds_from_gmt"] = storedOffset + } + + crumb.data = dataDict + delegate?.add(crumb) + + updateStoredTimezone() + } + + private func updateStoredTimezone() { + fileManager.storeTimezoneOffset(dateProvider.timezoneOffset()) + } + + // MARK: - Significant Time Change Observer + + private func initSignificantTimeChangeObserver() { + notificationCenterWrapper.addObserver( + self, + selector: #selector(significantTimeChangeTriggered(_:)), + name: UIApplication.significantTimeChangeNotification, + object: nil + ) + } + + /** + * The system posts this notification when, for example, there's a change to a new day (midnight), a + * carrier time update, or a change to, or from, daylight savings time. The notification doesn't + * contain a user info dictionary. + * + * @see + * https://developer.apple.com/documentation/uikit/uiapplication/significanttimechangenotification#Discussion + */ + @objc private func significantTimeChangeTriggered(_ notification: Notification) { + let crumb = Breadcrumb(level: .info, category: "device.event") + crumb.type = "system" + + // We don't add the timezone here, because we already add it in timezoneEventTriggered. + crumb.data = ["action": "SIGNIFICANT_TIME_CHANGE"] + + delegate?.add(crumb) + } +} + +#endif // (os(iOS) || os(tvOS) || os(visionOS)) && !SENTRY_NO_UIKIT diff --git a/Sources/Swift/SentryDependencyContainer.swift b/Sources/Swift/SentryDependencyContainer.swift index 25f95400493..d7844b8a253 100644 --- a/Sources/Swift/SentryDependencyContainer.swift +++ b/Sources/Swift/SentryDependencyContainer.swift @@ -507,10 +507,16 @@ protocol CrashInstallationReporterBuilder { extension SentryDependencyContainer: CrashInstallationReporterBuilder {} #if (os(iOS) || os(tvOS) || os(visionOS)) && !SENTRY_NO_UIKIT +protocol SentryUIDeviceWrapperProvider { + var uiDeviceWrapper: SentryUIDeviceWrapper { get } +} + +extension SentryDependencyContainer: SentryUIDeviceWrapperProvider {} + protocol SentryEventTrackerBuilder { func getUIEventTracker(_ options: Options) -> SentryUIEventTracker } extension SentryDependencyContainer: SentryEventTrackerBuilder {} -#endif +#endif // (os(iOS) || os(tvOS) || os(visionOS)) && !SENTRY_NO_UIKIT //swiftlint:enable file_length missing_docs diff --git a/Tests/SentryTests/Integrations/Breadcrumbs/SentryAutoBreadcrumbTrackingIntegration+Test.h b/Tests/SentryTests/Integrations/Breadcrumbs/SentryAutoBreadcrumbTrackingIntegration+Test.h deleted file mode 100644 index 2278d4455b2..00000000000 --- a/Tests/SentryTests/Integrations/Breadcrumbs/SentryAutoBreadcrumbTrackingIntegration+Test.h +++ /dev/null @@ -1,20 +0,0 @@ -#import "SentryAutoBreadcrumbTrackingIntegration.h" - -NS_ASSUME_NONNULL_BEGIN - -@class SentryBreadcrumbTracker; -@class SentryOptions; -@class SentrySystemEventBreadcrumbs; - -@interface SentryAutoBreadcrumbTrackingIntegration (Test) - -- (void)installWithOptions:(nonnull SentryOptions *)options - breadcrumbTracker:(SentryBreadcrumbTracker *)breadcrumbTracker -#if TARGET_OS_IOS && SENTRY_HAS_UIKIT - systemEventBreadcrumbs:(SentrySystemEventBreadcrumbs *)systemEventBreadcrumbs -#endif // TARGET_OS_IOS && SENTRY_HAS_UIKIT - ; - -@end - -NS_ASSUME_NONNULL_END diff --git a/Tests/SentryTests/Integrations/Breadcrumbs/SentryAutoBreadcrumbTrackingIntegrationTests.swift b/Tests/SentryTests/Integrations/Breadcrumbs/SentryAutoBreadcrumbTrackingIntegrationTests.swift deleted file mode 100644 index bf313ef802d..00000000000 --- a/Tests/SentryTests/Integrations/Breadcrumbs/SentryAutoBreadcrumbTrackingIntegrationTests.swift +++ /dev/null @@ -1,146 +0,0 @@ -@testable import Sentry -@_spi(Private) import SentryTestUtils -import XCTest - -class SentryAutoBreadcrumbTrackingIntegrationTests: XCTestCase { - - private class Fixture { - private let dateProvider = TestCurrentDateProvider() - private let dispatchQueueWrapper = TestSentryDispatchQueueWrapper() - - let fileManager: TestFileManager - - let breadcrumbTracker = SentryTestBreadcrumbTracker() - -#if os(iOS) - var systemEventBreadcrumbTracker: SentryTestSystemEventBreadcrumbs? -#endif // os(iOS) - - init() throws { - let options = Options() - options.dsn = TestConstants.dsnForTestCase(type: SentryAutoBreadcrumbTrackingIntegrationTests.self) - - fileManager = try TestFileManager( - options: options, - dateProvider: dateProvider, - dispatchQueueWrapper: dispatchQueueWrapper - ) - } - - var sut: SentryAutoBreadcrumbTrackingIntegration { - return SentryAutoBreadcrumbTrackingIntegration() - } - } - - private var fixture: Fixture! - - override func setUpWithError() throws { - try super.setUpWithError() - fixture = try Fixture() - } - - override func tearDown() { - super.tearDown() - clearTestState() - } - -#if os(iOS) - func testInstallWithSwizzleEnabled_StartSwizzleCalled() throws { - let sut = fixture.sut - - try self.install(sut: sut) - - XCTAssertEqual(1, fixture.breadcrumbTracker.startInvocations.count) - XCTAssertEqual(1, fixture.breadcrumbTracker.startSwizzleInvocations.count) - } - - func testInstallWithSwizzleDisabled_StartSwizzleNotCalled() throws { - let sut = fixture.sut - - let options = Options() - options.enableSwizzling = false - - try self.install(sut: sut, options: options) - - XCTAssertEqual(1, fixture.breadcrumbTracker.startInvocations.count) - XCTAssertEqual(0, fixture.breadcrumbTracker.startSwizzleInvocations.count) - } -#endif // os(iOS) - - func test_enableAutoBreadcrumbTracking_Disabled() { - let options = Options() - options.enableAutoBreadcrumbTracking = false - - let sut = SentryAutoBreadcrumbTrackingIntegration() - let result = sut.install(with: options) - - XCTAssertFalse(result) - } - -#if os(iOS) - func testInstall() throws { - let options = Options() - - let sut = SentryAutoBreadcrumbTrackingIntegration() - try self.install(sut: sut, options: options) - - let scope = Scope() - let hub = SentryHubInternal(client: TestClient(options: Options()), andScope: scope) - SentrySDKInternal.setCurrentHub(hub) - - let crumb = TestData.crumb - fixture.systemEventBreadcrumbTracker?.startWithDelegateInvocations.first?.add(crumb) - - let serializedScope = scope.serialize() - - XCTAssertNotNil(serializedScope["breadcrumbs"] as? [[String: Any]], "no scope.breadcrumbs") - - if let breadcrumbs = serializedScope["breadcrumbs"] as? [[String: Any]] { - XCTAssertNotNil(breadcrumbs.first, "scope.breadcrumbs is empty") - if let actualCrumb = breadcrumbs.first { - XCTAssertEqual(crumb.category, actualCrumb["category"] as? String) - XCTAssertEqual(crumb.type, actualCrumb["type"] as? String) - } - } - } -#endif // os(iOS) - - private func install(sut: SentryAutoBreadcrumbTrackingIntegration, options: Options = Options()) throws { - -#if os(iOS) - fixture.systemEventBreadcrumbTracker = SentryTestSystemEventBreadcrumbs(fileManager: fixture.fileManager, andNotificationCenterWrapper: TestNSNotificationCenterWrapper()) - sut.install(with: options, breadcrumbTracker: fixture.breadcrumbTracker, systemEventBreadcrumbs: fixture.systemEventBreadcrumbTracker!) -#else - sut.install(with: options, breadcrumbTracker: fixture.breadcrumbTracker) -#endif // os(iOS) - - } -} - -private class SentryTestBreadcrumbTracker: SentryBreadcrumbTracker { - - let startInvocations = Invocations() - override func start(with delegate: SentryBreadcrumbDelegate) { - startInvocations.record(delegate) - } - -#if os(iOS) - let startSwizzleInvocations = Invocations() - override func startSwizzle() { - startSwizzleInvocations.record(Void()) - } -#endif // os(iOS) - -} - -#if os(iOS) - -private class SentryTestSystemEventBreadcrumbs: SentrySystemEventBreadcrumbs { - - let startWithDelegateInvocations = Invocations() - override func start(with delegate: SentryBreadcrumbDelegate) { - startWithDelegateInvocations.record(delegate) - } -} - -#endif // os(iOS) diff --git a/Tests/SentryTests/Integrations/Breadcrumbs/SentryBreadcrumbTestDelegate.swift b/Tests/SentryTests/Integrations/Breadcrumbs/SentryBreadcrumbTestDelegate.swift index 9713ebc0cb4..eb6e42c1c74 100644 --- a/Tests/SentryTests/Integrations/Breadcrumbs/SentryBreadcrumbTestDelegate.swift +++ b/Tests/SentryTests/Integrations/Breadcrumbs/SentryBreadcrumbTestDelegate.swift @@ -1,4 +1,4 @@ -import Foundation +@_spi(Private) import Sentry import SentryTestUtils class SentryBreadcrumbTestDelegate: NSObject, SentryBreadcrumbDelegate { diff --git a/Tests/SentryTests/Integrations/Breadcrumbs/SentryBreadcrumbTrackerTests.swift b/Tests/SentryTests/Integrations/Breadcrumbs/SentryBreadcrumbTrackerTests.swift index 57bd1eacd1b..ddd423c8fcf 100644 --- a/Tests/SentryTests/Integrations/Breadcrumbs/SentryBreadcrumbTrackerTests.swift +++ b/Tests/SentryTests/Integrations/Breadcrumbs/SentryBreadcrumbTrackerTests.swift @@ -2,12 +2,6 @@ import SentryTestUtils import XCTest -extension SentryBreadcrumbTracker { - override convenience init() { - self.init(reportAccessibilityIdentifier: true) - } -} - class SentryBreadcrumbTrackerTests: XCTestCase { private var delegate: SentryBreadcrumbTestDelegate! @@ -26,8 +20,8 @@ class SentryBreadcrumbTrackerTests: XCTestCase { #if os(iOS) || os(tvOS) || targetEnvironment(macCatalyst) func testStopRemovesSwizzleSendAction() { - let sut = SentryBreadcrumbTracker() - + let sut = SentryBreadcrumbTracker(reportAccessibilityIdentifier: true) + sut.start(with: delegate) sut.startSwizzle() sut.stop() @@ -40,7 +34,7 @@ class SentryBreadcrumbTrackerTests: XCTestCase { SentryDependencyContainer.sharedInstance().reachability = testReachability - let sut = SentryBreadcrumbTracker() + let sut = SentryBreadcrumbTracker(reportAccessibilityIdentifier: true) sut.start(with: delegate) let states: [SentryConnectivity] = [.cellular, .wiFi, @@ -65,7 +59,7 @@ class SentryBreadcrumbTrackerTests: XCTestCase { func testNetworkConnectivityBreadcrumbForSessionReplay() throws { let testReachability = TestSentryReachability() SentryDependencyContainer.sharedInstance().reachability = testReachability - let sut = SentryBreadcrumbTracker() + let sut = SentryBreadcrumbTracker(reportAccessibilityIdentifier: true) sut.start(with: delegate) testReachability.setReachabilityState(state: .cellular) sut.stop() @@ -101,7 +95,7 @@ class SentryBreadcrumbTrackerTests: XCTestCase { let hub = TestHub(client: client, andScope: scope) SentrySDKInternal.setCurrentHub(hub) - let sut = SentryBreadcrumbTracker() + let sut = SentryBreadcrumbTracker(reportAccessibilityIdentifier: true) sut.start(with: delegate) sut.startSwizzle() @@ -168,7 +162,7 @@ class SentryBreadcrumbTrackerTests: XCTestCase { let hub = TestHub(client: client, andScope: scope) SentrySDKInternal.setCurrentHub(hub) - let tracker = SentryBreadcrumbTracker() + let tracker = SentryBreadcrumbTracker(reportAccessibilityIdentifier: true) tracker.start(with: delegate) NotificationCenter.default.post(name: UIApplication.didEnterBackgroundNotification, object: nil) @@ -193,7 +187,7 @@ class SentryBreadcrumbTrackerTests: XCTestCase { let swizzlingWrapper = TestSentrySwizzleWrapper() SentryDependencyContainer.sharedInstance().swizzleWrapper = swizzlingWrapper - let tracker = SentryBreadcrumbTracker() + let tracker = SentryBreadcrumbTracker(reportAccessibilityIdentifier: true) tracker.start(with: delegate) tracker.startSwizzle() @@ -215,7 +209,7 @@ class SentryBreadcrumbTrackerTests: XCTestCase { let swizzlingWrapper = TestSentrySwizzleWrapper() SentryDependencyContainer.sharedInstance().swizzleWrapper = swizzlingWrapper - let tracker = SentryBreadcrumbTracker() + let tracker = SentryBreadcrumbTracker(reportAccessibilityIdentifier: true) tracker.start(with: delegate) tracker.startSwizzle() @@ -296,7 +290,7 @@ class SentryBreadcrumbTrackerTests: XCTestCase { let hub = TestHub(client: client, andScope: scope) SentrySDKInternal.setCurrentHub(hub) - let sut = SentryBreadcrumbTracker() + let sut = SentryBreadcrumbTracker(reportAccessibilityIdentifier: true) sut.start(with: delegate) sut.startSwizzle() diff --git a/Tests/SentryTests/Integrations/Breadcrumbs/SentryBreadcrumbTrackingIntegrationTests.swift b/Tests/SentryTests/Integrations/Breadcrumbs/SentryBreadcrumbTrackingIntegrationTests.swift new file mode 100644 index 00000000000..1950f5aba36 --- /dev/null +++ b/Tests/SentryTests/Integrations/Breadcrumbs/SentryBreadcrumbTrackingIntegrationTests.swift @@ -0,0 +1,91 @@ +@_spi(Private) import _SentryPrivate +@_spi(Private) @testable import Sentry +@_spi(Private) import SentryTestUtils +import XCTest + +class SentryBreadcrumbTrackingIntegrationTests: XCTestCase { + + private class Fixture { + private let dateProvider = TestCurrentDateProvider() + private let dispatchQueueWrapper = TestSentryDispatchQueueWrapper() + + let fileManager: TestFileManager + let notificationCenterWrapper = TestNSNotificationCenterWrapper() + let defaultOptions: Options + + init() throws { + let options = Options() + options.dsn = TestConstants.dsnForTestCase(type: SentryBreadcrumbTrackingIntegrationTests.self) + options.enableAutoBreadcrumbTracking = true + defaultOptions = options + + fileManager = try TestFileManager( + options: options, + dateProvider: dateProvider, + dispatchQueueWrapper: dispatchQueueWrapper + ) + } + + func getSut(options: Options? = nil) throws -> SentryAutoBreadcrumbTrackingIntegration { + let container = SentryDependencyContainer.sharedInstance() + container.fileManager = fileManager + container.notificationCenterWrapper = notificationCenterWrapper + + return try XCTUnwrap(SentryAutoBreadcrumbTrackingIntegration( + with: options ?? defaultOptions, + dependencies: container + )) + } + } + + private var fixture: Fixture! + + override func setUpWithError() throws { + try super.setUpWithError() + fixture = try Fixture() + } + + override func tearDown() { + super.tearDown() + clearTestState() + } + + func test_enableAutoBreadcrumbTracking_Disabled() { + let options = Options() + options.enableAutoBreadcrumbTracking = false + + let container = SentryDependencyContainer.sharedInstance() + container.fileManager = fixture.fileManager + container.notificationCenterWrapper = fixture.notificationCenterWrapper + + let sut = SentryAutoBreadcrumbTrackingIntegration(with: options, dependencies: container) + + XCTAssertNil(sut, "Integration should return nil when enableAutoBreadcrumbTracking is disabled") + } + + func testInstall() throws { + let sut = try fixture.getSut() + defer { + sut.uninstall() + } + + let scope = Scope() + let hub = SentryHubInternal(client: TestClient(options: Options()), andScope: scope) + SentrySDKInternal.setCurrentHub(hub) + + let crumb = TestData.crumb + SentrySDKInternal.addBreadcrumb(crumb) + + let serializedScope = scope.serialize() + + XCTAssertNotNil(serializedScope["breadcrumbs"] as? [[String: Any]], "no scope.breadcrumbs") + + if let breadcrumbs = serializedScope["breadcrumbs"] as? [[String: Any]] { + XCTAssertNotNil(breadcrumbs.first, "scope.breadcrumbs is empty") + if let actualCrumb = breadcrumbs.first { + XCTAssertEqual(crumb.category, actualCrumb["category"] as? String) + XCTAssertEqual(crumb.type, actualCrumb["type"] as? String) + } + } + } +} diff --git a/Tests/SentryTests/Integrations/Breadcrumbs/SentrySystemEventBreadcrumbsTest.swift b/Tests/SentryTests/Integrations/Breadcrumbs/SentrySystemEventBreadcrumbsTest.swift index 0c9125619dc..0c0aa09a533 100644 --- a/Tests/SentryTests/Integrations/Breadcrumbs/SentrySystemEventBreadcrumbsTest.swift +++ b/Tests/SentryTests/Integrations/Breadcrumbs/SentrySystemEventBreadcrumbsTest.swift @@ -7,6 +7,14 @@ class SentrySystemEventBreadcrumbsTest: XCTestCase { // This feature only works on iOS #if os(iOS) + private class TestUIDeviceWrapperProvider: SentryUIDeviceWrapperProvider { + let uiDeviceWrapper: SentryUIDeviceWrapper + + init(uiDeviceWrapper: SentryUIDeviceWrapper) { + self.uiDeviceWrapper = uiDeviceWrapper + } + } + private class Fixture { let options: Options let delegate = SentryBreadcrumbTestDelegate() @@ -30,11 +38,18 @@ class SentrySystemEventBreadcrumbsTest: XCTestCase { } func getSut(currentDevice: UIDevice? = UIDevice.current) -> SentrySystemEventBreadcrumbs { + let deviceWrapper = TestSentryUIDeviceWrapper() + if let customDevice = currentDevice { + deviceWrapper.internalCurrentDevice = customDevice + } + let provider = TestUIDeviceWrapperProvider(uiDeviceWrapper: deviceWrapper) + let systemEvents = SentrySystemEventBreadcrumbs( + currentDeviceProvider: provider, fileManager: fileManager, - andNotificationCenterWrapper: notificationCenterWrapper + notificationCenterWrapper: notificationCenterWrapper ) - systemEvents.start(with: self.delegate, currentDevice: currentDevice) + systemEvents.start(with: self.delegate) return systemEvents } @@ -358,7 +373,7 @@ class SentrySystemEventBreadcrumbsTest: XCTestCase { func testStopCallsSpecificRemoveObserverMethods() { sut = fixture.getSut(currentDevice: nil) sut.stop() - XCTAssertEqual(fixture.notificationCenterWrapper.removeObserverWithNameAndObjectInvocations.count, 7) + XCTAssertEqual(fixture.notificationCenterWrapper.removeObserverWithNameAndObjectInvocations.count, 8) } private func postBatteryLevelNotification(uiDevice: UIDevice?) { diff --git a/Tests/SentryTests/Protocol/TestData.swift b/Tests/SentryTests/Protocol/TestData.swift index 8ed89c69933..1e329c39e3c 100644 --- a/Tests/SentryTests/Protocol/TestData.swift +++ b/Tests/SentryTests/Protocol/TestData.swift @@ -43,7 +43,7 @@ class TestData { event.logger = "logger" event.message = SentryMessage(formatted: "message") event.modules = ["module": "1"] - event.platform = SentryPlatformName + event.platform = "cocoa" event.releaseName = SentryMeta.versionString event.sdk = sdk event.serverName = "serverName" diff --git a/Tests/SentryTests/SentryCrash/SentryDebugImageProviderTests.swift b/Tests/SentryTests/SentryCrash/SentryDebugImageProviderTests.swift index d72772adf11..7b1f0d6df9c 100644 --- a/Tests/SentryTests/SentryCrash/SentryDebugImageProviderTests.swift +++ b/Tests/SentryTests/SentryCrash/SentryDebugImageProviderTests.swift @@ -97,7 +97,7 @@ class SentryDebugImageProviderTests: XCTestCase { let image1 = try XCTUnwrap(actual.first) XCTAssertEqual(image1.debugID, "84BAEBDA-AD1A-33F4-B35D-8A45F5DAF322") - XCTAssertEqual(image1.type, SentryDebugImageType) + XCTAssertEqual(image1.type, "macho") XCTAssertEqual(image1.imageVmAddress, "0x0000daf262294000") XCTAssertEqual(image1.imageAddress, "0x00000001410b1a00") XCTAssertEqual(image1.imageSize, 1_352_256) @@ -106,7 +106,7 @@ class SentryDebugImageProviderTests: XCTestCase { let image2 = try XCTUnwrap(actual.last) XCTAssertEqual(image2.debugID, "84BAEBDA-AD1A-33F4-B35D-8A45F5DAF322") - XCTAssertEqual(image2.type, SentryDebugImageType) + XCTAssertEqual(image2.type, "macho") XCTAssertEqual(image2.imageVmAddress, "0x00007fff51af0000") XCTAssertEqual(image2.imageAddress, "0x0000000105705000") XCTAssertEqual(image2.imageSize, 352_256) @@ -128,7 +128,7 @@ class SentryDebugImageProviderTests: XCTestCase { let image1 = try XCTUnwrap(actual.first) XCTAssertEqual(image1.debugID, "84BAEBDA-AD1A-33F4-B35D-8A45F5DAF322") - XCTAssertEqual(image1.type, SentryDebugImageType) + XCTAssertEqual(image1.type, "macho") XCTAssertEqual(image1.imageVmAddress, "0x0000daf262294000") XCTAssertEqual(image1.imageAddress, "0x00000001410b1a00") XCTAssertEqual(image1.imageSize, 1_352_256) @@ -137,7 +137,7 @@ class SentryDebugImageProviderTests: XCTestCase { let image2 = try XCTUnwrap(actual.last) XCTAssertEqual(image2.debugID, "84BAEBDA-AD1A-33F4-B35D-8A45F5DAF322") - XCTAssertEqual(image2.type, SentryDebugImageType) + XCTAssertEqual(image2.type, "macho") XCTAssertEqual(image2.imageVmAddress, "0x00007fff51af0000") XCTAssertEqual(image2.imageAddress, "0x0000000105705000") XCTAssertEqual(image2.imageSize, 352_256) @@ -158,7 +158,7 @@ class SentryDebugImageProviderTests: XCTestCase { XCTAssertEqual(actual.count, 1) let image = try XCTUnwrap(actual.first) XCTAssertEqual(image.debugID, "84BAEBDA-AD1A-33F4-B35D-8A45F5DAF322") - XCTAssertEqual(image.type, SentryDebugImageType) + XCTAssertEqual(image.type, "macho") XCTAssertEqual(image.imageVmAddress, "0x00007fff51af0000") XCTAssertEqual(image.imageAddress, "0x0000000105705000") XCTAssertEqual(image.imageSize, 352_256) @@ -184,7 +184,7 @@ class SentryDebugImageProviderTests: XCTestCase { let image = try XCTUnwrap(actual.first) XCTAssertEqual(image.debugID, "84BAEBDA-AD1A-33F4-B35D-8A45F5DAF322") - XCTAssertEqual(image.type, SentryDebugImageType) + XCTAssertEqual(image.type, "macho") XCTAssertEqual(image.imageVmAddress, "0x0000daf262294000") XCTAssertEqual(image.imageAddress, "0x00000001410b1a00") XCTAssertEqual(image.imageSize, 1_352_256) @@ -219,7 +219,7 @@ class SentryDebugImageProviderTests: XCTestCase { let coreDataImage = try XCTUnwrap(actual.first { $0.codeFile == "CoreData" }) XCTAssertEqual(coreDataImage.debugID, "84BAEBDA-AD1A-33F4-B35D-8A45F5DAF322") - XCTAssertEqual(coreDataImage.type, SentryDebugImageType) + XCTAssertEqual(coreDataImage.type, "macho") XCTAssertEqual(coreDataImage.imageVmAddress, "0x000135e572a38000") XCTAssertEqual(coreDataImage.imageAddress, "0x000000017ca5e400") XCTAssertEqual(coreDataImage.imageSize, 900_256) @@ -228,7 +228,7 @@ class SentryDebugImageProviderTests: XCTestCase { let uiKitImage = try XCTUnwrap(actual.first { $0.codeFile == "UIKit" }) XCTAssertEqual(uiKitImage.debugID, "84BAEBDA-AD1A-33F4-B35D-8A45F5DAF322") - XCTAssertEqual(uiKitImage.type, SentryDebugImageType) + XCTAssertEqual(uiKitImage.type, "macho") XCTAssertEqual(uiKitImage.imageVmAddress, "0x0000daf262294000") XCTAssertEqual(uiKitImage.imageAddress, "0x00000001410b1a00") XCTAssertEqual(uiKitImage.imageSize, 1_352_256) @@ -237,7 +237,7 @@ class SentryDebugImageProviderTests: XCTestCase { let dyldImage = try XCTUnwrap(actual.first { $0.codeFile == "dyld_sim" }) XCTAssertEqual(dyldImage.debugID, "84BAEBDA-AD1A-33F4-B35D-8A45F5DAF322") - XCTAssertEqual(dyldImage.type, SentryDebugImageType) + XCTAssertEqual(dyldImage.type, "macho") XCTAssertEqual(dyldImage.imageVmAddress, "0x00007fff51af0000") XCTAssertEqual(dyldImage.imageAddress, "0x0000000105705000") XCTAssertEqual(dyldImage.imageSize, 352_256) diff --git a/Tests/SentryTests/SentryCrash/SentryUIDeviceWrapperTests.swift b/Tests/SentryTests/SentryCrash/SentryUIDeviceWrapperTests.swift index fdb841ecc2e..ba4886698fe 100644 --- a/Tests/SentryTests/SentryCrash/SentryUIDeviceWrapperTests.swift +++ b/Tests/SentryTests/SentryCrash/SentryUIDeviceWrapperTests.swift @@ -46,5 +46,11 @@ class SentryUIDeviceWrapperTests: XCTestCase { } XCTAssertEqual(dispatchQueue.blockOnMainInvocations.count, 2) } + + func testCurrentDevice() { + let dispatchQueue = TestSentryDispatchQueueWrapper() + let sut = SentryDefaultUIDeviceWrapper(queueWrapper: dispatchQueue) + XCTAssertEqual(sut.currentDevice, UIDevice.current) + } } #endif diff --git a/Tests/SentryTests/SentryCrash/TestSentryUIDeviceWrapper.swift b/Tests/SentryTests/SentryCrash/TestSentryUIDeviceWrapper.swift index 42ba50b0f76..e070452ea33 100644 --- a/Tests/SentryTests/SentryCrash/TestSentryUIDeviceWrapper.swift +++ b/Tests/SentryTests/SentryCrash/TestSentryUIDeviceWrapper.swift @@ -8,6 +8,7 @@ class TestSentryUIDeviceWrapper: SentryUIDeviceWrapper { var internalBatteryLevel: Float = 0.6 var internalBatteryState = UIDevice.BatteryState.charging var started = false + var internalCurrentDevice = UIDevice.current func start() { started = true @@ -16,6 +17,10 @@ class TestSentryUIDeviceWrapper: SentryUIDeviceWrapper { started = false } + var currentDevice: UIDevice { + return internalCurrentDevice + } + var orientation: UIDeviceOrientation { return internalOrientation } diff --git a/Tests/SentryTests/SentryTests-Bridging-Header.h b/Tests/SentryTests/SentryTests-Bridging-Header.h index be4638caf07..8c9f7086fe8 100644 --- a/Tests/SentryTests/SentryTests-Bridging-Header.h +++ b/Tests/SentryTests/SentryTests-Bridging-Header.h @@ -41,12 +41,8 @@ #import "SentryAppStartTrackingIntegration.h" #import "SentryArray.h" #import "SentryAttachment+Private.h" -#import "SentryAutoBreadcrumbTrackingIntegration+Test.h" -#import "SentryAutoBreadcrumbTrackingIntegration.h" #import "SentryBooleanSerialization.h" #import "SentryBreadcrumb+Private.h" -#import "SentryBreadcrumbDelegate.h" -#import "SentryBreadcrumbTracker.h" #import "SentryBuildAppStartSpans.h" #import "SentryByteCountFormatter.h" #import "SentryClassRegistrator.h" @@ -143,7 +139,6 @@ #import "SentryStacktraceBuilder.h" #import "SentrySubClassFinder.h" #import "SentrySwift.h" -#import "SentrySystemEventBreadcrumbs.h" #import "SentrySystemWrapper.h" #import "SentryTestIntegration.h" #import "SentryTestObjCRuntimeWrapper.h" diff --git a/Tests/SentryTests/SentryTests.m b/Tests/SentryTests/SentryTests.m index 25c6c709104..c289b1f1af4 100644 --- a/Tests/SentryTests/SentryTests.m +++ b/Tests/SentryTests/SentryTests.m @@ -1,6 +1,5 @@ #import "SentryBreadcrumb+Private.h" #import "SentryBreadcrumb.h" -#import "SentryBreadcrumbTracker.h" #import "SentryClient.h" #import "SentryDataCategory.h" #import "SentryDateUtils.h" @@ -14,12 +13,6 @@ #import @import Sentry; -@interface SentryBreadcrumbTracker () - -+ (NSString *)sanitizeViewControllerName:(NSString *)controller; - -@end - @interface SentryTests : XCTestCase @end