Skip to content

Commit fad0397

Browse files
authored
Merge pull request #421 from Countly/user_props
Refactor user properties
2 parents ed8992d + 224446f commit fad0397

16 files changed

Lines changed: 999 additions & 251 deletions

CHANGELOG.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,25 @@
11
## XX.XX.XX
2+
* Added a new user properties functions on `CountlyUserDetails`:
3+
* `setProperty:value:` for setting a single predefined or custom user property.
4+
* `setProperties:` for setting multiple predefined and custom properties in one call.
5+
* Added `providedUserProperties` to `CountlyConfig` to set initial user properties that are applied and saved automatically right after `start`.
6+
* Added `setMaxValueSizePicture:` to `CountlySDKLimitsConfig` to control the maximum size of picture URLs and picture paths independently of other value limits (default 4096).
7+
* Improved `$push` / `$pull` / `$addToSet` wire format: values are now always sent as arrays so multiple consecutive calls on the same key accumulate correctly.
28
* Updated resolution extraction to accommodate iOS 26 deprecations.
39

10+
* Mitigated a race condition in the request queue that could drop or duplicate requests.
411
* Mitigated an issue where non-queued requests were affected from request timeout settings.
512
* Mitigated a race condition for tests in the request queue that could drop or duplicate requests.
613
* Mitigated an issue where server config defaults overrode user-provided SDK limits.
714
* Mitigated an issue where invalid or unknown `sdkBehaviorSettings` keys were persisted.
815
* Mitigated an issue where listing-filter conflicts cleared keys across unrelated categories.
916
* Mitigated an issue where consent could be sent twice during initialization.
1017

18+
* Deprecated the direct property setters on `CountlyUserDetails`: `name`, `username`, `email`, `organization`, `phone`, `gender`, `pictureURL`, `pictureLocalPath`, `birthYear`, `custom`. Use `setProperty:value:` or `setProperties:` instead.
19+
* Deprecated `set:value:`, `set:numberValue:`, `set:boolValue:` on `CountlyUserDetails`. Use `setProperty:value:` instead.
20+
* Deprecated `unSet:` on `CountlyUserDetails`. Use `setProperty:value:` with an empty string `@""` to clear a property on the server.
21+
* Deprecated the `+ user` class accessor on `Countly`. Use `Countly.sharedInstance.userProfile` instead.
22+
1123
## 26.1.1
1224
* Added POST method support for contents.
1325
* Added robust resource loading checks before displaying content

Countly.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -602,7 +602,7 @@ NS_ASSUME_NONNULL_BEGIN
602602
* Returns @c CountlyUserDetails singleton to be used throughout the app.
603603
* @return The shared @c CountlyUserDetails object
604604
*/
605-
+ (CountlyUserDetails *)user;
605+
+ (CountlyUserDetails *)user DEPRECATED_MSG_ATTRIBUTE("Use -userProfile via Countly.sharedInstance instead (e.g., Countly.sharedInstance.userProfile).");
606606

607607

608608

@@ -705,6 +705,8 @@ NS_ASSUME_NONNULL_BEGIN
705705
* @discussion Feedback widget interface for developer to interact with SDK.
706706
*/
707707
- (CountlyFeedbacks *) feedback;
708+
709+
- (CountlyUserDetails *) userProfile;
708710
#endif
709711

710712

Countly.m

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ - (void)startWithConfig:(CountlyConfig *)config
111111

112112
CountlyCommon.sharedInstance.maxKeyLength = config.sdkInternalLimits.getMaxKeyLength;
113113
CountlyCommon.sharedInstance.maxValueLength = config.sdkInternalLimits.getMaxValueSize;
114+
CountlyCommon.sharedInstance.maxValueLengthPicture = config.sdkInternalLimits.getMaxValueSizePicture;
114115
CountlyCommon.sharedInstance.maxSegmentationValues = config.sdkInternalLimits.getMaxSegmentationValues;
115116

116117
// For backward compatibility, deprecated values are only set incase new values are not provided using sdkInternalLimits interface
@@ -165,8 +166,13 @@ - (void)startWithConfig:(CountlyConfig *)config
165166

