Skip to content

Commit 9fafce9

Browse files
cdillard-NewRelicdiegomtz5mbruin-NR
authored
New Relic iOS agent Staging 7.6.2 (#601)
* triggering tests * Updated NRLoggerTests * Updated PersistentStoreTests * Updated NRMAURLSessionHeaderTrackingTests * Updated NRMASessionExclusivityWithoutDelegateTests * Updated all unit tests with known issues * Merge pull request #578 from newrelic/backport761develop Backport 7.6.1 develop * Improve touch movement smoothness * NR-508705 Background and foreground events match Android behavior (#579) * NR-508705 Changed the the foreground and background user actions to be consistent with Android and not be behind the gesture feature flag * Added the new event class to the persisted store classList. * Trying to update the yml to install the correct fastlane * NR-510109 changes to color reflection for SwiftUI MSR for iOS 26 (#583) * NR-510109 changes to color reflection for SwiftUI MSR for iOS 26 * Added the opacity to all views to fix the iOS 26 title blur issue * bump:s v 7.6.2 (#586) * NR-520409 changes to attributed text examination to minimize crash (#587) * Update cocoapods license to string "Apache License, Version 2.0" (#584) * NR-480518 added line numbers, line break, font weight, and kern to text in MSR (#588) * NR-480518 added line numbers, line break, font weight, and kern to text in MSR * Fix for tvos tests * Fix for hasher crash on older iOS versions (#591) * Nr 480854 Added shapes through SVG and drawing using images (#590) * NR-480854 working shapes for swiftUI * Added the SwiftUIDisplayList.Content.Value.drawing implementation too. * Fix for shape diffs * Added unit tests for UIShapeThingy * fix: add frameQueue when adding frame to process (#592) Co-authored-by: mbruin-NR <118208503+mbruin-NR@users.noreply.github.com> * restore:s logging sanity (#593) * fix: NR-518139 - restore iOS 15 by not allowing unmasking SwiftUI text in iOS 15 (#582) * fix: NR-518139 * fix: restore iOS 15 in project * add ios 15 override when traversing SwiftUI Text. iOS 15 SwiftUI text cannot be reliably unmasked so we mask it all. --------- Co-authored-by: mbruin-NR <118208503+mbruin-NR@users.noreply.github.com> * NR-502502 Added the discussed crash fix (#596) * NR-523372 added a check for off mode when a replay is paused so that we don't still send a harvest network request. (#597) * NR-523393: skip empty incrementalFrames (#598) * NR-522021 Changed capture to always put color views first so they are in the background (#599) * NR-522021 Changed capture to always put color views first so they are in the background * NR-522021 removed example code that wasn't needed --------- Co-authored-by: Diego Martinez <diegomartinez@newrelic.com> Co-authored-by: Diego Martinez <141683174+diegomtz5@users.noreply.github.com> Co-authored-by: mbruin-NR <118208503+mbruin-NR@users.noreply.github.com>
1 parent 85dd509 commit 9fafce9

File tree

73 files changed

+5288
-1197
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

73 files changed

+5288
-1197
lines changed

.github/workflows/main.yml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@ jobs:
3131
# curl https://raw.githubusercontent.com/Homebrew/homebrew-core/e92d2ae54954ebf485b484d8522104700b144fee/Formula/lcov.rb > lcov.rb
3232
# brew install ./lcov.rb
3333

34+
- name: Install Bundler 2.7.2
35+
run: gem install bundler:2.7.2
36+
3437
- name: Update gem
3538
run: bundle update
3639

@@ -57,6 +60,9 @@ jobs:
5760
# - name: Install lcov
5861
# run: brew install lcov
5962

63+
- name: Install Bundler 2.7.2
64+
run: gem install bundler:2.7.2
65+
6066
- name: Update gem
6167
run: bundle update
6268

@@ -83,6 +89,9 @@ jobs:
8389
# - name: Install lcov
8490
# run: brew install lcov
8591

92+
- name: Install Bundler 2.7.2
93+
run: gem install bundler:2.7.2
94+
8695
- name: Update gem
8796
run: bundle update
8897

@@ -139,6 +148,9 @@ jobs:
139148
# mkdir -p ~/Library/MobileDevice/Provisioning\ Profiles
140149
# cp $PP_PATH ~/Library/MobileDevice/Provisioning\ Profiles
141150
151+
- name: Install Bundler 2.7.2
152+
run: gem install bundler:2.7.2
153+
142154
- name: Update gem
143155
run: bundle update
144156

@@ -180,6 +192,9 @@ jobs:
180192
with:
181193
submodules: true
182194

195+
- name: Install Bundler 2.7.2
196+
run: gem install bundler:2.7.2
197+
183198
- name: Update gem
184199
run: bundle update
185200

Agent.xcodeproj/project.pbxproj

Lines changed: 104 additions & 50 deletions
Large diffs are not rendered by default.

Agent/Analytics/Constants.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ extern NSString *const kNRMA_RET_mobileRequestError;
4545
extern NSString *const kNRMA_RET_mobileCrash;
4646
extern NSString *const kNRMA_RET_mobileBreadcrumb;
4747
extern NSString *const kNRMA_RET_mobileUserAction;
48+
extern NSString *const kNRMA_RET_userAction;
4849

4950
extern NSString *const kNRMA_RA_methodExecuted;
5051
extern NSString *const kNRMA_RA_targetObject;

Agent/Analytics/Constants.m

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
NSString * const kNRMA_RET_mobileCrash = @"MobileCrash";
4848
NSString * const kNRMA_RET_mobileBreadcrumb = @"MobileBreadcrumb";
4949
NSString * const kNRMA_RET_mobileUserAction = @"MobileUserAction";
50+
NSString * const kNRMA_RET_userAction = @"UserAction";
5051

5152
//gesture attributes (not reserved)
5253
NSString * const kNRMA_RA_methodExecuted = @"methodExecuted";
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
//
2+
// NRMAUserActionEvent.h
3+
// Agent
4+
//
5+
// Created by Mike Bruin on 1/29/26.
6+
// Copyright © 2026 New Relic. All rights reserved.
7+
//
8+
9+
#import <Foundation/Foundation.h>
10+
11+
#import "NRMAMobileEvent.h"
12+
#import "AttributeValidatorProtocol.h"
13+
14+
NS_ASSUME_NONNULL_BEGIN
15+
16+
@interface NRMAUserActionEvent : NRMAMobileEvent
17+
@property (nonatomic, strong) NSString *category;
18+
19+
- (nonnull instancetype) initWithTimestamp:(NSTimeInterval)timestamp
20+
sessionElapsedTimeInSeconds:(NSTimeInterval)sessionElapsedTimeSeconds
21+
category:(NSString *) category
22+
withAttributeValidator:(__nullable id<AttributeValidatorProtocol>)attributeValidator;
23+
24+
@end
25+
26+
NS_ASSUME_NONNULL_END
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
//
2+
// NRMAUserActionEvent.m
3+
// Agent
4+
//
5+
// Created by Mike Bruin on 1/29/26.
6+
// Copyright © 2026 New Relic. All rights reserved.
7+
//
8+
9+
#import "NRMAUserActionEvent.h"
10+
#import "Constants.h"
11+
12+
static NSString* const kCategoryKey = @"Category";
13+
14+
@implementation NRMAUserActionEvent
15+
16+
+ (BOOL) supportsSecureCoding {
17+
return YES;
18+
}
19+
20+
- (nonnull instancetype) initWithTimestamp:(NSTimeInterval)timestamp
21+
sessionElapsedTimeInSeconds:(NSTimeInterval)sessionElapsedTimeSeconds
22+
category:(NSString *) category
23+
withAttributeValidator:(__nullable id<AttributeValidatorProtocol>)attributeValidator
24+
{
25+
self = [super initWithTimestamp:timestamp sessionElapsedTimeInSeconds:sessionElapsedTimeSeconds withAttributeValidator:attributeValidator];
26+
if (self) {
27+
self.eventType = kNRMA_RET_mobileUserAction;
28+
self.category = category;
29+
}
30+
31+
return self;
32+
}
33+
34+
- (id)JSONObject {
35+
NSDictionary *event = [super JSONObject];
36+
37+
NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithDictionary:event];
38+
dict[kNRMA_RA_category] = self.category;
39+
40+
return [NSDictionary dictionaryWithDictionary:dict];
41+
}
42+
43+
- (void)encodeWithCoder:(NSCoder *)coder {
44+
[super encodeWithCoder:coder];
45+
46+
[coder encodeObject:self.category forKey:kCategoryKey];
47+
}
48+
49+
- (nullable instancetype)initWithCoder:(nonnull NSCoder *)coder {
50+
self = [super initWithCoder:coder];
51+
if(self) {
52+
self.category = [coder decodeObjectOfClass:[NSString class] forKey:kCategoryKey];
53+
}
54+
55+
return self;
56+
}
57+
@end

