Skip to content

Commit 8ea5293

Browse files
authored
Full spm (#5359)
* Update codable conformances for SPM * Fix SentryId for SentryEvent in SPM * Update build and add to CI * PR comments
1 parent fc0757d commit 8ea5293

23 files changed

+401
-68
lines changed

.github/workflows/build.yml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,14 @@ jobs:
8787
name: raw-build-output-scheme-${{matrix.scheme}}
8888
path: |
8989
raw-build-output.log
90+
build-spm:
91+
name: Build with SPM
92+
runs-on: macos-15
93+
steps:
94+
- uses: actions/checkout@v4
95+
# Only watchOS is compiling with SPM so far, the rest of the targets need profiling support which is still a work in progress due to the ObjC++ usage
96+
- run: rm -r Sentry.xcodeproj && rm -r Sentry.xcworkspace && EXPERIMENTAL_SPM_BUILDS=1 xcodebuild build -scheme SentrySPM -sdk watchos -destination 'generic/platform=watchOS'
97+
shell: sh
9098

9199
check-debug-without-UIKit:
92100
name: Check no UIKit linkage (DebugWithoutUIKit)

Package.swift

Lines changed: 82 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,90 @@
11
// swift-tools-version:5.3
2+
import Darwin.C
23
import PackageDescription
34

5+
var products: [Product] = [
6+
.library(name: "Sentry", targets: ["Sentry"]),
7+
.library(name: "Sentry-Dynamic", targets: ["Sentry-Dynamic"]),
8+
.library(name: "SentrySwiftUI", targets: ["Sentry", "SentrySwiftUI"])
9+
]
10+
11+
var targets: [Target] = [
12+
.binaryTarget(
13+
name: "Sentry",
14+
url: "https://github.com/getsentry/sentry-cocoa/releases/download/8.52.1/Sentry.xcframework.zip",
15+
checksum: "48a6c6693148a3f9096108164eb938a931b964395fcf38e169383b9e4cffcfc5" //Sentry-Static
16+
),
17+
.binaryTarget(
18+
name: "Sentry-Dynamic",
19+
url: "https://github.com/getsentry/sentry-cocoa/releases/download/8.52.1/Sentry-Dynamic.xcframework.zip",
20+
checksum: "b9d9054c65ee5ac0591c27826edddc54490a96c2a83dee25519cae0c1a593231" //Sentry-Dynamic
21+
),
22+
.target (
23+
name: "SentrySwiftUI",
24+
dependencies: ["Sentry", "SentryInternal"],
25+
path: "Sources/SentrySwiftUI",
26+
exclude: ["SentryInternal/", "module.modulemap"],
27+
linkerSettings: [
28+
.linkedFramework("Sentry")
29+
]),
30+
.target(
31+
name: "SentryInternal",
32+
path: "Sources/SentrySwiftUI",
33+
sources: [
34+
"SentryInternal/"
35+
],
36+
publicHeadersPath: "SentryInternal/")
37+
]
38+
39+
let env = getenv("EXPERIMENTAL_SPM_BUILDS")
40+
if let env, String(cString: env, encoding: .utf8) == "1" {
41+
products.append(.library(name: "SentrySPM", type: .dynamic, targets: ["SentryObjc"]))
42+
targets.append(contentsOf: [
43+
// At least one source file is required
44+
.target(name: "SentryHeaders", path: "Sources/Sentry", sources: ["SentryDsn.m"], publicHeadersPath: "Public"),
45+
.target(
46+
name: "_SentryPrivate",
47+
dependencies: ["SentryHeaders"],
48+
path: "Sources/Sentry",
49+
sources: ["NSLocale+Sentry.m"],
50+
publicHeadersPath: "include",
51+
cSettings: [.headerSearchPath("include/HybridPublic")]),
52+
.target(
53+
name: "SentrySwift",
54+
dependencies: ["_SentryPrivate", "SentryHeaders"],
55+
path: "Sources/Swift",
56+
swiftSettings: [
57+
// The application extension flag is required due to https://github.com/getsentry/sentry-cocoa/issues/5371
58+
.unsafeFlags(["-enable-library-evolution", "-Xfrontend", "-application-extension"]),
59+
// This flag is used to make some API breaking changes necessary for the framework to compile with SPM.
60+
// We can either make more extensive changes to allow it to be backwards compatible, or release them as part of a V9 release.
61+
// For now we use this flag so that CI can compile the SPM version.
62+
.define("SENTRY_SWIFT_PACKAGE")
63+
],
64+
linkerSettings: [
65+
.unsafeFlags(["-Xlinker", "-application_extension"])
66+
]),
67+
.target(
68+
name: "SentryObjc",
69+
dependencies: ["SentrySwift"],
70+
path: "Sources",
71+
exclude: ["Sentry/SentryDsn.m", "Sentry/NSLocale+Sentry.m", "Swift", "SentrySwiftUI", "Resources", "Configuration"],
72+
cSettings: [
73+
.headerSearchPath("Sentry/include/HybridPublic"),
74+
.headerSearchPath("Sentry"),
75+
.headerSearchPath("SentryCrash/Recording"),
76+
.headerSearchPath("SentryCrash/Recording/Monitors"),
77+
.headerSearchPath("SentryCrash/Recording/Tools"),
78+
.headerSearchPath("SentryCrash/Installations"),
79+
.headerSearchPath("SentryCrash/Reporting/Filters"),
80+
.headerSearchPath("SentryCrash/Reporting/Filters/Tools")])
81+
])
82+
}
83+
484
let package = Package(
585
name: "Sentry",
686
platforms: [.iOS(.v11), .macOS(.v10_13), .tvOS(.v11), .watchOS(.v4)],
7-
products: [
8-
.library(name: "Sentry", targets: ["Sentry"]),
9-
.library(name: "Sentry-Dynamic", targets: ["Sentry-Dynamic"]),
10-
.library(name: "SentrySwiftUI", targets: ["Sentry", "SentrySwiftUI"])
11-
],
12-
targets: [
13-
.binaryTarget(
14-
name: "Sentry",
15-
url: "https://github.com/getsentry/sentry-cocoa/releases/download/8.52.1/Sentry.xcframework.zip",
16-
checksum: "48a6c6693148a3f9096108164eb938a931b964395fcf38e169383b9e4cffcfc5" //Sentry-Static
17-
),
18-
.binaryTarget(
19-
name: "Sentry-Dynamic",
20-
url: "https://github.com/getsentry/sentry-cocoa/releases/download/8.52.1/Sentry-Dynamic.xcframework.zip",
21-
checksum: "b9d9054c65ee5ac0591c27826edddc54490a96c2a83dee25519cae0c1a593231" //Sentry-Dynamic
22-
),
23-
.target ( name: "SentrySwiftUI",
24-
dependencies: ["Sentry", "SentryInternal"],
25-
path: "Sources/SentrySwiftUI",
26-
exclude: ["SentryInternal/", "module.modulemap"],
27-
linkerSettings: [
28-
.linkedFramework("Sentry")
29-
]
30-
),
31-
.target( name: "SentryInternal",
32-
path: "Sources/SentrySwiftUI",
33-
sources: [
34-
"SentryInternal/"
35-
],
36-
publicHeadersPath: "SentryInternal/"
37-
),
38-
.target(name: "SentryCoreSwift", path: "Sources/Swift/Core")
39-
],
87+
products: products,
88+
targets: targets,
4089
cxxLanguageStandard: .cxx14
4190
)

Sentry.xcodeproj/project.pbxproj

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1071,6 +1071,8 @@
10711071
FA67DD192DDBD4EA00896B02 /* SwizzleClassNameExclude.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA67DCD52DDBD4EA00896B02 /* SwizzleClassNameExclude.swift */; };
10721072
FA8A36182DEAA1EB0058D883 /* SentryThread+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = FA8A36172DEAA1EB0058D883 /* SentryThread+Private.h */; };
10731073
FA90FAFD2E070A3B008CAAE8 /* SentryURLRequestFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA90FAFC2E070A3B008CAAE8 /* SentryURLRequestFactory.swift */; };
1074+
FAB359982E05D7E90083D5E3 /* SentryEventSwiftHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = FAB359972E05D7E90083D5E3 /* SentryEventSwiftHelper.h */; };
1075+
FAB3599A2E05D8080083D5E3 /* SentryEventSwiftHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = FAB359992E05D8080083D5E3 /* SentryEventSwiftHelper.m */; };
10741076
FAEC270E2DF3526000878871 /* SentryUserFeedback.swift in Sources */ = {isa = PBXBuildFile; fileRef = FAEC270D2DF3526000878871 /* SentryUserFeedback.swift */; };
10751077
FAEC273D2DF3933A00878871 /* NSData+Unzip.m in Sources */ = {isa = PBXBuildFile; fileRef = FAEC273C2DF3933200878871 /* NSData+Unzip.m */; };
10761078
/* End PBXBuildFile section */
@@ -2322,6 +2324,8 @@
23222324
FA67DCF22DDBD4EA00896B02 /* SwiftDescriptor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftDescriptor.swift; sourceTree = "<group>"; };
23232325
FA8A36172DEAA1EB0058D883 /* SentryThread+Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "SentryThread+Private.h"; path = "include/SentryThread+Private.h"; sourceTree = "<group>"; };
23242326
FA90FAFC2E070A3B008CAAE8 /* SentryURLRequestFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SentryURLRequestFactory.swift; sourceTree = "<group>"; };
2327+
FAB359972E05D7E90083D5E3 /* SentryEventSwiftHelper.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SentryEventSwiftHelper.h; path = include/SentryEventSwiftHelper.h; sourceTree = "<group>"; };
2328+
FAB359992E05D8080083D5E3 /* SentryEventSwiftHelper.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SentryEventSwiftHelper.m; sourceTree = "<group>"; };
23252329
FAEC270D2DF3526000878871 /* SentryUserFeedback.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SentryUserFeedback.swift; sourceTree = "<group>"; };
23262330
FAEC273C2DF3933200878871 /* NSData+Unzip.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "NSData+Unzip.m"; sourceTree = "<group>"; };
23272331
FAEC273E2DF393E000878871 /* NSData+Unzip.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "NSData+Unzip.h"; sourceTree = "<group>"; };
@@ -2796,6 +2800,8 @@
27962800
844EDC75294144DB00C86F34 /* SentrySystemWrapper.mm */,
27972801
844EDCE32947DC3100C86F34 /* SentryNSTimerFactory.h */,
27982802
844EDCE42947DC3100C86F34 /* SentryNSTimerFactory.m */,
2803+
FAB359972E05D7E90083D5E3 /* SentryEventSwiftHelper.h */,
2804+
FAB359992E05D8080083D5E3 /* SentryEventSwiftHelper.m */,
27992805
33042A0B29DAF5F400C60085 /* SentryExtraContextProvider.h */,
28002806
33042A0C29DAF79A00C60085 /* SentryExtraContextProvider.m */,
28012807
D858FA642A29EAB3002A3503 /* SentryBinaryImageCache.h */,
@@ -4781,6 +4787,7 @@
47814787
8E564AEF267AF24400FE117D /* SentryNetworkTracker.h in Headers */,
47824788
63FE715120DA4C1100CDBAE8 /* SentryCrashDebug.h in Headers */,
47834789
63FE70F520DA4C1000CDBAE8 /* SentryCrashMonitor_System.h in Headers */,
4790+
FAB359982E05D7E90083D5E3 /* SentryEventSwiftHelper.h in Headers */,
47844791
7B31C291277B04A000337126 /* SentryCrashPlatformSpecificDefines.h in Headers */,
47854792
D452FC732DDB553100AFF56F /* SentryWatchdogTerminationBreadcrumbProcessor.h in Headers */,
47864793
D456B4382D706BFE007068CB /* SentrySpanDataKey.h in Headers */,
@@ -5591,6 +5598,7 @@
55915598
63FE711520DA4C1000CDBAE8 /* SentryCrashJSONCodec.c in Sources */,
55925599
03F84D3327DD4191008FE43F /* SentryMachLogging.cpp in Sources */,
55935600
D85852BA27EDDC5900C6D8AE /* SentryUIApplication.m in Sources */,
5601+
FAB3599A2E05D8080083D5E3 /* SentryEventSwiftHelper.m in Sources */,
55945602
7B4E375F258231FC00059C93 /* SentryAttachment.m in Sources */,
55955603
636085141ED47BE600E8599E /* SentryFileManager.m in Sources */,
55965604
63FE710B20DA4C1000CDBAE8 /* SentryCrashMach.c in Sources */,
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#import "SentryEventSwiftHelper.h"
2+
#import "SentryEvent.h"
3+
#import "SentrySwift.h"
4+
5+
// This helper is to bridge Swift and ObjC when building with SPM.
6+
// SPM cannot use Swift types in public ObjC APIs. Since SentryId
7+
// is Swift and SentryEvent is ObjC, Swift code built with SPM
8+
// cannot modify the eventId. This helper makes that possible.
9+
// Other solutions involve a force cast, forward declaring in ObjC
10+
// or re-writing in Swift. We will explore those in the future, but for
11+
// now this enables CI to build with SPM.
12+
@implementation SentryEventSwiftHelper
13+
14+
+ (void)setEventIdString:(NSString *)idString event:(SentryEvent *)event
15+
{
16+
event.eventId = [[SentryId alloc] initWithUUIDString:idString];
17+
}
18+
19+
+ (NSString *)getEventIdString:(SentryEvent *)event
20+
{
21+
return event.eventId.sentryIdString;
22+
}
23+
24+
@end
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#import <Foundation/Foundation.h>
2+
3+
@class SentryEvent;
4+
5+
NS_ASSUME_NONNULL_BEGIN
6+
7+
@interface SentryEventSwiftHelper : NSObject
8+
9+
+ (void)setEventIdString:(NSString *)idString event:(SentryEvent *)event;
10+
11+
+ (NSString *)getEventIdString:(SentryEvent *)event;
12+
13+
@end
14+
15+
NS_ASSUME_NONNULL_END

