Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Liammeier/fence 1220 flush replays in more sdk lifecycle methods ios #274

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion RadarSDK.podspec
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = 'RadarSDK'
s.version = '3.8.6'
s.version = '3.8.7'
s.summary = 'iOS SDK for Radar, the leading geofencing and location tracking platform'
s.homepage = 'https://radar.com'
s.author = { 'Radar Labs, Inc.' => '[email protected]' }
Expand Down
4 changes: 2 additions & 2 deletions RadarSDK.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -973,7 +973,7 @@
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
MARKETING_VERSION = 3.8.6;
MARKETING_VERSION = 3.8.7;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
ONLY_ACTIVE_ARCH = YES;
Expand Down Expand Up @@ -1031,7 +1031,7 @@
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
MARKETING_VERSION = 3.8.6;
MARKETING_VERSION = 3.8.7;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
OTHER_CFLAGS = "-fembed-bitcode";
Expand Down
2 changes: 2 additions & 0 deletions RadarSDK/Include/Radar.h
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,8 @@ typedef void (^_Nullable RadarBeaconCompletionHandler)(RadarStatus status, NSArr
*/
typedef void (^_Nullable RadarTrackCompletionHandler)(RadarStatus status, CLLocation *_Nullable location, NSArray<RadarEvent *> *_Nullable events, RadarUser *_Nullable user);

typedef void (^_Nullable RadarFlushReplaysCompletionHandler)(RadarStatus status, NSDictionary *_Nullable res);

/**
Called when an track request with token callback succeeds, fails, or times out.

Expand Down
1 change: 1 addition & 0 deletions RadarSDK/Radar.m
Original file line number Diff line number Diff line change
Expand Up @@ -1219,6 +1219,7 @@ - (void)applicationWillEnterForeground {
[RadarSettings setFeatureSettings:config.meta.featureSettings];
}];
}

[Radar logOpenedAppConversion];
}

Expand Down
4 changes: 4 additions & 0 deletions RadarSDK/RadarAPIClient.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ typedef void (^_Nonnull RadarTrackAPICompletionHandler)(RadarStatus status,
RadarConfig *_Nullable config,
NSString *_Nullable token);

typedef void (^_Nonnull RadarFlushReplaysAPICompletionHandler)(RadarStatus status, NSDictionary *_Nullable res);

typedef void (^_Nonnull RadarTripAPICompletionHandler)(RadarStatus status, RadarTrip *_Nullable trip, NSArray<RadarEvent *> *_Nullable events);

typedef void (^_Nonnull RadarContextAPICompletionHandler)(RadarStatus status, NSDictionary *_Nullable res, RadarContext *_Nullable context);
Expand Down Expand Up @@ -90,6 +92,8 @@ typedef void (^_Nonnull RadarSyncLogsAPICompletionHandler)(RadarStatus status);
encrypted:(BOOL)encrypted
completionHandler:(RadarTrackAPICompletionHandler _Nonnull)completionHandler;

- (void)flushReplays:(NSArray<NSDictionary *> *_Nonnull)replays completionHandler:(RadarFlushReplaysAPICompletionHandler _Nonnull)completionHandler;

- (void)verifyEventId:(NSString *_Nonnull)eventId verification:(RadarEventVerification)verification verifiedPlaceId:(NSString *_Nullable)verifiedPlaceId;

- (void)createTripWithOptions:(RadarTripOptions *_Nullable)options completionHandler:(RadarTripAPICompletionHandler _Nonnull)completionHandler;
Expand Down
248 changes: 141 additions & 107 deletions RadarSDK/RadarAPIClient.m

Large diffs are not rendered by default.

4 changes: 3 additions & 1 deletion RadarSDK/RadarFeatureSettings.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,15 @@ NS_ASSUME_NONNULL_BEGIN
Flag indicating whether to use persistence.
*/
@property (nonatomic, assign) BOOL usePersistence;
@property (nonatomic, assign) BOOL extendFlushReplays;

/**
Initializes a new RadarFeatureSettings object with given value.

@param usePersistence A flag indicating whether to use persistence.
*/
- (instancetype)initWithUsePersistence:(BOOL)usePersistence;
- (instancetype)initWithUsePersistence:(BOOL)usePersistence
extendFlushReplays:(BOOL)extendFlushReplays;

/**
Creates a RadarFeatureSettings object from the provided dictionary.
Expand Down
20 changes: 16 additions & 4 deletions RadarSDK/RadarFeatureSettings.m
Original file line number Diff line number Diff line change
Expand Up @@ -9,28 +9,40 @@

@implementation RadarFeatureSettings

- (instancetype)initWithUsePersistence:(BOOL)usePersistence {
- (instancetype)initWithUsePersistence:(BOOL)usePersistence
extendFlushReplays:(BOOL)extendFlushReplays {
if (self = [super init]) {
_usePersistence = usePersistence;
_extendFlushReplays = extendFlushReplays;
}
return self;
}

+ (RadarFeatureSettings *_Nullable)featureSettingsFromDictionary:(NSDictionary *)dict {
if (!dict) {
return [[RadarFeatureSettings alloc] initWithUsePersistence:NO];
return [[RadarFeatureSettings alloc] initWithUsePersistence:NO extendFlushReplays:NO];
}

NSObject *usePersistenceObj = dict[@"usePersistence"];
BOOL usePersistence = NO;
if (usePersistenceObj && [usePersistenceObj isKindOfClass:[NSNumber class]]) {
usePersistence = [(NSNumber *)usePersistenceObj boolValue];
}
return [[RadarFeatureSettings alloc] initWithUsePersistence:usePersistence];

NSObject *extendFlushReplaysObj = dict[@"extendFlushReplays"];
BOOL extendFlushReplays = NO;
if (extendFlushReplaysObj && [extendFlushReplaysObj isKindOfClass:[NSNumber class]]) {
extendFlushReplays = [(NSNumber *)extendFlushReplaysObj boolValue];
}
return [[RadarFeatureSettings alloc] initWithUsePersistence:usePersistence extendFlushReplays:extendFlushReplays];
}

- (NSDictionary *)dictionaryValue {
return @{@"usePersistence": @(self.usePersistence)};
NSMutableDictionary *dict = [NSMutableDictionary new];
[dict setValue:@(self.usePersistence) forKey:@"usePersistence"];
[dict setValue:@(self.extendFlushReplays) forKey:@"extendFlushReplays"];

return dict;
}

@end
8 changes: 8 additions & 0 deletions RadarSDK/RadarLocationManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#import "RadarSettings.h"
#import "RadarState.h"
#import "RadarUtils.h"
#import "RadarReplayBuffer.h"

@interface RadarLocationManager ()

Expand Down Expand Up @@ -202,6 +203,12 @@ - (void)startTrackingWithOptions:(RadarTrackingOptions *)trackingOptions {

- (void)stopTracking {
[RadarSettings setTracking:NO];
RadarFeatureSettings *featureSettings = [RadarSettings featureSettings];
if (featureSettings.extendFlushReplays) {
[[RadarLogger sharedInstance] logWithLevel:RadarLogLevelInfo type:RadarLogTypeSDKCall message:@"flushReplays() from stopTracking"];
[[RadarReplayBuffer sharedInstance] flushReplaysWithCompletionHandler:nil completionHandler:nil];
}

[self updateTracking];
}

Expand Down Expand Up @@ -400,6 +407,7 @@ - (void)updateTrackingFromMeta:(RadarMeta *_Nullable)meta {
}
}
[self updateTrackingFromInitialize];

}

- (void)restartPreviousTrackingOptions {
Expand Down
16 changes: 16 additions & 0 deletions RadarSDK/RadarReplay.m
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,20 @@ - (void)encodeWithCoder:(NSCoder *)coder {
return arr;
}

- (BOOL)isEqual:(id)object {
if (self == object) {
return YES;
}

if (![object isKindOfClass:[RadarReplay class]]) {
return NO;
}

return [self.replayParams isEqual:((RadarReplay *)object).replayParams];
}

- (NSUInteger)hash {
return [self.replayParams hash];
}

@end
5 changes: 5 additions & 0 deletions RadarSDK/RadarReplayBuffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@ NS_ASSUME_NONNULL_BEGIN

- (void)writeNewReplayToBuffer:(NSMutableDictionary *)replayParams;

- (void)flushReplaysWithCompletionHandler:(NSDictionary *_Nullable)replayParams
completionHandler:(RadarFlushReplaysCompletionHandler _Nullable)completionHandler;

- (void)setIsFlushing:(BOOL)flushing;

- (void)dropOldestReplay;

- (void)clearBuffer;
Expand Down
85 changes: 85 additions & 0 deletions RadarSDK/RadarReplayBuffer.m
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
// Copyright © 2023 Radar Labs, Inc. All rights reserved.
//

#import "Radar+Internal.h"
#import "RadarAPIClient.h"
#import "RadarReplayBuffer.h"
#import "RadarReplay.h"
#import "RadarLogger.h"
Expand All @@ -14,12 +16,14 @@

@implementation RadarReplayBuffer {
NSMutableArray<RadarReplay *> *mutableReplayBuffer;
BOOL isFlushing;
}

- (instancetype)init {
self = [super init];
if (self) {
mutableReplayBuffer = [NSMutableArray<RadarReplay *> new];
isFlushing = NO;
}
return self;
}
Expand Down Expand Up @@ -74,6 +78,79 @@ - (void)writeNewReplayToBuffer:(NSMutableDictionary *)replayParams {
return flushableReplays;
}

/**
* Flushes the replay in the buffer
*/
- (void)flushReplaysWithCompletionHandler:(NSDictionary *_Nullable)replayParams
completionHandler:(RadarFlushReplaysCompletionHandler _Nullable)completionHandler {
if (isFlushing) {
[[RadarLogger sharedInstance] logWithLevel:RadarLogLevelDebug message:@"Already flushing replays"];
if (completionHandler) {
completionHandler(RadarStatusErrorServer, nil);
}
return;
}

isFlushing = YES;

NSArray<RadarReplay *> *flushableReplays = [self flushableReplays];
if ([flushableReplays count] == 0 && !replayParams) {
[[RadarLogger sharedInstance] logWithLevel:RadarLogLevelDebug message:@"No replays to flush"];
isFlushing = NO;
if (completionHandler) {
completionHandler(RadarStatusSuccess, nil);
}
return;
}

// get a copy of the replays so we can safely clear what was synced up
NSMutableArray<RadarReplay *> *replaysArray = [NSMutableArray arrayWithArray:flushableReplays];

NSMutableArray *replaysRequestArray = [RadarReplay arrayForReplays:replaysArray];

// if we have a current track update, add it to the local replay list
if (replayParams) {
[replaysRequestArray addObject:replayParams];
}

// log the replay count
[[RadarLogger sharedInstance] logWithLevel:RadarLogLevelDebug message:[NSString stringWithFormat:@"Flushing %lu replays", (unsigned long)[replaysRequestArray count]]];

// set aside the current time in case we need to write it to that last replay
long nowMs = (long)([NSDate date].timeIntervalSince1970 * 1000);

[[RadarAPIClient sharedInstance] flushReplays:replaysRequestArray completionHandler:^(RadarStatus status, NSDictionary *_Nullable res) {
if (status == RadarStatusSuccess) {
// if the flush was successful, remove the replays from the buffer
[[RadarLogger sharedInstance] logWithLevel:RadarLogLevelDebug message:@"Flushed replays successfully"];
[self removeReplaysFromBuffer:replaysArray];
[Radar flushLogs];

} else {
if (replayParams) {
// if the flush failed, update the timestamp of the last replay to now
NSMutableDictionary *newReplayParams = [replayParams mutableCopy];
newReplayParams[@"replayed"] = @(YES);
newReplayParams[@"updatedAtMs"] = @(nowMs);
// remove the updatedAtMsDiff key because for replays we want to rely on the updatedAtMs key for the time instead
[newReplayParams removeObjectForKey:@"updatedAtMsDiff"];
// write the replay not yet persisted
[self writeNewReplayToBuffer:newReplayParams];
}
}

[self setIsFlushing:NO];
if (completionHandler) {
completionHandler(status, res);
}
}];
}

// Set is Flushing from outside
- (void)setIsFlushing:(BOOL)flushing {
isFlushing = flushing;
}

/**
* Clears the buffer out
*/
Expand All @@ -84,6 +161,14 @@ - (void)clearBuffer {
[[NSUserDefaults standardUserDefaults] removeObjectForKey:@"radar-replays"];
}

- (void)removeReplaysFromBuffer:(NSArray<RadarReplay *> *)replays {
[mutableReplayBuffer removeObjectsInArray:replays];

// persist the updated buffer
NSData *replaysData = [NSKeyedArchiver archivedDataWithRootObject:mutableReplayBuffer];
[[NSUserDefaults standardUserDefaults] setObject:replaysData forKey:@"radar-replays"];
}

- (void)loadReplaysFromPersistentStore {
NSData *replaysData = [[NSUserDefaults standardUserDefaults] objectForKey:@"radar-replays"];
if (replaysData) {
Expand Down
7 changes: 7 additions & 0 deletions RadarSDK/RadarSettings.m
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#import "RadarLogger.h"
#import "RadarTripOptions.h"
#import "RadarFeatureSettings.h"
#import "RadarReplayBuffer.h"

@implementation RadarSettings

Expand Down Expand Up @@ -62,6 +63,12 @@ + (NSString *)sessionId {
+ (BOOL)updateSessionId {
double timestampSeconds = [[NSDate date] timeIntervalSince1970];
double sessionIdSeconds = [[NSUserDefaults standardUserDefaults] doubleForKey:kSessionId];

RadarFeatureSettings *featureSettings = [RadarSettings featureSettings];
if (featureSettings.extendFlushReplays) {
[[RadarLogger sharedInstance] logWithLevel:RadarLogLevelInfo type:RadarLogTypeSDKCall message:@"flushReplays() from updateSesssionId"];
[[RadarReplayBuffer sharedInstance] flushReplaysWithCompletionHandler:nil completionHandler:nil];
}
if (timestampSeconds - sessionIdSeconds > 300) {
[[NSUserDefaults standardUserDefaults] setDouble:timestampSeconds forKey:kSessionId];

Expand Down
2 changes: 1 addition & 1 deletion RadarSDK/RadarUtils.m
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ + (NSNumber *)timeZoneOffset {
}

+ (NSString *)sdkVersion {
return @"3.8.5-beta.5";
return @"3.8.7";
}

+ (NSString *)deviceId {
Expand Down
Loading