Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix: Load integration from same binary #4541

Merged
merged 26 commits into from
Nov 26, 2024
Merged
Show file tree
Hide file tree
Changes from 24 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions .github/workflows/ui-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -129,3 +129,23 @@ jobs:
path: |
~/Library/Logs/scan/*.log
./fastlane/test_output/**

duplication-tests:
name: UI Tests for project with Sentry duplicated
runs-on: macos-15

steps:
- uses: actions/checkout@v4
- run: ./scripts/ci-select-xcode.sh "16.0"
- run: ./scripts/build-xcframework.sh gameOnly
- name: Run Fastlane
run: fastlane duplication_test

- name: Archiving Raw Test Logs
uses: actions/upload-artifact@v4
if: ${{ failure() || cancelled() }}
with:
name: raw-ios-swift-test-output-${{matrix.xcode}}-${{matrix.device}}
path: |
~/Library/Logs/scan/*.log
./fastlane/test_output/**
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
- Make `Scope.span` fully thread safe (#4519)
- Finish TTFD when not calling reportFullyDisplayed before binding a new transaction to the scope (#4526).
- Session replay opacity animation masking (#4532)
- Load integration from same binary (#4541)

## 8.40.1

Expand Down
53 changes: 27 additions & 26 deletions Sources/Sentry/SentryOptions.m
Original file line number Diff line number Diff line change
Expand Up @@ -39,48 +39,49 @@ @implementation SentryOptions {
BOOL _enableTracingManual;
}

NSMutableArray<NSString *> *
sentry_defaultIntegrations(void)
+ (NSArray<NSString *> *)defaultIntegrations
{
NSArray<Class> *defaultIntegrationClasses = [self defaultIntegrationClasses];
NSMutableArray<NSString *> *defaultIntegrationNames =
[[NSMutableArray alloc] initWithCapacity:defaultIntegrationClasses.count];

for (Class class in defaultIntegrationClasses) {
[defaultIntegrationNames addObject:NSStringFromClass(class)];
}

return defaultIntegrationNames;
}

+ (NSArray<Class> *)defaultIntegrationClasses
{
// The order of integrations here is important.
// SentryCrashIntegration needs to be initialized before SentryAutoSessionTrackingIntegration.
// And SentrySessionReplayIntegration before SentryCrashIntegration.
NSMutableArray<NSString *> *defaultIntegrations = [NSMutableArray<NSString *> arrayWithObjects:
NSMutableArray<Class> *defaultIntegrations = [NSMutableArray<Class> arrayWithObjects:
#if SENTRY_HAS_UIKIT && !TARGET_OS_VISION
NSStringFromClass([SentrySessionReplayIntegration class]),
[SentrySessionReplayIntegration class],
#endif
NSStringFromClass([SentryCrashIntegration class]),
[SentryCrashIntegration class],
#if SENTRY_HAS_UIKIT
NSStringFromClass([SentryAppStartTrackingIntegration class]),
NSStringFromClass([SentryFramesTrackingIntegration class]),
NSStringFromClass([SentryPerformanceTrackingIntegration class]),
NSStringFromClass([SentryScreenshotIntegration class]),
NSStringFromClass([SentryUIEventTrackingIntegration class]),
NSStringFromClass([SentryViewHierarchyIntegration class]),
NSStringFromClass([SentryWatchdogTerminationTrackingIntegration class]),
[SentryAppStartTrackingIntegration class], [SentryFramesTrackingIntegration class],
[SentryPerformanceTrackingIntegration class], [SentryScreenshotIntegration class],
[SentryUIEventTrackingIntegration class], [SentryViewHierarchyIntegration class],
[SentryWatchdogTerminationTrackingIntegration class],
#endif // SENTRY_HAS_UIKIT
NSStringFromClass([SentryANRTrackingIntegration class]),
NSStringFromClass([SentryAutoBreadcrumbTrackingIntegration class]),
NSStringFromClass([SentryAutoSessionTrackingIntegration class]),
NSStringFromClass([SentryCoreDataTrackingIntegration class]),
NSStringFromClass([SentryFileIOTrackingIntegration class]),
NSStringFromClass([SentryNetworkTrackingIntegration class]),
NSStringFromClass([SentrySwiftAsyncIntegration class]), nil];
[SentryANRTrackingIntegration class], [SentryAutoBreadcrumbTrackingIntegration class],
[SentryAutoSessionTrackingIntegration class], [SentryCoreDataTrackingIntegration class],
[SentryFileIOTrackingIntegration class], [SentryNetworkTrackingIntegration class],
[SentrySwiftAsyncIntegration class], nil];

#if SENTRY_HAS_METRIC_KIT
if (@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, *)) {
[defaultIntegrations addObject:NSStringFromClass([SentryMetricKitIntegration class])];
[defaultIntegrations addObject:[SentryMetricKitIntegration class]];
}
#endif // SENTRY_HAS_METRIC_KIT

return defaultIntegrations;
}

+ (NSArray<NSString *> *)defaultIntegrations
{
return sentry_defaultIntegrations();
}

- (instancetype)init
{
if (self = [super init]) {
Expand All @@ -97,7 +98,7 @@ - (instancetype)init
self.debug = NO;
self.maxBreadcrumbs = defaultMaxBreadcrumbs;
self.maxCacheItems = 30;
_integrations = sentry_defaultIntegrations();
_integrations = [SentryOptions defaultIntegrations];
self.sampleRate = SENTRY_DEFAULT_SAMPLE_RATE;
self.enableAutoSessionTracking = YES;
self.enableGraphQLOperationTracking = NO;
Expand Down
18 changes: 17 additions & 1 deletion Sources/Sentry/SentrySDK.m
Original file line number Diff line number Diff line change
Expand Up @@ -464,16 +464,32 @@
NSMutableArray<NSString *> *integrationNames =
[SentrySDK.currentHub getClient].options.integrations.mutableCopy;

NSArray<Class> *defaultIntegrations = SentryOptions.defaultIntegrationClasses;

// We are going to use a dictionary that links the classes with their names
// so we can quickly check whether that class is in the option integrations collection.
// We cannot load the class itself with NSClassFromString because doing so may load a class
// that was duplicated in another module, leading to undefined behavior.
NSMutableDictionary<NSString *, Class> *integrationDictionary =
[[NSMutableDictionary alloc] init];

for (Class integrationClass in defaultIntegrations) {
integrationDictionary[NSStringFromClass(integrationClass)] = integrationClass;
}

#if TARGET_OS_IOS && SENTRY_HAS_UIKIT
if (@available(iOS 13.0, *)) {
if (options.userFeedbackConfiguration != nil) {
integrationDictionary[NSStringFromClass([SentryUserFeedbackIntegration class])] =
[SentryUserFeedbackIntegration class];

Check warning on line 484 in Sources/Sentry/SentrySDK.m

View check run for this annotation

Codecov / codecov/patch

Sources/Sentry/SentrySDK.m#L483-L484

Added lines #L483 - L484 were not covered by tests
[integrationNames addObject:NSStringFromClass([SentryUserFeedbackIntegration class])];
}
}
#endif // TARGET_OS_IOS && SENTRY_HAS_UIKIT

for (NSString *integrationName in integrationNames) {
Class integrationClass = NSClassFromString(integrationName);
Class integrationClass
= integrationDictionary[integrationName] ?: NSClassFromString(integrationName);
if (nil == integrationClass) {
SENTRY_LOG_ERROR(@"[SentryHub doInstallIntegrations] "
@"couldn't find \"%@\" -> skipping.",
Expand Down
2 changes: 2 additions & 0 deletions Sources/Sentry/include/SentryOptions+Private.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ FOUNDATION_EXPORT NSString *const kSentryDefaultEnvironment;
@property (nonatomic, copy, nullable)
SentryUserFeedbackConfigurationBlock configureUserFeedback API_AVAILABLE(ios(13.0));

@property (nonatomic, readonly, class) NSArray<Class> *defaultIntegrationClasses;

@property (nonatomic, strong, nullable)
SentryUserFeedbackConfiguration *userFeedbackConfiguration API_AVAILABLE(ios(13.0));

Expand Down
Loading
Loading