Sources/Sentry/include/SentryPrivate.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#import "NSLocale+Sentry.h"
44
#import "SentryCrashExceptionApplicationHelper.h"
55
#import "SentryDispatchQueueWrapper.h"
6+
#import "SentryEventSwiftHelper.h"
67
#import "SentryNSDataUtils.h"
78
#import "SentryRandom.h"
89
#import "SentryTime.h"

Sources/Swift/Exports.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// This file is only for SPM, it allows all Swift
2+
// files to use code in SentryHeaders without needing
3+
// to add an import. This allows the same source to
4+
// compile in SPM and xcodebuild (which doesn't separate
5+
// ObjC into the SentryHeaders target)
6+
#if SENTRY_SWIFT_PACKAGE
7+
@_exported import SentryHeaders
8+
#endif

Sources/Swift/Integrations/SessionReplay/SentryReplayEvent.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ import Foundation
2828
self.segmentId = segmentId
2929

3030
super.init()
31-
self.eventId = eventId
31+
SentryEventSwiftHelper.setEventIdString(eventId.sentryIdString, event: self)
3232
self.type = "replay_video"
3333
}
3434

@@ -40,7 +40,7 @@ import Foundation
4040
var result = super.serialize()
4141
result["urls"] = urls
4242
result["replay_start_timestamp"] = replayStartTimestamp.timeIntervalSince1970
43-
result["replay_id"] = eventId.sentryIdString
43+
result["replay_id"] = SentryEventSwiftHelper.getEventIdString(self)
4444
result["segment_id"] = segmentId
4545
result["replay_type"] = replayType.toString()
4646
return result