166167
NSDictionary* customMetricsTruncated = [config.customMetrics cly_truncated:@"Custom metric"];
167168
CountlyDeviceInfo.sharedInstance.customMetrics = [customMetricsTruncated cly_limited:@"Custom metric"];
168-
169-
[Countly.user save];
169+
170+
if (config.providedUserProperties.count > 0) {
171+
CLY_LOG_I(@"%s applying providedUserProperties at init [%lu]", __FUNCTION__, (unsigned long)config.providedUserProperties.count);
172+
[Countly.sharedInstance.userProfile setProperties:config.providedUserProperties];
173+
}
174+
175+
[Countly.sharedInstance.userProfile save];
170176
// If something added related to server config, make sure to check CountlyServerConfig.notifySdkConfigChange
171177
[CountlyServerConfig.sharedInstance fetchServerConfig:config];
172178

@@ -1613,4 +1619,9 @@ - (CountlyRemoteConfig *) remoteConfig {
16131619
return CountlyRemoteConfig.sharedInstance;
16141620
}
16151621

1622+
- (CountlyUserDetails *) userProfile
1623+
{
1624+
return CountlyUserDetails.sharedInstance;
1625+
}
1626+
16161627
@end

CountlyCommon.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ extern NSString* const kCountlySDKName;
9696

9797
@property (nonatomic) NSUInteger maxKeyLength;
9898
@property (nonatomic) NSUInteger maxValueLength;
99+
@property (nonatomic) NSUInteger maxValueLengthPicture;
99100
@property (nonatomic) NSUInteger maxSegmentationValues;
100101

101102
void CountlyInternalLog(CLYInternalLogLevel level, NSString *format, ...) NS_FORMAT_FUNCTION(2, 3);
@@ -157,6 +158,7 @@ void CountlyPrint(NSString *stringToPrint);
157158
- (NSString *)cly_valueForQueryStringKey:(NSString *)key;
158159
- (NSString *)cly_truncatedKey:(NSString *)explanation;
159160
- (NSString *)cly_truncatedValue:(NSString *)explanation;
161+
- (NSString *)cly_truncatedPictureValue:(NSString *)explanation;
160162
@end
161163

162164
@interface NSArray (Countly)

CountlyCommon.m

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ - (void)resetInstance {
7373
_hasFinishedInit = false;
7474
_maxKeyLength = kCountlyMaxKeyLength;
7575
_maxValueLength = kCountlyMaxValueSize;
76+
_maxValueLengthPicture = kCountlyMaxValueSizePicture;
7677
_maxSegmentationValues = kCountlyMaxSegmentationValues;
7778
onceToken = 0;
7879
s_sharedInstance = nil;
@@ -648,6 +649,17 @@ - (NSString *)cly_truncatedKey:(NSString *)explanation
648649
return self;
649650
}
650651

