Skip to content

Commit

Permalink
Merge eae7f93 into cd816d5
Browse files Browse the repository at this point in the history
  • Loading branch information
brustolin authored Feb 14, 2024
2 parents cd816d5 + eae7f93 commit 91877f9
Show file tree
Hide file tree
Showing 25 changed files with 543 additions and 9 deletions.
3 changes: 3 additions & 0 deletions Samples/iOS-Swift/iOS-Swift/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>

<key>NSFaceIDUsageDescription</key>
<string>$(PRODUCT_NAME) Authentication with TouchId or FaceID for testing purposes of the Sentry Cocoa SDK.</string>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import CoreLocation
import LocalAuthentication
import UIKit

class PermissionsViewController: UIViewController {
Expand All @@ -18,9 +19,16 @@ class PermissionsViewController: UIViewController {
button.addTarget(self, action: #selector(requestLocationPermission), for: .touchUpInside)
return button
}()

private lazy var biometricButton: UIButton = {
let button = UIButton(type: .system)
button.setTitle("Request Biometric Permission", for: .normal)
button.addTarget(self, action: #selector(requestBiometricPermission), for: .touchUpInside)
return button
}()

private lazy var stackView: UIStackView = {
let stackView = UIStackView(arrangedSubviews: [pushPermissionButton, locationPermissionButton])
let stackView = UIStackView(arrangedSubviews: [pushPermissionButton, locationPermissionButton, biometricButton])
stackView.axis = .vertical
stackView.spacing = 10
stackView.alignment = .center
Expand Down Expand Up @@ -71,6 +79,34 @@ class PermissionsViewController: UIViewController {
print(granted)
}
}

@objc func requestBiometricPermission() {
let context = LAContext()
var error: NSError?

if context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &error) {
let reason = "Identify yourself!"

context.evaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, localizedReason: reason) { success, _ in

DispatchQueue.main.async {
if success {
let crumb = Breadcrumb()
crumb.message = "Biometry success"
SentrySDK.addBreadcrumb(crumb)
} else {
let crumb = Breadcrumb()
crumb.message = "Biometry failure"
SentrySDK.addBreadcrumb(crumb)
}
}
}
} else {
let ac = UIAlertController(title: "No biometry", message: "Couldn't access biometry.", preferredStyle: .alert)
ac.addAction(UIAlertAction(title: "OK", style: .default))
self.present(ac, animated: true)
}
}
}

extension PermissionsViewController: CLLocationManagerDelegate {
Expand Down
44 changes: 44 additions & 0 deletions Sentry.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

50 changes: 47 additions & 3 deletions Sources/Sentry/SentryClient.m
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,12 @@
#import "SentryOptions+Private.h"
#import "SentryPropagationContext.h"
#import "SentryRandom.h"
#import "SentryReplayEnvelopeItemHeader.h"
#import "SentryReplayEvent.h"
#import "SentryReplayRecording.h"
#import "SentrySDK+Private.h"
#import "SentryScope+Private.h"
#import "SentrySerialization.h"
#import "SentrySession.h"
#import "SentryStacktraceBuilder.h"
#import "SentrySwift.h"
Expand Down Expand Up @@ -472,13 +476,53 @@ - (void)captureSession:(SentrySession *)session
}

SentryEnvelopeItem *item = [[SentryEnvelopeItem alloc] initWithSession:session];
SentryEnvelopeHeader *envelopeHeader = [[SentryEnvelopeHeader alloc] initWithId:nil
traceContext:nil];
SentryEnvelope *envelope = [[SentryEnvelope alloc] initWithHeader:envelopeHeader
SentryEnvelope *envelope = [[SentryEnvelope alloc] initWithHeader:[SentryEnvelopeHeader empty]
singleItem:item];
[self captureEnvelope:envelope];
}

- (void)captureReplayEvent:(SentryReplayEvent *)replayEvent
replayRecording:(SentryReplayRecording *)replayRecording
video:(NSURL *)videoURL
{
replayEvent = (SentryReplayEvent *)[self prepareEvent:replayEvent
withScope:[[SentryScope alloc] init]
alwaysAttachStacktrace:NO];

if (replayEvent == nil) {
return;
} else if (![replayEvent isKindOfClass:SentryReplayEvent.class]) {
SENTRY_LOG_DEBUG(@"The event preprocessor didn't update the replay event in place. The "
@"replay was discarded.");
return;
}

// breadcrumbs for replay will be send with ReplayRecording
replayEvent.breadcrumbs = nil;

SentryEnvelopeItem *eventEnvelopeItem = [[SentryEnvelopeItem alloc] initWithEvent:replayEvent];

NSData *recording = [SentrySerialization dataWithJSONObject:[replayRecording serialize]];
SentryEnvelopeItem *recordingEnvelopeItem = [[SentryEnvelopeItem alloc]
initWithHeader:[SentryReplayEnvelopeItemHeader
replayRecordingHeaderWithSegmentId:replayRecording.segmentId
length:recording.length]
data:recording];

NSData *video = [NSData dataWithContentsOfURL:videoURL];
SentryEnvelopeItem *videoEnvelopeItem = [[SentryEnvelopeItem alloc]
initWithHeader:[SentryReplayEnvelopeItemHeader
replayVideoHeaderWithSegmentId:replayRecording.segmentId
length:video.length]
data:video];

SentryEnvelope *envelope = [[SentryEnvelope alloc]
initWithHeader:[SentryEnvelopeHeader empty]
items:@[ eventEnvelopeItem, recordingEnvelopeItem, videoEnvelopeItem ]];

[self captureEnvelope:envelope];
}