Agent/Analytics/NRMAAnalytics.mm

Lines changed: 50 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#import "NRMACustomEvent.h"
2727
#import "NRMARequestEvent.h"
2828
#import "NRMAInteractionEvent.h"
29+
#import "NRMAUserActionEvent.h"
2930
#import "NRMAPayload.h"
3031
#import "NRMANetworkErrorEvent.h"
3132
#import "NRMASAM.h"
@@ -932,45 +933,64 @@ - (BOOL) checkBackgroundStatus {
932933

933934
- (BOOL)recordUserAction:(NRMAUserAction *)userAction {
934935
if (userAction == nil) { return NO; };
935-
936-
NRMACustomEvent* event = [[NRMACustomEvent alloc] initWithEventType:kNRMA_RET_mobileUserAction
937-
timestamp:[NRMAAnalytics currentTimeMillis]
938-
sessionElapsedTimeInSeconds:[[NSDate date] timeIntervalSinceDate:_sessionStartTime] withAttributeValidator:_attributeValidator];
936+
if([NRMAFlags shouldEnableNewEventSystem]){
937+
NRMAUserActionEvent* event = [[NRMAUserActionEvent alloc] initWithTimestamp:[NRMAAnalytics currentTimeMillis]
938+
sessionElapsedTimeInSeconds:[[NSDate date] timeIntervalSinceDate:_sessionStartTime]
939+
category:kNRMA_RET_userAction withAttributeValidator:_attributeValidator];
939940

940-
if (userAction.associatedMethod.length > 0) {
941-
[event addAttribute:kNRMA_RA_methodExecuted value:userAction.associatedMethod];
942-
}
941+
if (userAction.associatedMethod.length > 0) {
942+
[event addAttribute:kNRMA_RA_methodExecuted value:userAction.associatedMethod];
943+
}
943944

944-
if (userAction.associatedClass.length > 0) {
945-
[event addAttribute:kNRMA_RA_targetObject value:userAction.associatedClass];
946-
}
945+
if (userAction.associatedClass.length > 0) {
946+
[event addAttribute:kNRMA_RA_targetObject value:userAction.associatedClass];
947+
}
947948

948-
if (userAction.elementLabel.length > 0) {
949-
[event addAttribute:kNRMA_RA_label value:userAction.elementLabel];
950-
}
949+
if (userAction.elementLabel.length > 0) {
950+
[event addAttribute:kNRMA_RA_label value:userAction.elementLabel];
951+
}
951952

952-
if ((userAction.accessibilityId.length > 0)) {
953-
[event addAttribute:kNRMA_RA_accessibility value:userAction.accessibilityId];
954-
}
953+
if ((userAction.accessibilityId.length > 0)) {
954+
[event addAttribute:kNRMA_RA_accessibility value:userAction.accessibilityId];
955+
}
955956

956-
if ((userAction.interactionCoordinates.length > 0)) {
957-
[event addAttribute:kNRMA_RA_touchCoordinates value:userAction.interactionCoordinates];
958-
}
957+
if ((userAction.interactionCoordinates.length > 0)) {
958+
[event addAttribute:kNRMA_RA_touchCoordinates value:userAction.interactionCoordinates];
959+
}
959960

960-
if ((userAction.actionType.length > 0)) {
961-
[event addAttribute:kNMRA_RA_actionType value:userAction.actionType];
962-
}
961+
if ((userAction.actionType.length > 0)) {
962+
[event addAttribute:kNMRA_RA_actionType value:userAction.actionType];
963+
}
963964

964-
if ((userAction.elementFrame.length > 0)) {
965-
[event addAttribute:kNRMA_RA_frame value:userAction.elementFrame];
966-
}
965+
if ((userAction.elementFrame.length > 0)) {
966+
[event addAttribute:kNRMA_RA_frame value:userAction.elementFrame];
967+
}
967968

968-
NSString* deviceOrientation = [NewRelicInternalUtils deviceOrientation];
969-
if (deviceOrientation.length > 0) {
970-
[event addAttribute:kNRMA_RA_orientation value:deviceOrientation];
971-
}
969+
NSString* deviceOrientation = [NewRelicInternalUtils deviceOrientation];
970+
if (deviceOrientation.length > 0) {
971+
[event addAttribute:kNRMA_RA_orientation value:deviceOrientation];
972+
}
972973

973-
return [_eventManager addEvent:[event autorelease]];
974+
return [_eventManager addEvent:[event autorelease]];
975+
} else {
976+
try {
977+
return _analyticsController->addUserActionEvent(userAction.associatedMethod.UTF8String,
978+
userAction.associatedClass.UTF8String,
979+
userAction.elementLabel.UTF8String,
980+
userAction.accessibilityId.UTF8String,
981+
userAction.interactionCoordinates.UTF8String,
982+
userAction.actionType.UTF8String,
983+
userAction.elementFrame.UTF8String,
984+
[NewRelicInternalUtils deviceOrientation].UTF8String,
985+
[self checkOfflineStatus],
986+
[self checkBackgroundStatus]);
987+
} catch (std::exception &error) {
988+
NRLOG_AGENT_VERBOSE(@"Failed to add TrackedGesture: %s.", error.what());
989+
} catch (...) {
990+
NRLOG_AGENT_VERBOSE(@"Failed to add TrackedGesture: unknown error.");
991+
}
992+
}
993+
return false;
974994
}
975995

976996
- (BOOL) incrementSessionAttribute:(NSString*)name value:(NSNumber*)number
@@ -1123,14 +1143,6 @@ - (void) clearLastSessionsAnalytics {
11231143

11241144
- (void) sessionWillEnd {
11251145
_sessionWillEnd = YES;
1126-
1127-
if([NRMAFlags shouldEnableGestureInstrumentation])
1128-
{
1129-
NRMAUserAction* backgroundGesture = [NRMAUserActionBuilder buildWithBlock:^(NRMAUserActionBuilder *builder) {
1130-
[builder withActionType:kNRMAUserActionAppBackground];
1131-
}];
1132-
[[NewRelicAgentInternal sharedInstance].gestureFacade recordUserAction:backgroundGesture];
1133-
}
11341146

11351147
[self endSessionReusable];
11361148
}

Agent/Analytics/PersistentEventStore.m

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#import "NRMACustomEvent.h"
1515
#import "NRMARequestEvent.h"
1616
#import "NRMANetworkErrorEvent.h"
17+
#import "NRMAUserActionEvent.h"
1718

1819
@interface PersistentEventStore ()
1920
@property (nonatomic, strong) dispatch_queue_t writeQueue;
@@ -216,7 +217,7 @@ + (NSDictionary *)getLastSessionEventsFromFilename:(NSString *)filename {
216217

217218
+ (NSSet*) classList {
218219
NSSet *classList = [[NSSet alloc] initWithArray:@[ [NRMAPayload class],
219-
[NRMAInteractionEvent class],[NRMAMobileEvent class], [NRMASessionEvent class],[NRMACustomEvent class],[NRMARequestEvent class],[NRMANetworkErrorEvent class],
220+
[NRMAInteractionEvent class],[NRMAMobileEvent class], [NRMASessionEvent class],[NRMACustomEvent class],[NRMARequestEvent class],[NRMANetworkErrorEvent class], [NRMAUserActionEvent class],
220221
[NSMutableDictionary class],[NSDictionary class],[NSString class],[NSNumber class]]];
221222
return classList;
222223
}

Agent/General/NewRelicAgentInternal.m

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -617,16 +617,6 @@ - (void) onSessionStart {
617617
}
618618
}
619619

620-
if([NRMAFlags shouldEnableGestureInstrumentation])
621-
{
622-
self.gestureFacade = [[NRMAUserActionFacade alloc] initWithAnalyticsController:self.analyticsController];
623-
624-
NRMAUserAction* foregroundGesture = [NRMAUserActionBuilder buildWithBlock:^(NRMAUserActionBuilder *builder) {
625-
[builder withActionType:kNRMAUserActionAppLaunch];
626-
}];
627-
[self.gestureFacade recordUserAction:foregroundGesture];
628-
}
629-
630620
// appInstallMetricGenerator will receive the 'new install' notification
631621
// before the harvester is setup and before the task queue is set up.
632622
// by adding the appInstallMetricGenerator to the harvestAwareListener
@@ -792,6 +782,11 @@ - (void)applicationWillEnterForeground {
792782
*/
793783
[self sessionStartInitialization];
794784
didFireEnterBackground = NO;
785+
786+
NRMAUserActionBuilder* builder = [[NRMAUserActionBuilder alloc] init];
787+
[builder withActionType:kNRMAUserActionAppLaunch];
788+
NRMAUserAction* backgroundGesture = [builder build];
789+
[self.analyticsController recordUserAction:backgroundGesture];
795790
}
796791
}
797792
});
@@ -972,6 +967,11 @@ - (void) applicationDidEnterBackground {
972967
NSTimeInterval sessionLength = [[NSDate date] timeIntervalSinceDate:self.appSessionStartDate];
973968
#ifndef DISABLE_NRMA_EXCEPTION_WRAPPER
974969
@try {
970+
971+
NRMAUserActionBuilder* builder = [[NRMAUserActionBuilder alloc] init];
972+
[builder withActionType:kNRMAUserActionAppBackground];
973+
NRMAUserAction* backgroundGesture = [builder build];
974+
[self.analyticsController recordUserAction:backgroundGesture];
975975
#endif
976976
self.gestureFacade = nil;
977977
[self.analyticsController sessionWillEnd];

Agent/Network/NRMAHTTPUtilities.mm

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,11 +54,14 @@ + (NSArray*) trackedHeaderFields
5454
}
5555

5656
+ (NSMutableURLRequest*) addCrossProcessIdentifier:(NSURLRequest*)request {
57-
5857
NSMutableURLRequest* mutableRequest = [self makeMutable:request];
59-
60-
NSString* xprocess = [NRMAHarvestController configuration].cross_process_id;
61-
58+
NRMAHarvesterConfiguration *config = [NRMAHarvestController configuration];
59+
60+
if (!config) {
61+
return mutableRequest;
62+
}
63+
64+
NSString* xprocess = config.cross_process_id;
6265
if (xprocess.length) {
6366
[mutableRequest setValue:xprocess
6467
forHTTPHeaderField:NEW_RELIC_CROSS_PROCESS_ID_HEADER_KEY];

0 commit comments

Comments
 (0)