652+
- (NSString *)cly_truncatedPictureValue:(NSString *)explanation
653+
{
654+
NSUInteger limit = CountlyCommon.sharedInstance.maxValueLengthPicture;
655+
if (self.length > limit)
656+
{
657+
CLY_LOG_W(@"%@ length is more than the picture limit (%ld)! So, it will be truncated: %@.", explanation, (long)limit, self);
658+
return [self substringToIndex:limit];
659+
}
660+
return self;
661+
}
662+
651663
- (NSString *)cly_truncatedValue:(NSString *)explanation
652664
{
653665
if (self.length > CountlyCommon.sharedInstance.maxValueLength)
@@ -738,7 +750,7 @@ - (NSMutableDictionary *) cly_filterSupportedDataTypes
738750

739751
if ([value isKindOfClass:[NSNumber class]] ||
740752
[value isKindOfClass:[NSString class]] ||
741-
([value isKindOfClass:[NSArray class]] && (value = [value cly_filterSupportedDataTypes]))) {
753+
([value isKindOfClass:[NSArray class]] && (value = [(NSArray *)value cly_filterSupportedDataTypes]))) {
742754
[filteredDictionary setObject:value forKey:key];
743755
} else {
744756
CLY_LOG_W(@"%s, Removed invalid type for key %@: %@", __FUNCTION__, key, [value class]);

CountlyConfig.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -440,6 +440,14 @@ typedef enum : NSUInteger
440440
*/
441441
- (CountlySDKLimitsConfig *)sdkInternalLimits;
442442

443+
/**
444+
* User properties to set automatically right after SDK init.
445+
* @discussion Equivalent to calling @c [Countly.user setProperties:data] followed by @c save once the SDK has started.
446+
* @discussion Keys matching predefined fields (name, username, email, organization, phone, gender, picture, picturePath, byear)
447+
* are routed to the corresponding top-level user-detail field. All other keys are stored as custom user properties.
448+
*/
449+
@property (nonatomic, copy) NSDictionary<NSString *, id> * _Nullable providedUserProperties;
450+
443451
/**
444452
* For sending all requests using HTTP POST method.
445453
* @discussion If set, all requests will be sent using HTTP POST method. Otherwise; only the requests with a file upload or data size more than 2048 bytes will be sent using HTTP POST method.

CountlyConnectionManager.m

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -612,9 +612,9 @@ - (void)beginSession
612612
}
613613
#endif
614614

615-
if([Countly.user hasUnsyncedChanges])
615+
if ([CountlyUserDetails.sharedInstance hasUnsyncedChanges])
616616
{
617-
[Countly.user save];
617+
[CountlyUserDetails.sharedInstance save];
618618
}
619619

620620
isSessionStarted = YES;
@@ -655,9 +655,9 @@ - (void)updateSession
655655
return;
656656
}
657657

658-
if([Countly.user hasUnsyncedChanges])
658+
if ([CountlyUserDetails.sharedInstance hasUnsyncedChanges])
659659
{
660-
[Countly.user save];
660+
[CountlyUserDetails.sharedInstance save];
661661
}
662662

663663
NSString* queryString = [[self queryEssentials] stringByAppendingFormat:@"&%@=%d",
@@ -697,9 +697,9 @@ - (void)endSession
697697

698698
- (void)sendEventsWithSaveIfNeeded
699699
{
700-
if([Countly.user hasUnsyncedChanges])
700+
if ([CountlyUserDetails.sharedInstance hasUnsyncedChanges])
701701
{
702-
[Countly.user save];
702+
[CountlyUserDetails.sharedInstance save];
703703
}
704704
else
705705
{

CountlyConsentManager.m

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -309,7 +309,7 @@ - (void)setConsentForUserDetails:(BOOL)consentForUserDetails
309309
{
310310
CLY_LOG_D(@"Consent for UserDetails is given.");
311311
[CountlyCommon.sharedInstance recordOrientation];
312-
[Countly.user save];
312+
[CountlyUserDetails.sharedInstance save];
313313
}
314314
else
315315
{

CountlyPersistency.m

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -271,9 +271,9 @@ - (void)recordEvent:(CountlyEvent *)event callback:(CLYRequestCallback)callback
271271
{
272272
@synchronized (self.recordedEvents)
273273
{
274-
if([Countly.user hasUnsyncedChanges])
274+
if ([CountlyUserDetails.sharedInstance hasUnsyncedChanges])
275275
{
276-
[Countly.user save];
276+
[CountlyUserDetails.sharedInstance save];
277277
}
278278

279279
[self.recordedEvents addObject:event];

CountlySDKLimitsConfig.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
extern const NSUInteger kCountlyMaxKeyLength;
1111
extern const NSUInteger kCountlyMaxValueSize;
12+
extern const NSUInteger kCountlyMaxValueSizePicture;
1213
extern const NSUInteger kCountlyMaxBreadcrumbCount;
1314
extern const NSUInteger kCountlyMaxSegmentationValues;
1415
extern const NSUInteger kCountlyMaxStackTraceLineLength;
@@ -19,13 +20,15 @@ extern const NSUInteger kCountlyMaxStackTraceLinesPerThread;
1920

2021
- (void)setMaxKeyLength:(NSUInteger)maxKeyLength;
2122
- (void)setMaxValueSize:(NSUInteger)maxValueSize;
23+
- (void)setMaxValueSizePicture:(NSUInteger)maxValueSizePicture;
2224
- (void)setMaxBreadcrumbCount:(NSUInteger)maxBreadcrumbCount;
2325
- (void)setMaxSegmentationValues:(NSUInteger)maxSegmentationValues;
2426
- (void)setMaxStackTraceLineLength:(NSUInteger)maxStackTraceLineLength;
2527
- (void)setMaxStackTraceLinesPerThread:(NSUInteger)maxStackTraceLinesPerThread;
2628

2729
- (NSUInteger)getMaxKeyLength;
2830
- (NSUInteger)getMaxValueSize;
31+
- (NSUInteger)getMaxValueSizePicture;
2932
- (NSUInteger)getMaxBreadcrumbCount;
3033
- (NSUInteger)getMaxSegmentationValues;
3134
- (NSUInteger)getMaxStackTraceLineLength;

0 commit comments

Comments
 (0)