- (void)captureEnvelope:(SentryEnvelope *)envelope
{
if ([self isDisabled]) {
Expand Down
5 changes: 5 additions & 0 deletions Sources/Sentry/SentryDateUtil.m
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,11 @@ + (NSDate *_Nullable)getMaximumDate:(NSDate *_Nullable)first andOther:(NSDate *_
}
}

+ (long)javascriptDate:(NSDate *)date
{
return (NSInteger)([date timeIntervalSince1970] * 1000);
}

@end

NS_ASSUME_NONNULL_END
5 changes: 5 additions & 0 deletions Sources/Sentry/SentryEnvelope.m
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,11 @@ - (instancetype)initWithId:(nullable SentryId *)eventId
return self;
}

+ (instancetype)empty
{
return [[SentryEnvelopeHeader alloc] initWithId:nil traceContext:nil];
}

@end

@implementation SentryEnvelopeItem
Expand Down
35 changes: 35 additions & 0 deletions Sources/Sentry/SentryReplayEnvelopeItemHeader.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#import "SentryReplayEnvelopeItemHeader.h"
#import "SentryEnvelopeItemType.h"

@implementation SentryReplayEnvelopeItemHeader

- (instancetype)initWithType:(NSString *)type
segmentId:(NSInteger)segmentId
length:(NSUInteger)length
{
if (self = [super initWithType:type length:length]) {
self.segmentId = segmentId;
}
return self;
}

+ (instancetype)replayRecordingHeaderWithSegmentId:(NSInteger)segmentId length:(NSUInteger)length
{
return [[self alloc] initWithType:SentryEnvelopeItemTypeReplayRecording
segmentId:segmentId
length:length];
}

+ (instancetype)replayVideoHeaderWithSegmentId:(NSInteger)segmentId length:(NSUInteger)length
{
return [[self alloc] initWithType:SentryEnvelopeItemTypeReplayVideo
segmentId:segmentId
length:length];
}

- (NSDictionary *)serialize
{
return @{ @"type" : self.type, @"length" : @(self.length), @"segment_id" : @(self.segmentId) };
}

@end
28 changes: 28 additions & 0 deletions Sources/Sentry/SentryReplayEvent.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#import "SentryReplayEvent.h"
#import "SentryDateUtil.h"
#import "SentryId.h"

@implementation SentryReplayEvent

- (NSDictionary *)serialize
{
NSMutableDictionary *result = [[super serialize] mutableCopy];

NSMutableArray *trace_ids = [NSMutableArray array];

for (SentryId *traceId in self.traceIds) {
[trace_ids addObject:traceId.sentryIdString];
}

result[@"urls"] = self.urls;
result[@"replay_start_timestamp"] =
@([SentryDateUtil javascriptDate:self.replayStartTimestamp]);
result[@"trace_ids"] = trace_ids;
result[@"replay_id"] = self.replayId.sentryIdString;
result[@"segment_id"] = @(self.segmentId);
result[@"replay_type"] = @"buffer";

return result;
}

@end
64 changes: 64 additions & 0 deletions Sources/Sentry/SentryReplayRecording.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
#import "SentryReplayRecording.h"
#import "SentryDateUtil.h"

@implementation SentryReplayRecording

- (instancetype)initWithSegmentId:(NSInteger)segmentId
size:(NSInteger)size
start:(NSDate *)start
duration:(NSTimeInterval)duration
frameCount:(NSInteger)frameCount
frameRate:(NSInteger)frameRate
height:(NSInteger)height
width:(NSInteger)width
{
if (self = [super init]) {
self.segmentId = segmentId;
self.size = size;
self.start = start;
self.duration = duration;
self.frameCount = frameCount;
self.frameRate = frameRate;
self.height = height;
self.width = width;
}
return self;
}

