diff --git a/CHANGELOG.md b/CHANGELOG.md index 667ad620c..fc489cdeb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +### Fixes + +- The SDK now correctly syncs attachments to the native layer on iOS and macOS (with the Cococa backend) for non-crashing events. ([#2743](https://github.com/getsentry/sentry-unity/pull/2743)) + ### Dependencies - Bump CLI from v3.5.1 to v3.6.0 ([#2741](https://github.com/getsentry/sentry-unity/pull/2741)) diff --git a/package-dev/Plugins/iOS/SentryNativeBridge.m b/package-dev/Plugins/iOS/SentryNativeBridge.m index f9d643af3..0e5c27e84 100644 --- a/package-dev/Plugins/iOS/SentryNativeBridge.m +++ b/package-dev/Plugins/iOS/SentryNativeBridge.m @@ -255,6 +255,47 @@ void SentryNativeBridgeSetTrace(const char *traceId, const char *spanId) } } +void SentryNativeBridgeAddFileAttachment( + const char *path, const char *filename, const char *contentType) +{ + if (path == NULL) { + return; + } + + NSString *pathStr = [NSString stringWithUTF8String:path]; + NSString *filenameStr = _NSStringOrNil(filename); + NSString *contentTypeStr = _NSStringOrNil(contentType); + + SentryAttachment *attachment = [[SentryAttachment alloc] initWithPath:pathStr + filename:filenameStr + contentType:contentTypeStr]; + + [SentrySDK configureScope:^(SentryScope *scope) { [scope addAttachment:attachment]; }]; +} + +void SentryNativeBridgeAddByteAttachment( + const uint8_t *bytes, int32_t length, const char *filename, const char *contentType) +{ + if (bytes == NULL || filename == NULL) { + return; + } + + NSData *data = [NSData dataWithBytes:bytes length:length]; + NSString *filenameStr = [NSString stringWithUTF8String:filename]; + NSString *contentTypeStr = _NSStringOrNil(contentType); + + SentryAttachment *attachment = [[SentryAttachment alloc] initWithData:data + filename:filenameStr + contentType:contentTypeStr]; + + [SentrySDK configureScope:^(SentryScope *scope) { [scope addAttachment:attachment]; }]; +} + +void SentryNativeBridgeClearAttachments() +{ + [SentrySDK configureScope:^(SentryScope *scope) { [scope clearAttachments]; }]; +} + void SentryNativeBridgeWriteScope( // clang-format off // // const char *AppStartTime, // const char *AppBuildType, diff --git a/package-dev/Plugins/iOS/SentryNativeBridgeNoOp.m b/package-dev/Plugins/iOS/SentryNativeBridgeNoOp.m index f9eab6e99..8c6a513e7 100644 --- a/package-dev/Plugins/iOS/SentryNativeBridgeNoOp.m +++ b/package-dev/Plugins/iOS/SentryNativeBridgeNoOp.m @@ -34,6 +34,14 @@ void SentryNativeBridgeUnsetUser() { } void SentryNativeBridgeSetTrace(const char *traceId, const char *spanId) { } +void SentryNativeBridgeAddFileAttachment( + const char *path, const char *filename, const char *contentType) { } + +void SentryNativeBridgeAddByteAttachment( + const uint8_t *bytes, int32_t length, const char *filename, const char *contentType) { } + +void SentryNativeBridgeClearAttachments() { } + void SentryNativeBridgeWriteScope( // clang-format off // // const char *AppStartTime, // const char *AppBuildType, diff --git a/package-dev/Plugins/macOS/SentryNativeBridge.m b/package-dev/Plugins/macOS/SentryNativeBridge.m index 52270547f..0384cd0e5 100644 --- a/package-dev/Plugins/macOS/SentryNativeBridge.m +++ b/package-dev/Plugins/macOS/SentryNativeBridge.m @@ -47,6 +47,7 @@ static Class SentrySpanId; static Class PrivateSentrySDKOnly; static Class SentryHttpStatusCodeRange; +static Class SentryAttachment; #define LOAD_CLASS_OR_BREAK(name) \ name = (__bridge Class)dlsym(dylib, "OBJC_CLASS_$_" #name); \ @@ -90,6 +91,7 @@ int SentryNativeBridgeLoadLibrary() LOAD_CLASS_OR_BREAK(SentrySpanId) LOAD_CLASS_OR_BREAK(PrivateSentrySDKOnly) LOAD_CLASS_OR_BREAK(SentryHttpStatusCodeRange) + LOAD_CLASS_OR_BREAK(SentryAttachment) // everything above passed - mark as successfully loaded loadStatus = 1; @@ -357,12 +359,63 @@ void SentryNativeBridgeSetTrace(const char *traceId, const char *spanId) performSelector:@selector(initWithValue:) withObject:[NSString stringWithUTF8String:spanId]]; - [PrivateSentrySDKOnly - performSelector:@selector(setTrace:spanId:) - withObject:sentryTraceId + [PrivateSentrySDKOnly + performSelector:@selector(setTrace:spanId:) + withObject:sentryTraceId withObject:sentrySpanId]; } +void SentryNativeBridgeAddFileAttachment( + const char *path, const char *filename, const char *contentType) +{ + if (path == NULL) { + return; + } + + NSString *pathStr = [NSString stringWithUTF8String:path]; + NSString *filenameStr = _NSStringOrNil(filename); + NSString *contentTypeStr = _NSStringOrNil(contentType); + + // initWithPath:filename:contentType: - use objc_msgSend directly for the multi-arg init + id attachment = ((id (*)(id, SEL, NSString *, NSString *, NSString *))objc_msgSend)( + [SentryAttachment alloc], @selector(initWithPath:filename:contentType:), pathStr, + filenameStr, contentTypeStr); + if (!attachment) { + return; + } + + SentryConfigureScope( + ^(id scope) { [scope performSelector:@selector(addAttachment:) withObject:attachment]; }); +} + +void SentryNativeBridgeAddByteAttachment( + const uint8_t *bytes, int32_t length, const char *filename, const char *contentType) +{ + if (bytes == NULL || filename == NULL) { + return; + } + + NSData *data = [NSData dataWithBytes:bytes length:length]; + NSString *filenameStr = [NSString stringWithUTF8String:filename]; + NSString *contentTypeStr = _NSStringOrNil(contentType); + + // initWithData:filename:contentType: - use objc_msgSend directly for the multi-arg init + id attachment = ((id (*)(id, SEL, NSData *, NSString *, NSString *))objc_msgSend)( + [SentryAttachment alloc], @selector(initWithData:filename:contentType:), data, filenameStr, + contentTypeStr); + if (!attachment) { + return; + } + + SentryConfigureScope( + ^(id scope) { [scope performSelector:@selector(addAttachment:) withObject:attachment]; }); +} + +void SentryNativeBridgeClearAttachments() +{ + SentryConfigureScope(^(id scope) { [scope performSelector:@selector(clearAttachments)]; }); +} + void SentryNativeBridgeWriteScope( // clang-format off // // const char *AppStartTime, // const char *AppBuildType, diff --git a/src/Sentry.Unity.iOS/NativeScopeObserver.cs b/src/Sentry.Unity.iOS/NativeScopeObserver.cs index 1bedc6b92..57f286cce 100644 --- a/src/Sentry.Unity.iOS/NativeScopeObserver.cs +++ b/src/Sentry.Unity.iOS/NativeScopeObserver.cs @@ -55,20 +55,14 @@ public override void SetUserImpl(SentryUser user) => public override void SetTraceImpl(SentryId traceId, SpanId spanId) => SentryCocoaBridgeProxy.SetTrace(traceId.ToString(), spanId.ToString()); - public override void AddFileAttachmentImpl(string filePath, string fileName, string? contentType) - { - // iOS/macOS attachment sync to sentry-cocoa is not yet supported. - } + public override void AddFileAttachmentImpl(string filePath, string fileName, string? contentType) => + SentryCocoaBridgeProxy.AddFileAttachment(filePath, fileName, contentType); - public override void AddByteAttachmentImpl(byte[] data, string fileName, string? contentType) - { - // iOS/macOS attachment sync to sentry-cocoa is not yet supported. - } + public override void AddByteAttachmentImpl(byte[] data, string fileName, string? contentType) => + SentryCocoaBridgeProxy.AddByteAttachment(data, data.Length, fileName, contentType); - public override void ClearAttachmentsImpl() - { - // iOS/macOS attachment sync to sentry-cocoa is not yet supported. - } + public override void ClearAttachmentsImpl() => + SentryCocoaBridgeProxy.ClearAttachments(); internal static string GetTimestamp(DateTimeOffset timestamp) => // "o": Using ISO 8601 to make sure the timestamp makes it to the bridge correctly. diff --git a/src/Sentry.Unity.iOS/SentryCocoaBridgeProxy.cs b/src/Sentry.Unity.iOS/SentryCocoaBridgeProxy.cs index 70055b56e..03cfcc120 100644 --- a/src/Sentry.Unity.iOS/SentryCocoaBridgeProxy.cs +++ b/src/Sentry.Unity.iOS/SentryCocoaBridgeProxy.cs @@ -151,4 +151,13 @@ public static extern void AddBreadcrumb(string timestamp, string? message, strin [DllImport("__Internal", EntryPoint = "SentryNativeBridgeSetTrace")] public static extern void SetTrace(string traceId, string spanId); + + [DllImport("__Internal", EntryPoint = "SentryNativeBridgeAddFileAttachment")] + public static extern void AddFileAttachment(string path, string fileName, string? contentType); + + [DllImport("__Internal", EntryPoint = "SentryNativeBridgeAddByteAttachment")] + public static extern void AddByteAttachment(byte[] bytes, int length, string fileName, string? contentType); + + [DllImport("__Internal", EntryPoint = "SentryNativeBridgeClearAttachments")] + public static extern void ClearAttachments(); }