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

ref: prevent implicit UIKit linkage #3175

Merged
merged 61 commits into from
Oct 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
61 commits
Select commit Hold shift + click to select a range
9baf396
redefine all UIKit callers as dynamic class accesses; also redefine e…
armcknight Jul 19, 2023
09da2a9
fixup! redefine all UIKit callers as dynamic class accesses; also red…
armcknight Jul 19, 2023
8cd73d4
TEMP: comment out code that would have to be moved to separate target
armcknight Jul 19, 2023
c98b25e
fixup! redefine all UIKit callers as dynamic class accesses; also red…
armcknight Jul 19, 2023
824421e
disable autolinking clang modules
armcknight Jul 19, 2023
4440cca
fixup! redefine all UIKit callers as dynamic class accesses; also red…
armcknight Jul 19, 2023
f1e92f5
add configurations that allow us to test UIKit more easily, like with…
armcknight Jul 20, 2023
f7d1e0a
use correct macro and fix endif comments
armcknight Jul 25, 2023
435f4b7
Merge remote-tracking branch 'origin/main' into armcknight/ref/weak-l…
armcknight Sep 27, 2023
798aaae
also fix infoplist path
armcknight Sep 27, 2023
6229965
remove unused UIView category; remove UIViewController category, move…
armcknight Sep 27, 2023
bddbf2c
conditionally compile screenshotting only if uikit is actually linked…
armcknight Sep 28, 2023
264bb25
ref: remove SENTRY_HAS_UIKIT (and some macros from SentryCrashSystemC…
armcknight Sep 29, 2023
afdff7d
get building with UIKit configuration
armcknight Sep 29, 2023
1670239
invert build configs so there are new ones Debug and Release _without…
armcknight Sep 29, 2023
26733e0
rework/simplify how system name and version are retrieved for iOS/tvOS
armcknight Sep 29, 2023
42e87e4
add a script to run in CI that checks for UIKit linkage where it shou…
armcknight Sep 29, 2023
aacc08c
Merge remote-tracking branch 'origin/main' into armcknight/ref/weak-l…
armcknight Sep 29, 2023
2540e28
fixup! Merge remote-tracking branch 'origin/main' into armcknight/ref…
armcknight Sep 29, 2023
dce4574
fix macro def for macos and SENTRY_HAS_UIKIT so that it only applies …
armcknight Sep 29, 2023
5fd5079
bail from script if file doesnt exist; fix iphone destination
armcknight Sep 29, 2023
6cd4946
set debug in script
armcknight Sep 29, 2023
2ba14d6
fix comparison
armcknight Sep 29, 2023
cf47563
fix grep invocation to succeed regardless if there were no matches
armcknight Sep 29, 2023
4d6c9a0
fix iOS-Swift build
armcknight Oct 3, 2023
14c642a
fix test script invocations
armcknight Oct 3, 2023
f7986b1
fix macOS test build
armcknight Oct 4, 2023
f567fec
fix tvOS test build
armcknight Oct 4, 2023
8a23f82
make uikit-only options no-ops without uikit linked and print warning…
armcknight Oct 4, 2023
d12522c
set uikit macro in SPM/CocoaPods specs
armcknight Oct 4, 2023
05c2cc7
try fixing patch file
armcknight Oct 4, 2023
34d7c83
Merge remote-tracking branch 'origin/main' into armcknight/ref/weak-l…
armcknight Oct 4, 2023
faf2b91
fixup! set uikit macro in SPM/CocoaPods specs
armcknight Oct 4, 2023
3ef32d5
fixup! Merge remote-tracking branch 'origin/main' into armcknight/ref…
armcknight Oct 4, 2023
826eeb7
fixup! fixup! set uikit macro in SPM/CocoaPods specs
armcknight Oct 4, 2023
877813f
Merge remote-tracking branch 'origin/main' into armcknight/ref/weak-l…
armcknight Oct 4, 2023
2436c40
fix invocation args after merge
armcknight Oct 4, 2023
742b032
try putting back changes to SentryUIApplication in SentryUIViewContro…
armcknight Oct 5, 2023
aeaebfc
put back some breadcrumb tracker unnecessary changes
armcknight Oct 5, 2023
9c7c63b
put back device test macro: cant use the one in sentrydefines from th…
armcknight Oct 5, 2023
7b73122
put back UIViewController+Sentry category/test
armcknight Oct 5, 2023
0b8dfcb
Merge remote-tracking branch 'origin/main' into armcknight/ref/weak-l…
armcknight Oct 5, 2023
2f5c366
add develop-docs section describing out conditional linking of UIKit
armcknight Oct 5, 2023
fdb629c
fixup! put back UIViewController+Sentry category/test
armcknight Oct 5, 2023
bf321a9
fix typo
armcknight Oct 5, 2023
74dd57a
remove failing breadcrumb test from non-ios runs; some method/propert…
armcknight Oct 5, 2023
ff8f48f
remove CLANG_ENABLE_OBJC_WEAK added as early experiment; orphaned pbx…
armcknight Oct 5, 2023
2fe817d
changelog
armcknight Oct 5, 2023
bf976e3
stub PrivateSentrySDKOnly methods when UIKit not linked
armcknight Oct 5, 2023
c0cc1ba
add another macro
armcknight Oct 5, 2023
f7c3e1f
add endif comment
armcknight Oct 5, 2023
99e61a6
remove gated compilation in test app
armcknight Oct 5, 2023
ccd2465
stub implementations in exposed headers depending on presence of UIKit
armcknight Oct 6, 2023
14d87be
fix build
armcknight Oct 6, 2023
83aa958
fixup! fix build
armcknight Oct 6, 2023
a697fca
update develop-docs/README.md
armcknight Oct 6, 2023
45b984a
Merge remote-tracking branch 'origin/main' into armcknight/ref/weak-l…
armcknight Oct 10, 2023
c39bc7b
Merge remote-tracking branch 'origin/main' into armcknight/ref/weak-l…
armcknight Oct 11, 2023
6f0ed44
terminate in debug for customer-facing UIKit-only API in UIKitless bu…
armcknight Oct 12, 2023
9474a92
remove unneeded getters
armcknight Oct 13, 2023
dc4e0cc
Merge remote-tracking branch 'origin/main' into armcknight/ref/weak-l…
armcknight Oct 13, 2023
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/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -166,3 +166,23 @@ jobs:
- uses: actions/checkout@v4
- run: swift build
shell: sh

check-uikit-linkage-debug:
armcknight marked this conversation as resolved.
Show resolved Hide resolved
name: Check UIKit linkage (Debug)
runs-on: macos-13
steps:
- uses: actions/checkout@v4
- name: Build for Debug
run: ./scripts/xcode-test.sh "iOS" "latest" $GITHUB_REF_NAME ci build "iPhone 14" Debug_without_UIKit uikit-check-build
- name: Ensure no UIKit
run: ./scripts/check-uikit-linkage.sh Debug_without_UIKit uikit-check-build

check-uikit-linkage-release:
name: Check UIKit linkage (Release)
runs-on: macos-13
steps:
- uses: actions/checkout@v4
- name: Build for Release
run: ./scripts/xcode-test.sh "iOS" "latest" $GITHUB_REF_NAME ci build "iPhone 14" Release_without_UIKit uikit-check-build
- name: Ensure no UIKit
run: ./scripts/check-uikit-linkage.sh Release_without_UIKit uikit-check-build
4 changes: 2 additions & 2 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -182,14 +182,14 @@ jobs:
# We split building and running tests in two steps so we know how long running the tests takes.
- name: Build tests
id: build_tests
run: ./scripts/xcode-test.sh ${{matrix.platform}} ${{matrix.test-destination-os}} $GITHUB_REF_NAME ci build-for-testing "${{matrix.device}}"
run: ./scripts/xcode-test.sh ${{matrix.platform}} ${{matrix.test-destination-os}} $GITHUB_REF_NAME ci build-for-testing "${{matrix.device}}" TestCI

- name: Run tests
# We call a script with the platform so the destination
# passed to xcodebuild doesn't end up in the job name,
# because GitHub Actions don't provide an easy way of
# manipulating string in expressions.
run: ./scripts/xcode-test.sh ${{matrix.platform}} ${{matrix.test-destination-os}} $GITHUB_REF_NAME ci test-without-building "${{matrix.device}}"
run: ./scripts/xcode-test.sh ${{matrix.platform}} ${{matrix.test-destination-os}} $GITHUB_REF_NAME ci test-without-building "${{matrix.device}}" TestCI

- name: Slowest Tests
if: ${{ always() }}
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

### Features

- Sentry can now be used without linking UIKit; this is helpful for using the SDK in certain app extension contexts (#3175)
armcknight marked this conversation as resolved.
Show resolved Hide resolved
- GA of MetricKit integration (#3340)

Once enabled, this feature subscribes to [MetricKit's](https://developer.apple.com/documentation/metrickit) [MXDiagnosticPayload](https://developer.apple.com/documentation/metrickit/mxdiagnosticpayload) data, converts it to events, and sends it to Sentry.
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ GIT-REF := $(shell git rev-parse --abbrev-ref HEAD)

test:
@echo "--> Running all tests"
./scripts/xcode-test.sh iOS latest $(GIT-REF) YES
./scripts/xcode-test.sh iOS latest $(GIT-REF) YES test Test
./scripts/xcode-slowest-tests.sh
.PHONY: test

Expand Down
1 change: 1 addition & 0 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ let package = Package(
"SentryCrash/"
],
publicHeadersPath: "Sentry/Public/",
cSettings: [.unsafeFlags(["-DSENTRY_UIKIT_LINKED=1"])],
cxxSettings: [
.define("GCC_ENABLE_CPP_EXCEPTIONS", to: "YES"),
.headerSearchPath("Sentry/include"),
Expand Down
2 changes: 1 addition & 1 deletion Samples/iOS-Swift/iOS-Swift/ExtraViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ class ExtraViewController: UIViewController {
}

SentrySDK.reportFullyDisplayed()

Timer.scheduledTimer(withTimeInterval: 0.5, repeats: true) { _ in
self.framesLabel?.text = "Frames Total:\(PrivateSentrySDKOnly.currentScreenFrames.total) Slow:\(PrivateSentrySDKOnly.currentScreenFrames.slow) Frozen:\(PrivateSentrySDKOnly.currentScreenFrames.frozen)"
}
Expand Down
3 changes: 2 additions & 1 deletion Sentry.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ Pod::Spec.new do |s|
s.pod_target_xcconfig = {
'GCC_ENABLE_CPP_EXCEPTIONS' => 'YES',
'CLANG_CXX_LANGUAGE_STANDARD' => 'c++14',
'CLANG_CXX_LIBRARY' => 'libc++'
'CLANG_CXX_LIBRARY' => 'libc++',
'GCC_PREPROCESSOR_DEFINITIONS' => 'SENTRY_UIKIT_LINKED=1'
}
s.watchos.pod_target_xcconfig = {
'OTHER_LDFLAGS' => '$(inherited) -framework WatchKit'
Expand Down
686 changes: 664 additions & 22 deletions Sentry.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions Sentry.xcodeproj/xcshareddata/xcschemes/Sentry.xcscheme
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,9 @@
<Test
Identifier = "SentrySubClassFinderTests/testActOnSubclassesOfViewController()">
</Test>
<Test
Identifier = "SentryThreadInspectorTests/testStacktraceHasFrames_forEveryThread()">
</Test>
</SkippedTests>
</TestableReference>
<TestableReference
Expand Down
6 changes: 6 additions & 0 deletions SentryTestUtils/SentryTestUtils-ObjC-BridgingHeader.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
#import "SentryDefines.h"

#if TARGET_OS_IOS || TARGET_OS_TV
# define SENTRY_UIKIT_AVAILABLE 1
#else
# define SENTRY_UIKIT_AVAILABLE 0
#endif

#if SENTRY_HAS_UIKIT
# import "SentryAppStartTracker.h"
# import "SentryDisplayLinkWrapper.h"
Expand Down
47 changes: 42 additions & 5 deletions Sources/Sentry/PrivateSentrySDKOnly.mm
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ @implementation PrivateSentrySDKOnly
static BOOL _appStartMeasurementHybridSDKMode = NO;
#if SENTRY_HAS_UIKIT
static BOOL _framesTrackingMeasurementHybridSDKMode = NO;
#endif
#endif // SENTRY_HAS_UIKIT

+ (void)storeEnvelope:(SentryEnvelope *)envelope
{
Expand Down Expand Up @@ -157,40 +157,77 @@ + (void)discardProfilerForTrace:(SentryId *)traceId;

#endif // SENTRY_TARGET_PROFILING_SUPPORTED

#if SENTRY_HAS_UIKIT

+ (BOOL)framesTrackingMeasurementHybridSDKMode
{
#if SENTRY_HAS_UIKIT
return _framesTrackingMeasurementHybridSDKMode;
#else
SENTRY_LOG_DEBUG(@"PrivateSentrySDKOnly.framesTrackingMeasurementHybridSDKMode only works with "
@"UIKit enabled. Ensure you're "
@"using the right configuration of Sentry that links UIKit.");
return NO;
#endif // SENTRY_HAS_UIKIT
}

+ (void)setFramesTrackingMeasurementHybridSDKMode:(BOOL)framesTrackingMeasurementHybridSDKMode
{
#if SENTRY_HAS_UIKIT
_framesTrackingMeasurementHybridSDKMode = framesTrackingMeasurementHybridSDKMode;
#else
SENTRY_LOG_DEBUG(@"PrivateSentrySDKOnly.framesTrackingMeasurementHybridSDKMode only works with "
@"UIKit enabled. Ensure you're "
@"using the right configuration of Sentry that links UIKit.");
#endif // SENTRY_HAS_UIKIT
}

+ (BOOL)isFramesTrackingRunning
{
#if SENTRY_HAS_UIKIT
return SentryDependencyContainer.sharedInstance.framesTracker.isRunning;
#else
SENTRY_LOG_DEBUG(@"PrivateSentrySDKOnly.isFramesTrackingRunning only works with UIKit enabled. "
@"Ensure you're "
@"using the right configuration of Sentry that links UIKit.");
return NO;
#endif // SENTRY_HAS_UIKIT
}

+ (SentryScreenFrames *)currentScreenFrames
{
#if SENTRY_HAS_UIKIT
return SentryDependencyContainer.sharedInstance.framesTracker.currentFrames;
#else
SENTRY_LOG_DEBUG(
@"PrivateSentrySDKOnly.currentScreenFrames only works with UIKit enabled. Ensure you're "
@"using the right configuration of Sentry that links UIKit.");
return nil;
#endif // SENTRY_HAS_UIKIT
}

+ (NSArray<NSData *> *)captureScreenshots
{
#if SENTRY_HAS_UIKIT
return [SentryDependencyContainer.sharedInstance.screenshot takeScreenshots];
#else
SENTRY_LOG_DEBUG(
@"PrivateSentrySDKOnly.captureScreenshots only works with UIKit enabled. Ensure you're "
@"using the right configuration of Sentry that links UIKit.");
return nil;
#endif // SENTRY_HAS_UIKIT
}

+ (NSData *)captureViewHierarchy
{
#if SENTRY_HAS_UIKIT
return [SentryDependencyContainer.sharedInstance.viewHierarchy fetchViewHierarchy];
#else
SENTRY_LOG_DEBUG(
@"PrivateSentrySDKOnly.captureViewHierarchy only works with UIKit enabled. Ensure you're "
@"using the right configuration of Sentry that links UIKit.");
return nil;
#endif // SENTRY_HAS_UIKIT
}

#endif

+ (SentryUser *)userWithDictionary:(NSDictionary *)dictionary
{
return [[SentryUser alloc] initWithDictionary:dictionary];
Expand Down
18 changes: 17 additions & 1 deletion Sources/Sentry/Public/SentryDefines.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,29 @@
# define SENTRY_EXTERN extern __attribute__((visibility("default")))
#endif

// SENTRY_UIKIT_AVAILABLE basically means: are we on a platform where we can link UIKit?
#if TARGET_OS_IOS || TARGET_OS_TV
# define SENTRY_UIKIT_AVAILABLE 1
#else
# define SENTRY_UIKIT_AVAILABLE 0
#endif

// SENTRY_HAS_UIKIT means we're on a platform that can link UIKit and we're building a configuration
// that will allow it to be autolinked. SENTRY_UIKIT_LINKED is set in GCC_PREPROCESSOR_DEFINITIONS
// for configurations that we will allow to link UIKit by setting CLANG_MODULES_AUTOLINK to YES.
#if SENTRY_UIKIT_AVAILABLE && SENTRY_UIKIT_LINKED
# define SENTRY_HAS_UIKIT 1
#else
# define SENTRY_HAS_UIKIT 0
#endif

#if TARGET_OS_IOS || TARGET_OS_OSX || TARGET_OS_MACCATALYST
#if TARGET_OS_OSX || TARGET_OS_MACCATALYST
# define SENTRY_TARGET_MACOS 1
#else
# define SENTRY_TARGET_MACOS 0
#endif

#if TARGET_OS_IOS || SENTRY_TARGET_MACOS
# define SENTRY_HAS_METRIC_KIT 1
#else
# define SENTRY_HAS_METRIC_KIT 0
Expand Down
18 changes: 14 additions & 4 deletions Sources/Sentry/Public/SentryOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -199,15 +199,19 @@ NS_SWIFT_NAME(Options)
*/
@property (nonatomic) SentryScope * (^initialScope)(SentryScope *);

#if SENTRY_HAS_UIKIT

This comment was marked as outdated.

This comment was marked as outdated.

This comment was marked as outdated.

This comment was marked as outdated.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So the issue was that the GCC_PREPROCESSOR_DEFINITION setting being used to set the macro definition in SentryDefines.h had no effect in headers delivered in the framework bundle. So for headers exposed in the framework bundle, I reverted to the previous type of macro, under a new name SENTRY_UIKIT_AVAILABLE, and stubbed the implementations depending on SENTRY_HAS_UIKIT (which, again, means it's available and linked). You can see ccd2465

Copy link
Member Author

@armcknight armcknight Oct 10, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It comes down to how we know whether to link UIKit on iOS/tvOS.

The old way that SENTRY_HAS_UIKIT was defined only tells us if we're compiling for either an iOS or tvOS target. So this works to compile out UIKit code for eg macOS, but if we want to compile out UIKit code on iOS/tvOS, we need another option to switch over. The only way I thought of to do so was to create the new build configs and then vary those from the original debug/release I cloned them from using a new GCC_PREPROCESSOR_DEFINITION that I called SENTRY_UIKIT_LINKED, which we now check for when defining SENTRY_HAS_UIKIT. This is why I renamed what used to be SENTRY_HAS_UIKIT (TARGET_OS_IOS || TARGET_OS_TVOS) to SENTRY_UIKIT_AVAILABLE and changed SENTRY_HAS_UIKIT to be not only SENTRY_UIKIT_AVAILABLE, but also SENTRY_UIKIT_LINKED for the build configs that do so. I think the changed naming is more accurate for both cases as well. Let me know if this makes sense to you; I also wrote this up in the develop-docs/README.md in 2f5c366, let me know if I should tweak that description.

Copy link
Member Author

@armcknight armcknight Oct 11, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also to address your question in your other comment:

I don't understand why we want to expose functionality when UIKit is available on the platform but not linked and to provide a fallback that prints a warning

What I saw was our test apps would not compile for both Debug and Debug_without_UIKit, they'd break on the latter because the symbol was compiled out but the sample app doesn't inherit the GCC_PREPROCESSOR_DEFINITION. We also don't want to make people have to write #if/#endif regions around code we conditionally compile. We figured it was better to not break their builds and just print warnings (and I added documentation to all such public API).

Copy link
Contributor

@brustolin brustolin Oct 12, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with Philipp, it seems to me that #if SENTRY_HAS_UIKIT is what we should use, because it addresses both situation, it's the right target and linking UIKit is enabled. And all this #if SENTRY_HAS_UIKIT or warning is annoying. If the target doesn't support uikit, its better for the user if the build crashes because they are trying to use a feature that don't work than having it compile just to found out later (if at all) that the feature is not supported.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What I saw was our test apps would not compile for both Debug and Debug_without_UIKit, they'd break on the latter because the symbol was compiled out but the sample app doesn't inherit the GCC_PREPROCESSOR_DEFINITION.

Not compiling for Debug is suspicious. Our sample apps not compiling for Debug_without_UIKit should be fine. I guess we need a new sample without UIKit to validate Debug_without_UIKit.

We also don't want to make people have to write #if/#endif regions around code we conditionally compile. We figured it was better to not break their builds and just print warnings (and I added documentation to all such public API).

We absolutely can't break existing builds in a minor version and writing #if/#endif regions is also suboptimal.

I agree with @brustolin. @armcknight, can we somehow make it work without breaking customers?

As you said, maybe it's better to discuss this over a call instead of ping-pong here on GH.

Copy link
Member Author

@armcknight armcknight Oct 12, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

our test apps would not compile for both Debug and Debug_without_UIKit

Not compiling for Debug is suspicious. Our sample apps not compiling for Debug_without_UIKit should be fine

This is due to the nature of the change in how SENTRY_HAS_UIKIT is now defined as I explained above: GCC_PREPROCESSOR_DEFINITIONS cannot propagate to the sample app from the Sentry build config, so SENTRY_HAS_UIKIT was essentially always false in the sample app, so the Sentry header always had the bounded declarations removed.

After my changes, it built for both again, and only emitted the warning logs in debug_without_uikit. I did this so no code changes would be necessary in the sample app. This is my definition of not breaking customers. I can add assertions instead of just warning logs, so that debug builds crash, but not production. How does that sound? I pushed a commit with this change, see 6f0ed44.

#if SENTRY_UIKIT_AVAILABLE
/**
* When enabled, the SDK tracks performance for UIViewController subclasses.
* @warning This feature is not available in @c Debug_without_UIKit and @c Release_without_UIKit
* configurations even when targeting iOS or tvOS platforms.
* @note The default is @c YES .
*/
@property (nonatomic, assign) BOOL enableUIViewControllerTracing;

/**
* Automatically attaches a screenshot when capturing an error or exception.
* @warning This feature is not available in @c Debug_without_UIKit and @c Release_without_UIKit
* configurations even when targeting iOS or tvOS platforms.
* @note Default value is @c NO .
*/
@property (nonatomic, assign) BOOL attachScreenshot;
Expand All @@ -216,24 +220,29 @@ NS_SWIFT_NAME(Options)
* @warning This is an experimental feature and may still have bugs.
* @brief Automatically attaches a textual representation of the view hierarchy when capturing an
* error event.
* @warning This feature is not available in @c Debug_without_UIKit and @c Release_without_UIKit
* configurations even when targeting iOS or tvOS platforms.
* @note Default value is @c NO .
*/
@property (nonatomic, assign) BOOL attachViewHierarchy;

/**
* When enabled, the SDK creates transactions for UI events like buttons clicks, switch toggles,
* and other ui elements that uses UIControl @c sendAction:to:forEvent:
* @warning This feature is not available in @c Debug_without_UIKit and @c Release_without_UIKit
* configurations even when targeting iOS or tvOS platforms.
* @note Default value is @c YES .
*/
@property (nonatomic, assign) BOOL enableUserInteractionTracing;

/**
* How long an idle transaction waits for new children after all its child spans finished. Only UI
* event transactions are idle transactions.
* @warning This feature is not available in @c Debug_without_UIKit and @c Release_without_UIKit
* configurations even when targeting iOS or tvOS platforms.
* @note The default is 3 seconds.
*/
@property (nonatomic, assign) NSTimeInterval idleTimeout;

/**
* @warning This is an experimental feature and may still have bugs.
* @brief Report pre-warmed app starts by dropping the first app start spans if pre-warming paused
Expand All @@ -242,11 +251,12 @@ NS_SWIFT_NAME(Options)
* @note You can filter for different app start types in Discover with
* @c app_start_type:cold.prewarmed ,
* @c app_start_type:warm.prewarmed , @c app_start_type:cold , and @c app_start_type:warm .
* @warning This feature is not available in @c Debug_without_UIKit and @c Release_without_UIKit
* configurations even when targeting iOS or tvOS platforms.
* @note Default value is @c NO .
*/
@property (nonatomic, assign) BOOL enablePreWarmedAppStartTracing;

#endif // SENTRY_HAS_UIKIT
#endif // SENTRY_UIKIT_AVAILABLE

/**
* When enabled, the SDK tracks performance for HTTP requests if auto performance tracking and
Expand Down
28 changes: 26 additions & 2 deletions Sources/Sentry/SentryAppStartMeasurement.m
Original file line number Diff line number Diff line change
@@ -1,25 +1,43 @@
#import "SentryAppStartMeasurement.h"

#if SENTRY_HAS_UIKIT
#if SENTRY_UIKIT_AVAILABLE

# import "NSDate+SentryExtras.h"
# import "SentryLog.h"
# import <Foundation/Foundation.h>

@implementation SentryAppStartMeasurement
# if SENTRY_HAS_UIKIT
{
SentryAppStartType _type;
BOOL _isPreWarmed;
NSTimeInterval _duration;
NSDate *_appStartTimestamp;
NSDate *_runtimeInitTimestamp;
NSDate *_moduleInitializationTimestamp;
NSDate *_didFinishLaunchingTimestamp;
}
# endif // SENTRY_HAS_UIKIT

- (instancetype)initWithType:(SentryAppStartType)type
appStartTimestamp:(NSDate *)appStartTimestamp
duration:(NSTimeInterval)duration
runtimeInitTimestamp:(NSDate *)runtimeInitTimestamp
didFinishLaunchingTimestamp:(NSDate *)didFinishLaunchingTimestamp
{
# if SENTRY_HAS_UIKIT
return [self initWithType:type
isPreWarmed:NO
appStartTimestamp:appStartTimestamp
duration:duration
runtimeInitTimestamp:runtimeInitTimestamp
moduleInitializationTimestamp:[NSDate dateWithTimeIntervalSince1970:0]
didFinishLaunchingTimestamp:didFinishLaunchingTimestamp];
# else
SENTRY_LOG_DEBUG(@"SentryAppStartMeasurement only works with UIKit enabled. Ensure you're "
@"using the right configuration of Sentry that links UIKit.");
return nil;
# endif // SENTRY_HAS_UIKIT
}

- (instancetype)initWithType:(SentryAppStartType)type
Expand All @@ -30,6 +48,7 @@ - (instancetype)initWithType:(SentryAppStartType)type
moduleInitializationTimestamp:(NSDate *)moduleInitializationTimestamp
didFinishLaunchingTimestamp:(NSDate *)didFinishLaunchingTimestamp
{
# if SENTRY_HAS_UIKIT
if (self = [super init]) {
_type = type;
_isPreWarmed = isPreWarmed;
Expand All @@ -41,8 +60,13 @@ - (instancetype)initWithType:(SentryAppStartType)type
}

return self;
# else
SENTRY_LOG_DEBUG(@"SentryAppStartMeasurement only works with UIKit enabled. Ensure you're "
@"using the right configuration of Sentry that links UIKit.");
return nil;
# endif // SENTRY_HAS_UIKIT
}

@end

#endif // SENTRY_HAS_UIKIT
#endif // SENTRY_UIKIT_AVAILABLE
1 change: 1 addition & 0 deletions Sources/Sentry/SentryAppStartTracker.m
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

# import "SentryAppStartMeasurement.h"
# import "SentryAppStateManager.h"
# import "SentryDefines.h"
# import "SentryLog.h"
# import "SentrySysctl.h"
# import <Foundation/Foundation.h>
Expand Down
5 changes: 3 additions & 2 deletions Sources/Sentry/SentryAppStateManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -179,10 +179,11 @@ - (SentryAppState *)buildCurrentAppState
// Is the current process being traced or not? If it is a debugger is attached.
bool isDebugging = self.crashWrapper.isBeingTraced;

NSString *vendorId = [UIDevice.currentDevice.identifierForVendor UUIDString];
UIDevice *device = [UIDevice currentDevice];
NSString *vendorId = [device.identifierForVendor UUIDString];

return [[SentryAppState alloc] initWithReleaseName:self.options.releaseName
osVersion:UIDevice.currentDevice.systemVersion
osVersion:device.systemVersion
vendorId:vendorId
isDebugging:isDebugging
systemBootTimestamp:SentryDependencyContainer.sharedInstance
Expand Down
Loading