- (nonnull NSArray<NSDictionary<NSString *, id> *> *)serialize
{

long timestamp = [SentryDateUtil javascriptDate:self.start];

NSDictionary *metaInfo = @{
@"type" : @4,
@"timestamp" : @(timestamp),
@"data" : @ { @"href" : @"", @"height" : @(self.height), @"width" : @(self.width) }
};

NSDictionary *recordingInfo = @{
@"type" : @5,
@"timestamp" : @(timestamp),
@"data" : @ {
@"tag" : @"video",
@"payload" : @ {
@"segmentId" : @(self.segmentId),
@"size" : @(self.size),
@"duration" : @(self.duration),
@"encoding" : @"h264",
@"container" : @"mp4",
@"height" : @(self.height),
@"width" : @(self.width),
@"frameCount" : @(self.frameCount),
@"frameRateType" : @"constant",
@"frameRate" : @(self.frameRate),
@"left" : @0,
@"top" : @0,
}
}
};

return @[ metaInfo, recordingInfo ];
}

@end
6 changes: 3 additions & 3 deletions Sources/Sentry/SentrySerialization.m
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,15 @@

@implementation SentrySerialization

+ (NSData *_Nullable)dataWithJSONObject:(NSDictionary *)dictionary
+ (NSData *_Nullable)dataWithJSONObject:(id)jsonObject
{
if (![NSJSONSerialization isValidJSONObject:dictionary]) {
if (![NSJSONSerialization isValidJSONObject:jsonObject]) {
SENTRY_LOG_ERROR(@"Dictionary is not a valid JSON object.");
return nil;
}

NSError *error = nil;
NSData *data = [NSJSONSerialization dataWithJSONObject:dictionary options:0 error:&error];
NSData *data = [NSJSONSerialization dataWithJSONObject:jsonObject options:0 error:&error];
if (error) {
SENTRY_LOG_ERROR(@"Internal error while serializing JSON: %@", error);
}
Expand Down
2 changes: 2 additions & 0 deletions Sources/Sentry/include/HybridPublic/SentryEnvelope.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ SENTRY_NO_INIT
*/
@property (nullable, nonatomic, copy) NSDate *sentAt;

+ (instancetype)empty;

@end

@interface SentryEnvelopeItem : NSObject
Expand Down
2 changes: 2 additions & 0 deletions Sources/Sentry/include/HybridPublic/SentryEnvelopeItemType.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,5 @@ static NSString *const SentryEnvelopeItemTypeTransaction = @"transaction";
static NSString *const SentryEnvelopeItemTypeAttachment = @"attachment";
static NSString *const SentryEnvelopeItemTypeClientReport = @"client_report";
static NSString *const SentryEnvelopeItemTypeProfile = @"profile";
static NSString *const SentryEnvelopeItemTypeReplayVideo = @"replay_video";
static NSString *const SentryEnvelopeItemTypeReplayRecording = @"replay_recording";
6 changes: 5 additions & 1 deletion Sources/Sentry/include/SentryClient+Private.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
#import "SentryDiscardReason.h"

@class SentrySession, SentryEnvelopeItem, SentryId, SentryAttachment, SentryThreadInspector,
SentryEnvelope;
SentryReplayEvent, SentryReplayRecording, SentryEnvelope;

NS_ASSUME_NONNULL_BEGIN

Expand Down Expand Up @@ -42,6 +42,10 @@ SentryClient ()
additionalEnvelopeItems:(NSArray<SentryEnvelopeItem *> *)additionalEnvelopeItems
NS_SWIFT_NAME(capture(event:scope:additionalEnvelopeItems:));

- (void)captureReplayEvent:(SentryReplayEvent *)replayEvent
replayRecording:(SentryReplayRecording *)replayRecording
video:(NSURL *)videoURL;

- (void)captureSession:(SentrySession *)session NS_SWIFT_NAME(capture(session:));

/**
Expand Down
2 changes: 2 additions & 0 deletions Sources/Sentry/include/SentryDateUtil.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ NS_SWIFT_NAME(DateUtil)

+ (NSDate *_Nullable)getMaximumDate:(NSDate *_Nullable)first andOther:(NSDate *_Nullable)second;

+ (long)javascriptDate:(NSDate *)date;

@end

NS_ASSUME_NONNULL_END
20 changes: 20 additions & 0 deletions Sources/Sentry/include/SentryReplayEnvelopeItemHeader.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#import "SentryEnvelopeItemHeader.h"
#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface SentryReplayEnvelopeItemHeader : SentryEnvelopeItemHeader

@property (nonatomic) NSInteger segmentId;

- (instancetype)initWithType:(NSString *)type
segmentId:(NSInteger)segmentId
length:(NSUInteger)length;

+ (instancetype)replayRecordingHeaderWithSegmentId:(NSInteger)segmentId length:(NSUInteger)length;

+ (instancetype)replayVideoHeaderWithSegmentId:(NSInteger)segmentId length:(NSUInteger)length;

@end

NS_ASSUME_NONNULL_END
Loading

0 comments on commit 91877f9

Please sign in to comment.