Sources/Swift/Protocol/Codable/SentryBreadcrumbCodable.swift

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,17 @@
11
@_implementationOnly import _SentryPrivate
22
import Foundation
33

4-
extension Breadcrumb: Decodable {
4+
// See `develop-docs/README.md` for an explanation of this pattern.
5+
#if SENTRY_SWIFT_PACKAGE
6+
final class BreadcrumbDecodable: Breadcrumb {
7+
convenience public init(from decoder: any Decoder) throws {
8+
try self.init(decodedFrom: decoder)
9+
}
10+
}
11+
#else
12+
typealias BreadcrumbDecodable = Breadcrumb
13+
#endif
14+
extension BreadcrumbDecodable: Decodable {
515

616
private enum CodingKeys: String, CodingKey {
717
case level
@@ -13,7 +23,13 @@ extension Breadcrumb: Decodable {
1323
case origin
1424
}
1525

26+
#if !SENTRY_SWIFT_PACKAGE
1627
required convenience public init(from decoder: any Decoder) throws {
28+
try self.init(decodedFrom: decoder)
29+
}
30+
#endif
31+
32+
private convenience init(decodedFrom decoder: Decoder) throws {
1733
let container = try decoder.container(keyedBy: CodingKeys.self)
1834

1935
self.init()

Sources/Swift/Protocol/Codable/SentryDebugMetaCodable.swift

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,17 @@
11
@_implementationOnly import _SentryPrivate
22
import Foundation
33

4-
extension DebugMeta: Decodable {
4+
// See `develop-docs/README.md` for an explanation of this pattern.
5+
#if SENTRY_SWIFT_PACKAGE
6+
final class DebugMetaDecodable: DebugMeta {
7+
convenience public init(from decoder: any Decoder) throws {
8+
try self.init(decodedFrom: decoder)
9+
}
10+
}
11+
#else
12+
typealias DebugMetaDecodable = DebugMeta
13+
#endif
14+
extension DebugMetaDecodable: Decodable {
515

616
private enum CodingKeys: String, CodingKey {
717
case uuid
@@ -14,7 +24,13 @@ extension DebugMeta: Decodable {
1424
case codeFile = "code_file"
1525
}
1626

27+
#if !SENTRY_SWIFT_PACKAGE
1728
required convenience public init(from decoder: any Decoder) throws {
29+
try self.init(decodedFrom: decoder)
30+
}
31+
#endif
32+
33+
private convenience init(decodedFrom decoder: Decoder) throws {
1834
let container = try decoder.container(keyedBy: CodingKeys.self)
1935

2036
self.init()

0 commit comments

Comments
 (0)