From 0d53579815aab37739ff21c06a51717fca4fa565 Mon Sep 17 00:00:00 2001 From: Obaied Date: Fri, 16 Mar 2018 12:31:08 +0100 Subject: [PATCH 01/39] Downgrade AdjustTestLibrary min supported sdk to 6.0 --- .../AdjustTestLibrary.xcodeproj/project.pbxproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/AdjustTests/AdjustTestLibrary/AdjustTestLibrary.xcodeproj/project.pbxproj b/AdjustTests/AdjustTestLibrary/AdjustTestLibrary.xcodeproj/project.pbxproj index 490dfccc1..75f7eef3e 100644 --- a/AdjustTests/AdjustTestLibrary/AdjustTestLibrary.xcodeproj/project.pbxproj +++ b/AdjustTests/AdjustTestLibrary/AdjustTestLibrary.xcodeproj/project.pbxproj @@ -325,7 +325,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 11.2; + IPHONEOS_DEPLOYMENT_TARGET = 6.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -374,7 +374,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 11.2; + IPHONEOS_DEPLOYMENT_TARGET = 6.0; MTL_ENABLE_DEBUG_INFO = NO; ONLY_ACTIVE_ARCH = NO; SDKROOT = iphoneos; From 6bf871583ba73c8aee3cf1df6177bc0e7562dfaa Mon Sep 17 00:00:00 2001 From: uerceg Date: Mon, 26 Mar 2018 10:05:07 +0200 Subject: [PATCH 02/39] Flag if SDK has initialised attribution request or an ask_in --- Adjust/ADJAttributionHandler.m | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/Adjust/ADJAttributionHandler.m b/Adjust/ADJAttributionHandler.m index 98f309385..d742190d1 100644 --- a/Adjust/ADJAttributionHandler.m +++ b/Adjust/ADJAttributionHandler.m @@ -98,7 +98,8 @@ - (void)getAttribution { selfInject:self block:^(ADJAttributionHandler* selfI) { [selfI waitRequestAttributionWithDelayI:selfI - milliSecondsDelay:0]; + milliSecondsDelay:0 + isSdkAskingForIt:YES]; }]; } @@ -147,7 +148,8 @@ - (void)checkAttributionI:(ADJAttributionHandler*)selfI [selfI.activityHandler setAskingAttribution:YES]; [selfI waitRequestAttributionWithDelayI:selfI - milliSecondsDelay:[timerMilliseconds intValue]]; + milliSecondsDelay:[timerMilliseconds intValue] + isSdkAskingForIt:NO]; return; } @@ -200,13 +202,19 @@ - (void)requestAttributionI:(ADJAttributionHandler*)selfI { - (void)waitRequestAttributionWithDelayI:(ADJAttributionHandler*)selfI milliSecondsDelay:(int)milliSecondsDelay -{ + isSdkAskingForIt:(BOOL)isSdkAsking { NSTimeInterval secondsDelay = milliSecondsDelay / 1000; NSTimeInterval nextAskIn = [selfI.attributionTimer fireIn]; if (nextAskIn > secondsDelay) { return; } + if (isSdkAsking) { + [selfI.attributionPackage.parameters setObject:@"1" forKey:@"sdk_asking"]; + } else { + [selfI.attributionPackage.parameters setObject:@"0" forKey:@"sdk_asking"]; + } + if (milliSecondsDelay > 0) { [selfI.logger debug:@"Waiting to query attribution in %d milliseconds", milliSecondsDelay]; } From 67cc324a0fc5442ec0fcc7e96f62cbe0b93940a1 Mon Sep 17 00:00:00 2001 From: uerceg Date: Mon, 26 Mar 2018 17:04:50 +0200 Subject: [PATCH 03/39] Parameter name/value convention change --- Adjust/ADJAttributionHandler.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Adjust/ADJAttributionHandler.m b/Adjust/ADJAttributionHandler.m index d742190d1..cbc386767 100644 --- a/Adjust/ADJAttributionHandler.m +++ b/Adjust/ADJAttributionHandler.m @@ -210,9 +210,9 @@ - (void)waitRequestAttributionWithDelayI:(ADJAttributionHandler*)selfI } if (isSdkAsking) { - [selfI.attributionPackage.parameters setObject:@"1" forKey:@"sdk_asking"]; + [selfI.attributionPackage.parameters setObject:@"sdk" forKey:@"author"]; } else { - [selfI.attributionPackage.parameters setObject:@"0" forKey:@"sdk_asking"]; + [selfI.attributionPackage.parameters setObject:@"backend" forKey:@"author"]; } if (milliSecondsDelay > 0) { From 9d1a5eabfe06a4164d48cad4d956f1bc22445cda Mon Sep 17 00:00:00 2001 From: uerceg Date: Tue, 27 Mar 2018 11:41:14 +0200 Subject: [PATCH 04/39] Parameter naming v3 --- Adjust/ADJAttributionHandler.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Adjust/ADJAttributionHandler.m b/Adjust/ADJAttributionHandler.m index cbc386767..033ebf0a1 100644 --- a/Adjust/ADJAttributionHandler.m +++ b/Adjust/ADJAttributionHandler.m @@ -210,9 +210,9 @@ - (void)waitRequestAttributionWithDelayI:(ADJAttributionHandler*)selfI } if (isSdkAsking) { - [selfI.attributionPackage.parameters setObject:@"sdk" forKey:@"author"]; + [selfI.attributionPackage.parameters setObject:@"sdk" forKey:@"initiated_by"]; } else { - [selfI.attributionPackage.parameters setObject:@"backend" forKey:@"author"]; + [selfI.attributionPackage.parameters setObject:@"backend" forKey:@"initiated_by"]; } if (milliSecondsDelay > 0) { From ce95195504106455baff5bad727bbde33b0c0938 Mon Sep 17 00:00:00 2001 From: uerceg Date: Fri, 6 Apr 2018 13:30:34 +0200 Subject: [PATCH 05/39] Sending of forget package and queue flushing --- .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++++ Adjust/ADJActivityHandler.h | 2 +- Adjust/ADJActivityHandler.m | 37 ++++++++++++++++++- Adjust/ADJActivityKind.h | 1 + Adjust/ADJActivityKind.m | 4 ++ Adjust/ADJAdjustFactory.h | 3 +- Adjust/ADJAdjustFactory.m | 9 +++-- Adjust/ADJPackageBuilder.h | 2 + Adjust/ADJPackageBuilder.m | 13 +++++++ Adjust/ADJPackageHandler.h | 1 + Adjust/ADJPackageHandler.m | 12 +++++- Adjust/ADJRequestHandler.h | 10 +++-- Adjust/ADJRequestHandler.m | 26 +++++++++++-- Adjust/ADJUserDefaults.h | 6 +++ Adjust/ADJUserDefaults.m | 15 ++++++++ Adjust/Adjust.h | 7 ++++ Adjust/Adjust.m | 14 +++++++ .../AdjustExample-iOS/ViewControlleriOS.m | 10 ++++- 18 files changed, 162 insertions(+), 18 deletions(-) create mode 100644 Adjust.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/Adjust.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Adjust.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Adjust.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Adjust/ADJActivityHandler.h b/Adjust/ADJActivityHandler.h index c8e1640a1..c38fcbdc8 100644 --- a/Adjust/ADJActivityHandler.h +++ b/Adjust/ADJActivityHandler.h @@ -70,7 +70,7 @@ - (void)appWillOpenUrl:(NSURL*)url; - (void)setDeviceToken:(NSData *)deviceToken; - +- (void)setGdprForgetMe; - (void)setAskingAttribution:(BOOL)askingAttribution; - (BOOL)updateAttributionI:(id)selfI attribution:(ADJAttribution *)attribution; diff --git a/Adjust/ADJActivityHandler.m b/Adjust/ADJActivityHandler.m index 6a3a32b4e..4493d6fc0 100644 --- a/Adjust/ADJActivityHandler.m +++ b/Adjust/ADJActivityHandler.m @@ -201,11 +201,12 @@ - (id)initWithConfig:(ADJConfig *)adjustConfig preLaunchActionsArray:savedPreLaunch.preLaunchActionsArray]; }]; - + /* Not needed, done already in initI:preLaunchActionsArray: method. // self.deviceTokenData = savedPreLaunch.deviceTokenData; if (self.activityState != nil) { [self setDeviceToken:[ADJUserDefaults getPushToken]]; } + */ [self addNotificationObserver]; @@ -353,6 +354,14 @@ - (void)setDeviceToken:(NSData *)deviceToken { }]; } +- (void)setGdprForgetMe { + [ADJUtil launchInQueue:self.internalQueue + selfInject:self + block:^(ADJActivityHandler * selfI) { + [selfI setGdprForgetMeI:selfI]; + }]; +} + - (void)setAttributionDetails:(NSDictionary *)attributionDetails error:(NSError *)error retriesLeft:(int)retriesLeft @@ -635,11 +644,14 @@ - (void)initI:(ADJActivityHandler *)selfI } else { if (selfI.activityState != nil) { NSData *deviceToken = [ADJUserDefaults getPushToken]; - [selfI setDeviceToken:deviceToken]; } } + if ([ADJUserDefaults getGdprForgetMe]) { + [selfI setGdprForgetMe]; + } + selfI.foregroundTimer = [ADJTimerCycle timerWithBlock:^{ [selfI foregroundTimerFired]; } @@ -1303,6 +1315,27 @@ - (void)setDeviceTokenI:(ADJActivityHandler *)selfI } } +- (void)setGdprForgetMeI:(ADJActivityHandler *)selfI { + // Send GDPR package + double now = [NSDate.date timeIntervalSince1970]; + ADJPackageBuilder *gdprBuilder = [[ADJPackageBuilder alloc] initWithDeviceInfo:selfI.deviceInfo + activityState:selfI.activityState + config:selfI.adjustConfig + sessionParameters:selfI.sessionParameters + createdAt:now]; + + ADJActivityPackage *gdprPackage = [gdprBuilder buildGdprPackage]; + [selfI.packageHandler addPackage:gdprPackage]; + + [ADJUserDefaults removeGdprForgetMe]; + + if (selfI.adjustConfig.eventBufferingEnabled) { + [selfI.logger info:@"Buffered gdpr %@", gdprPackage.suffix]; + } else { + [selfI.packageHandler sendFirstPackage]; + } +} + #pragma mark - private - (BOOL)isEnabledI:(ADJActivityHandler *)selfI { diff --git a/Adjust/ADJActivityKind.h b/Adjust/ADJActivityKind.h index 4beccccc2..728f13b92 100644 --- a/Adjust/ADJActivityKind.h +++ b/Adjust/ADJActivityKind.h @@ -20,6 +20,7 @@ typedef NS_ENUM(int, ADJActivityKind) { ADJActivityKindClick = 4, ADJActivityKindAttribution = 5, ADJActivityKindInfo = 6, + ADJActivityKindGdpr = 7 }; @interface ADJActivityKindUtil : NSObject diff --git a/Adjust/ADJActivityKind.m b/Adjust/ADJActivityKind.m index 9fce00922..bc525f497 100644 --- a/Adjust/ADJActivityKind.m +++ b/Adjust/ADJActivityKind.m @@ -23,6 +23,8 @@ + (ADJActivityKind)activityKindFromString:(NSString *)activityKindString { return ADJActivityKindAttribution; } else if ([@"info" isEqualToString:activityKindString]) { return ADJActivityKindInfo; + } else if ([@"gdpr" isEqualToString:activityKindString]) { + return ADJActivityKindGdpr; } else { return ADJActivityKindUnknown; } @@ -40,6 +42,8 @@ + (NSString *)activityKindToString:(ADJActivityKind)activityKind { return @"attribution"; case ADJActivityKindInfo: return @"info"; + case ADJActivityKindGdpr: + return @"gdpr"; default: return @"unknown"; } diff --git a/Adjust/ADJAdjustFactory.h b/Adjust/ADJAdjustFactory.h index 115d33f27..85fd4ed40 100644 --- a/Adjust/ADJAdjustFactory.h +++ b/Adjust/ADJAdjustFactory.h @@ -20,7 +20,8 @@ + (id)packageHandlerForActivityHandler:(id)activityHandler startsSending:(BOOL)startsSending; -+ (id)requestHandlerForPackageHandler:(id)packageHandler; ++ (id)requestHandlerForPackageHandler:(id)packageHandler + andActivityHandler:(id)activityHandler; + (id)activityHandlerWithConfig:(ADJConfig *)adjustConfig savedPreLaunch:(ADJSavedPreLaunch *)savedPreLaunch; + (id)sdkClickHandlerForActivityHandler:(id)activityHandler diff --git a/Adjust/ADJAdjustFactory.m b/Adjust/ADJAdjustFactory.m index b1e734c1b..1030ab1dd 100644 --- a/Adjust/ADJAdjustFactory.m +++ b/Adjust/ADJAdjustFactory.m @@ -38,11 +38,14 @@ @implementation ADJAdjustFactory return [internalPackageHandler initWithActivityHandler:activityHandler startsSending:startsSending]; } -+ (id)requestHandlerForPackageHandler:(id)packageHandler { ++ (id)requestHandlerForPackageHandler:(id)packageHandler + andActivityHandler:(id)activityHandler { if (internalRequestHandler == nil) { - return [ADJRequestHandler handlerWithPackageHandler:packageHandler]; + return [ADJRequestHandler handlerWithPackageHandler:packageHandler + andActivityHandler:activityHandler]; } - return [internalRequestHandler initWithPackageHandler:packageHandler]; + return [internalRequestHandler initWithPackageHandler:packageHandler + andActivityHandler:activityHandler]; } + (id)activityHandlerWithConfig:(ADJConfig *)adjustConfig diff --git a/Adjust/ADJPackageBuilder.h b/Adjust/ADJPackageBuilder.h index 2f2ed2117..a8a82194d 100644 --- a/Adjust/ADJPackageBuilder.h +++ b/Adjust/ADJPackageBuilder.h @@ -37,6 +37,8 @@ - (ADJActivityPackage *)buildAttributionPackage; +- (ADJActivityPackage *)buildGdprPackage; + - (ADJActivityPackage *)buildEventPackage:(ADJEvent *)event isInDelay:(BOOL)isInDelay; diff --git a/Adjust/ADJPackageBuilder.m b/Adjust/ADJPackageBuilder.m index 3c68bd080..54b4054f4 100644 --- a/Adjust/ADJPackageBuilder.m +++ b/Adjust/ADJPackageBuilder.m @@ -171,6 +171,19 @@ - (ADJActivityPackage *)buildAttributionPackage { return attributionPackage; } +- (ADJActivityPackage *)buildGdprPackage { + NSMutableDictionary *parameters = [self idsParameters]; + [ADJPackageBuilder parameters:parameters setString:@"push" forKey:@"source"]; + + ADJActivityPackage *gdprPackage = [self defaultActivityPackage]; + gdprPackage.path = @"/sdk_info"; + gdprPackage.activityKind = ADJActivityKindGdpr; + gdprPackage.suffix = @""; + gdprPackage.parameters = parameters; + + return gdprPackage; +} + #pragma mark - Private & helper methods - (ADJActivityPackage *)defaultActivityPackage { diff --git a/Adjust/ADJPackageHandler.h b/Adjust/ADJPackageHandler.h index 66c3b871a..a84442a94 100644 --- a/Adjust/ADJPackageHandler.h +++ b/Adjust/ADJPackageHandler.h @@ -26,6 +26,7 @@ - (void)pauseSending; - (void)resumeSending; - (void)updatePackages:(ADJSessionParameters *)sessionParameters; +- (void)flush; - (NSString *)getBasePath; - (void)teardown; diff --git a/Adjust/ADJPackageHandler.m b/Adjust/ADJPackageHandler.m index 6d6f2c49f..e38679c4d 100644 --- a/Adjust/ADJPackageHandler.m +++ b/Adjust/ADJPackageHandler.m @@ -135,6 +135,11 @@ - (void)updatePackages:(ADJSessionParameters *)sessionParameters }]; } +- (void)flush { + [self.packageQueue removeAllObjects]; + [self writePackageQueueS:self]; +} + - (NSString *)getBasePath { return _basePath; } @@ -171,7 +176,8 @@ - (void)initI:(ADJPackageHandler *)selfI { selfI.activityHandler = activityHandler; selfI.paused = !startsSending; - selfI.requestHandler = [ADJAdjustFactory requestHandlerForPackageHandler:selfI]; + selfI.requestHandler = [ADJAdjustFactory requestHandlerForPackageHandler:selfI + andActivityHandler:selfI.activityHandler]; selfI.logger = ADJAdjustFactory.logger; selfI.sendingSemaphore = dispatch_semaphore_create(1); [selfI readPackageQueueI:selfI]; @@ -214,6 +220,10 @@ - (void)sendFirstI:(ADJPackageHandler *)selfI } - (void)sendNextI:(ADJPackageHandler *)selfI { + if ([selfI.packageQueue count] <= 0) { + return; + } + [selfI.packageQueue removeObjectAtIndex:0]; [selfI writePackageQueueS:selfI]; dispatch_semaphore_signal(selfI.sendingSemaphore); diff --git a/Adjust/ADJRequestHandler.h b/Adjust/ADJRequestHandler.h index 197e538ed..5dc8d1772 100644 --- a/Adjust/ADJRequestHandler.h +++ b/Adjust/ADJRequestHandler.h @@ -7,14 +7,15 @@ // #import - #import "ADJPackageHandler.h" @protocol ADJRequestHandler -- (id)initWithPackageHandler:(id)packageHandler; +- (id)initWithPackageHandler:(id)packageHandler + andActivityHandler:(id)activityHandler; -- (void)sendPackage:(ADJActivityPackage *)activityPackage queueSize:(NSUInteger)queueSize; +- (void)sendPackage:(ADJActivityPackage *)activityPackage + queueSize:(NSUInteger)queueSize; - (void)teardown; @@ -22,6 +23,7 @@ @interface ADJRequestHandler : NSObject -+ (id)handlerWithPackageHandler:(id)packageHandler; ++ (id)handlerWithPackageHandler:(id)packageHandler + andActivityHandler:(id)activityHandler; @end diff --git a/Adjust/ADJRequestHandler.m b/Adjust/ADJRequestHandler.m index 30834ca6c..48f1fb001 100644 --- a/Adjust/ADJRequestHandler.m +++ b/Adjust/ADJRequestHandler.m @@ -24,6 +24,8 @@ @interface ADJRequestHandler() @property (nonatomic, weak) id packageHandler; +@property (nonatomic, weak) id activityHandler; + @property (nonatomic, copy) NSString *basePath; @end @@ -32,11 +34,14 @@ @implementation ADJRequestHandler #pragma mark - Public methods -+ (ADJRequestHandler *)handlerWithPackageHandler:(id)packageHandler { - return [[ADJRequestHandler alloc] initWithPackageHandler:packageHandler]; ++ (ADJRequestHandler *)handlerWithPackageHandler:(id)packageHandler + andActivityHandler:(id)activityHandler { + return [[ADJRequestHandler alloc] initWithPackageHandler:packageHandler + andActivityHandler:activityHandler]; } -- (id)initWithPackageHandler:(id)packageHandler { +- (id)initWithPackageHandler:(id)packageHandler + andActivityHandler:(id)activityHandler { self = [super init]; if (self == nil) { @@ -45,6 +50,7 @@ - (id)initWithPackageHandler:(id)packageHandler { self.internalQueue = dispatch_queue_create(kInternalQueueName, DISPATCH_QUEUE_SERIAL); self.packageHandler = packageHandler; + self.activityHandler = activityHandler; self.logger = ADJAdjustFactory.logger; self.basePath = [packageHandler getBasePath]; @@ -89,7 +95,19 @@ - (void)sendI:(ADJRequestHandler *)selfI activityPackage:(ADJActivityPackage *)a return; } - + + // Check if successfully sent package is GDPR forget me. + // If yes, disable SDK and flush any potentially stored packages that happened afterwards. + if (activityPackage.activityKind == ADJActivityKindGdpr) { + if (responseData.success) { + // TODO: Dummy string assumption, check with backend. + // if ([responseData.message containsString:@"user forgotten"]) { + [self.activityHandler setEnabled:NO]; + [self.packageHandler flush]; + // } + } + } + [selfI.packageHandler sendNextPackage:responseData]; }]; } diff --git a/Adjust/ADJUserDefaults.h b/Adjust/ADJUserDefaults.h index 0c66531e5..cb20f548f 100644 --- a/Adjust/ADJUserDefaults.h +++ b/Adjust/ADJUserDefaults.h @@ -22,4 +22,10 @@ + (BOOL)getInstallTracked; ++ (void)setGdprForgetMe; + ++ (BOOL)getGdprForgetMe; + ++ (void)removeGdprForgetMe; + @end diff --git a/Adjust/ADJUserDefaults.m b/Adjust/ADJUserDefaults.m index 103f159d4..290e0a7b6 100644 --- a/Adjust/ADJUserDefaults.m +++ b/Adjust/ADJUserDefaults.m @@ -9,6 +9,7 @@ #import "ADJUserDefaults.h" static NSString * const PREFS_KEY_PUSH_TOKEN = @"adj_push_token"; +static NSString * const PREFS_KEY_GDPR_FORGET_ME = @"adj_gdpr_forget_me"; static NSString * const PREFS_KEY_INSTALL_TRACKED = @"adj_install_tracked"; @implementation ADJUserDefaults @@ -38,6 +39,20 @@ + (BOOL)getInstallTracked { return [[NSUserDefaults standardUserDefaults] boolForKey:PREFS_KEY_INSTALL_TRACKED]; } ++ (void)setGdprForgetMe { + [[NSUserDefaults standardUserDefaults] setBool:YES forKey:PREFS_KEY_GDPR_FORGET_ME]; + [[NSUserDefaults standardUserDefaults] synchronize]; +} + ++ (BOOL)getGdprForgetMe { + return [[NSUserDefaults standardUserDefaults] boolForKey:PREFS_KEY_GDPR_FORGET_ME]; +} + ++ (void)removeGdprForgetMe { + [[NSUserDefaults standardUserDefaults] removeObjectForKey:PREFS_KEY_GDPR_FORGET_ME]; + [[NSUserDefaults standardUserDefaults] synchronize]; +} + + (void)clearAdjustStuff { [[NSUserDefaults standardUserDefaults] removeObjectForKey:PREFS_KEY_PUSH_TOKEN]; [[NSUserDefaults standardUserDefaults] removeObjectForKey:PREFS_KEY_INSTALL_TRACKED]; diff --git a/Adjust/Adjust.h b/Adjust/Adjust.h index c5706bdb1..c4afd504c 100644 --- a/Adjust/Adjust.h +++ b/Adjust/Adjust.h @@ -205,6 +205,11 @@ extern NSString * __nonnull const ADJEnvironmentProduction; */ + (void)resetSessionPartnerParameters; +/** + * @brief Give right user to be forgotten in accordance with GDPR law. + */ ++ (void)gdprForgetMe; + /** * Obtain singleton Adjust object. */ @@ -244,6 +249,8 @@ extern NSString * __nonnull const ADJEnvironmentProduction; - (void)addSessionCallbackParameter:(nonnull NSString *)key value:(nonnull NSString *)value; +- (void)gdprForgetMe; + - (BOOL)isEnabled; - (nullable NSString *)adid; diff --git a/Adjust/Adjust.m b/Adjust/Adjust.m index 9a4fddaca..418c2c2f5 100644 --- a/Adjust/Adjust.m +++ b/Adjust/Adjust.m @@ -144,6 +144,10 @@ + (void)resetSessionPartnerParameters { [[Adjust getInstance] resetSessionPartnerParameters]; } ++ (void)gdprForgetMe { + [[Adjust getInstance] gdprForgetMe]; +} + + (ADJAttribution *)attribution { return [[Adjust getInstance] attribution]; } @@ -352,6 +356,16 @@ - (void)resetSessionPartnerParameters { }]; } +- (void)gdprForgetMe { + [ADJUserDefaults setGdprForgetMe]; + + if ([self checkActivityHandler:@"GDPR forget me"]) { + if (self.activityHandler.isEnabled) { + [self.activityHandler setGdprForgetMe]; + } + } +} + - (ADJAttribution *)attribution { if (![self checkActivityHandler]) { return nil; diff --git a/examples/AdjustExample-iOS/AdjustExample-iOS/ViewControlleriOS.m b/examples/AdjustExample-iOS/AdjustExample-iOS/ViewControlleriOS.m index a86d84ac8..aec5b9619 100644 --- a/examples/AdjustExample-iOS/AdjustExample-iOS/ViewControlleriOS.m +++ b/examples/AdjustExample-iOS/AdjustExample-iOS/ViewControlleriOS.m @@ -35,9 +35,15 @@ - (void)didReceiveMemoryWarning { } - (IBAction)clickTrackSimpleEvent:(UIButton *)sender { - ADJEvent *event = [ADJEvent eventWithEventToken:kEventToken1]; + for (int i = 0; i < 100; i += 1) { + ADJEvent *event = [ADJEvent eventWithEventToken:kEventToken1]; + [Adjust trackEvent:event]; - [Adjust trackEvent:event]; + if (i == 20) { + [Adjust gdprForgetMe]; + } + } +// [Adjust gdprForgetMe]; } - (IBAction)clickTrackRevenueEvent:(UIButton *)sender { From dcfb76b6a2530a0cbbdaa3e7511ee44c84b12d3c Mon Sep 17 00:00:00 2001 From: uerceg Date: Fri, 6 Apr 2018 13:40:14 +0200 Subject: [PATCH 06/39] Forbid SDK re-enabling for forgotten user during app lifetime --- Adjust/ADJActivityHandler.m | 19 +++++++++++++++++++ Adjust/ADJActivityState.h | 1 + Adjust/ADJActivityState.m | 13 +++++++++++-- 3 files changed, 31 insertions(+), 2 deletions(-) diff --git a/Adjust/ADJActivityHandler.m b/Adjust/ADJActivityHandler.m index 4493d6fc0..9b3087772 100644 --- a/Adjust/ADJActivityHandler.m +++ b/Adjust/ADJActivityHandler.m @@ -1056,6 +1056,14 @@ - (void)setEnabledI:(ADJActivityHandler *)selfI enabled:(BOOL)enabled { return; } + // If user is forgotten, forbid re-enabling. + if (enabled) { + if ([selfI isForgottenI:selfI]) { + [selfI.logger debug:@"Re-enabling SDK for forgotten user not allowed"]; + return; + } + } + // save new enabled state in internal state selfI.internalState.enabled = enabled; @@ -1316,6 +1324,9 @@ - (void)setDeviceTokenI:(ADJActivityHandler *)selfI } - (void)setGdprForgetMeI:(ADJActivityHandler *)selfI { + selfI.activityState.isForgotten = YES; + [selfI writeActivityStateI:selfI]; + // Send GDPR package double now = [NSDate.date timeIntervalSince1970]; ADJPackageBuilder *gdprBuilder = [[ADJPackageBuilder alloc] initWithDeviceInfo:selfI.deviceInfo @@ -1338,6 +1349,14 @@ - (void)setGdprForgetMeI:(ADJActivityHandler *)selfI { #pragma mark - private +- (BOOL)isForgottenI:(ADJActivityHandler *)selfI { + if (selfI.activityState != nil) { + return selfI.activityState.isForgotten; + } else { + return NO; + } +} + - (BOOL)isEnabledI:(ADJActivityHandler *)selfI { if (selfI.activityState != nil) { return selfI.activityState.enabled; diff --git a/Adjust/ADJActivityState.h b/Adjust/ADJActivityState.h index 35e46d194..44145e77d 100644 --- a/Adjust/ADJActivityState.h +++ b/Adjust/ADJActivityState.h @@ -12,6 +12,7 @@ // Persistent data @property (nonatomic, assign) BOOL enabled; +@property (nonatomic, assign) BOOL isForgotten; @property (nonatomic, assign) BOOL askingAttribution; @property (nonatomic, copy) NSString *uuid; diff --git a/Adjust/ADJActivityState.m b/Adjust/ADJActivityState.m index 3dbd054b1..40a2fe414 100644 --- a/Adjust/ADJActivityState.m +++ b/Adjust/ADJActivityState.m @@ -36,6 +36,7 @@ - (id)init { self.lastActivity = -1; self.lastInterval = -1; self.enabled = YES; + self.isForgotten = NO; self.askingAttribution = NO; self.deviceToken = nil; self.transactionIds = [NSMutableArray arrayWithCapacity:kTransactionIdCount]; @@ -150,9 +151,9 @@ - (NSString *)generateUniqueKey { } - (NSString *)description { - return [NSString stringWithFormat:@"ec:%d sc:%d ssc:%d ask:%d sl:%.1f ts:%.1f la:%.1f dt:%@", + return [NSString stringWithFormat:@"ec:%d sc:%d ssc:%d ask:%d sl:%.1f ts:%.1f la:%.1f dt:%@ fgt:%d", self.eventCount, self.sessionCount, self.subsessionCount, self.askingAttribution, self.sessionLength, - self.timeSpent, self.lastActivity, self.deviceToken]; + self.timeSpent, self.lastActivity, self.deviceToken, self.isForgotten]; } #pragma mark - NSCoding protocol methods @@ -193,6 +194,12 @@ - (id)initWithCoder:(NSCoder *)decoder { } else { self.enabled = YES; } + + if ([decoder containsValueForKey:@"isForgotten"]) { + self.isForgotten = [decoder decodeBoolForKey:@"isForgotten"]; + } else { + self.isForgotten = NO; + } if ([decoder containsValueForKey:@"askingAttribution"]) { self.askingAttribution = [decoder decodeBoolForKey:@"askingAttribution"]; @@ -233,6 +240,7 @@ - (void)encodeWithCoder:(NSCoder *)encoder { [encoder encodeObject:self.uuid forKey:@"uuid"]; [encoder encodeObject:self.transactionIds forKey:@"transactionIds"]; [encoder encodeBool:self.enabled forKey:@"enabled"]; + [encoder encodeBool:self.isForgotten forKey:@"isForgotten"]; [encoder encodeBool:self.askingAttribution forKey:@"askingAttribution"]; [encoder encodeObject:self.deviceToken forKey:@"deviceToken"]; [encoder encodeBool:self.updatePackages forKey:@"updatePackages"]; @@ -255,6 +263,7 @@ - (id)copyWithZone:(NSZone *)zone { copy.lastInterval = self.lastInterval; copy.eventCount = self.eventCount; copy.enabled = self.enabled; + copy.isForgotten = self.isForgotten; copy.lastActivity = self.lastActivity; copy.askingAttribution = self.askingAttribution; copy.deviceToken = [self.deviceToken copyWithZone:zone]; From 17ffec6c3fae2bd5e42c654d658f371fa4986a5a Mon Sep 17 00:00:00 2001 From: uerceg Date: Mon, 9 Apr 2018 08:45:31 +0200 Subject: [PATCH 07/39] Don't track install session if user decided to be forgoten before it --- Adjust/ADJActivityHandler.m | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Adjust/ADJActivityHandler.m b/Adjust/ADJActivityHandler.m index 9b3087772..61d9fbf55 100644 --- a/Adjust/ADJActivityHandler.m +++ b/Adjust/ADJActivityHandler.m @@ -749,8 +749,11 @@ - (void)processSessionI:(ADJActivityHandler *)selfI { // track the first session package only if it's enabled if ([selfI.internalState isEnabled]) { - selfI.activityState.sessionCount = 1; // this is the first session - [selfI transferSessionPackageI:selfI now:now]; + // If user chose to be forgotten before install has ever tracked, don't track it. + if (![ADJUserDefaults getGdprForgetMe]) { + selfI.activityState.sessionCount = 1; // this is the first session + [selfI transferSessionPackageI:selfI now:now]; + } } [selfI.activityState resetSessionAttributes:now]; From 081a7d7feba6d0d1087d9a4e2386b6d4038e850f Mon Sep 17 00:00:00 2001 From: uerceg Date: Mon, 9 Apr 2018 08:46:05 +0200 Subject: [PATCH 08/39] For now treat any kind of GDPR package answer as valid one --- Adjust/ADJRequestHandler.m | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Adjust/ADJRequestHandler.m b/Adjust/ADJRequestHandler.m index 48f1fb001..984ea3d63 100644 --- a/Adjust/ADJRequestHandler.m +++ b/Adjust/ADJRequestHandler.m @@ -99,13 +99,14 @@ - (void)sendI:(ADJRequestHandler *)selfI activityPackage:(ADJActivityPackage *)a // Check if successfully sent package is GDPR forget me. // If yes, disable SDK and flush any potentially stored packages that happened afterwards. if (activityPackage.activityKind == ADJActivityKindGdpr) { - if (responseData.success) { + // TODO: For now accept all answers to GDPR type of package. + // if (responseData.success) { // TODO: Dummy string assumption, check with backend. // if ([responseData.message containsString:@"user forgotten"]) { [self.activityHandler setEnabled:NO]; [self.packageHandler flush]; // } - } + // } } [selfI.packageHandler sendNextPackage:responseData]; From abbabf204c52a9fb37ca37002e244d892e6f2883 Mon Sep 17 00:00:00 2001 From: uerceg Date: Mon, 9 Apr 2018 08:54:22 +0200 Subject: [PATCH 09/39] Synchronise queue flushing --- Adjust/ADJPackageHandler.m | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/Adjust/ADJPackageHandler.m b/Adjust/ADJPackageHandler.m index e38679c4d..cab6d31bd 100644 --- a/Adjust/ADJPackageHandler.m +++ b/Adjust/ADJPackageHandler.m @@ -136,8 +136,9 @@ - (void)updatePackages:(ADJSessionParameters *)sessionParameters } - (void)flush { - [self.packageQueue removeAllObjects]; - [self writePackageQueueS:self]; + [ADJUtil launchInQueue:self.internalQueue selfInject:self block:^(ADJPackageHandler *selfI) { + [selfI flushI:selfI]; + }]; } - (NSString *)getBasePath { @@ -260,6 +261,11 @@ - (void)updatePackagesI:(ADJPackageHandler *)selfI [selfI writePackageQueueS:selfI]; } +- (void)flushI:(ADJPackageHandler *)selfI { + [selfI.packageQueue removeAllObjects]; + [selfI writePackageQueueS:selfI]; +} + #pragma mark - private - (void)readPackageQueueI:(ADJPackageHandler *)selfI { [NSKeyedUnarchiver setClass:[ADJActivityPackage class] forClassName:@"AIActivityPackage"]; From 601970eed3e2ec75054cec49913487e5829c652e Mon Sep 17 00:00:00 2001 From: uerceg Date: Mon, 9 Apr 2018 09:19:19 +0200 Subject: [PATCH 10/39] Revert example app functionality --- .../AdjustExample-iOS/ViewControlleriOS.m | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/examples/AdjustExample-iOS/AdjustExample-iOS/ViewControlleriOS.m b/examples/AdjustExample-iOS/AdjustExample-iOS/ViewControlleriOS.m index aec5b9619..a86d84ac8 100644 --- a/examples/AdjustExample-iOS/AdjustExample-iOS/ViewControlleriOS.m +++ b/examples/AdjustExample-iOS/AdjustExample-iOS/ViewControlleriOS.m @@ -35,15 +35,9 @@ - (void)didReceiveMemoryWarning { } - (IBAction)clickTrackSimpleEvent:(UIButton *)sender { - for (int i = 0; i < 100; i += 1) { - ADJEvent *event = [ADJEvent eventWithEventToken:kEventToken1]; - [Adjust trackEvent:event]; + ADJEvent *event = [ADJEvent eventWithEventToken:kEventToken1]; - if (i == 20) { - [Adjust gdprForgetMe]; - } - } -// [Adjust gdprForgetMe]; + [Adjust trackEvent:event]; } - (IBAction)clickTrackRevenueEvent:(UIButton *)sender { From e777b550d37e8d85192fe6999c248336d6fb8a82 Mon Sep 17 00:00:00 2001 From: uerceg Date: Mon, 9 Apr 2018 17:04:47 +0200 Subject: [PATCH 11/39] Track forget package if user decided to be forgotten while SDK was disabled --- Adjust/ADJActivityHandler.m | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Adjust/ADJActivityHandler.m b/Adjust/ADJActivityHandler.m index 61d9fbf55..b30185843 100644 --- a/Adjust/ADJActivityHandler.m +++ b/Adjust/ADJActivityHandler.m @@ -1091,6 +1091,10 @@ - (void)setEnabledI:(ADJActivityHandler *)selfI enabled:(BOOL)enabled { if (deviceToken != nil && ![selfI.activityState.deviceToken isEqualToString:[ADJUtil convertDeviceToken:deviceToken]]) { [self setDeviceToken:deviceToken]; } + + if ([ADJUserDefaults getGdprForgetMe]) { + [selfI setGdprForgetMe]; + } } // save new enabled state in activity state From 5d3d2a11fa43ca6641aad00c41085885607f3c43 Mon Sep 17 00:00:00 2001 From: uerceg Date: Mon, 9 Apr 2018 17:05:08 +0200 Subject: [PATCH 12/39] Send next logic adjustment due to flushing --- Adjust/ADJPackageHandler.m | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/Adjust/ADJPackageHandler.m b/Adjust/ADJPackageHandler.m index cab6d31bd..cb8bd3cf7 100644 --- a/Adjust/ADJPackageHandler.m +++ b/Adjust/ADJPackageHandler.m @@ -221,12 +221,11 @@ - (void)sendFirstI:(ADJPackageHandler *)selfI } - (void)sendNextI:(ADJPackageHandler *)selfI { - if ([selfI.packageQueue count] <= 0) { - return; + if ([selfI.packageQueue count] > 0) { + [selfI.packageQueue removeObjectAtIndex:0]; + [selfI writePackageQueueS:selfI]; } - [selfI.packageQueue removeObjectAtIndex:0]; - [selfI writePackageQueueS:selfI]; dispatch_semaphore_signal(selfI.sendingSemaphore); [selfI sendFirstI:selfI]; } From 9a1a362b21fb0f35d06bbea8a795017cf3f78ac0 Mon Sep 17 00:00:00 2001 From: uerceg Date: Mon, 9 Apr 2018 17:56:58 +0200 Subject: [PATCH 13/39] Aim gdpr_forget_device endpoint --- Adjust/ADJPackageBuilder.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Adjust/ADJPackageBuilder.m b/Adjust/ADJPackageBuilder.m index 54b4054f4..c34d9a076 100644 --- a/Adjust/ADJPackageBuilder.m +++ b/Adjust/ADJPackageBuilder.m @@ -173,10 +173,10 @@ - (ADJActivityPackage *)buildAttributionPackage { - (ADJActivityPackage *)buildGdprPackage { NSMutableDictionary *parameters = [self idsParameters]; - [ADJPackageBuilder parameters:parameters setString:@"push" forKey:@"source"]; + // [ADJPackageBuilder parameters:parameters setString:@"push" forKey:@"source"]; ADJActivityPackage *gdprPackage = [self defaultActivityPackage]; - gdprPackage.path = @"/sdk_info"; + gdprPackage.path = @"/gdpr_forget_device"; gdprPackage.activityKind = ADJActivityKindGdpr; gdprPackage.suffix = @""; gdprPackage.parameters = parameters; From ee01df767833ef111357bae16a1602e5d7260a15 Mon Sep 17 00:00:00 2001 From: uerceg Date: Mon, 9 Apr 2018 17:57:32 +0200 Subject: [PATCH 14/39] Add handling of gdprForgetMe to command executor --- .../AdjustTestApp/AdjustTestApp/ATAAdjustCommandExecutor.m | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/AdjustTests/AdjustTestApp/AdjustTestApp/ATAAdjustCommandExecutor.m b/AdjustTests/AdjustTestApp/AdjustTestApp/ATAAdjustCommandExecutor.m index 67f58bed7..a620ad4e7 100644 --- a/AdjustTests/AdjustTestApp/AdjustTestApp/ATAAdjustCommandExecutor.m +++ b/AdjustTests/AdjustTestApp/AdjustTestApp/ATAAdjustCommandExecutor.m @@ -84,6 +84,8 @@ - (void)executeCommand:(NSString *)className [self setPushToken:parameters]; } else if ([methodName isEqualToString:@"openDeeplink"]) { [self openDeeplink:parameters]; + } else if ([methodName isEqualToString:@"gdprForgetMe"]) { + [self gdprForgetMe:parameters]; } } @@ -466,4 +468,8 @@ - (void)openDeeplink:(NSDictionary *)parameters { [Adjust appWillOpenUrl:deeplink]; } +- (void)gdprForgetMe:(NSDictionary *)parameters { + [Adjust gdprForgetMe]; +} + @end From 27799698f7ef0021abcb07f715b6871fd1e61423 Mon Sep 17 00:00:00 2001 From: uerceg Date: Tue, 10 Apr 2018 10:19:13 +0200 Subject: [PATCH 15/39] isForgotten -> isGdprForgotten rename --- Adjust/ADJActivityHandler.h | 1 + Adjust/ADJActivityHandler.m | 18 +++++++++++------- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/Adjust/ADJActivityHandler.h b/Adjust/ADJActivityHandler.h index c38fcbdc8..17367a6cf 100644 --- a/Adjust/ADJActivityHandler.h +++ b/Adjust/ADJActivityHandler.h @@ -67,6 +67,7 @@ - (void)launchAttributionResponseTasks:(ADJAttributionResponseData *)attributionResponseData; - (void)setEnabled:(BOOL)enabled; - (BOOL)isEnabled; +- (BOOL)isGdprForgotten; - (void)appWillOpenUrl:(NSURL*)url; - (void)setDeviceToken:(NSData *)deviceToken; diff --git a/Adjust/ADJActivityHandler.m b/Adjust/ADJActivityHandler.m index b30185843..517d1ee07 100644 --- a/Adjust/ADJActivityHandler.m +++ b/Adjust/ADJActivityHandler.m @@ -331,6 +331,10 @@ - (BOOL)isEnabled { return [self isEnabledI:self]; } +- (BOOL)isGdprForgotten { + return [self isGdprForgottenI:self]; +} + - (NSString *)adid { if (self.activityState == nil) { return nil; @@ -1061,7 +1065,7 @@ - (void)setEnabledI:(ADJActivityHandler *)selfI enabled:(BOOL)enabled { // If user is forgotten, forbid re-enabling. if (enabled) { - if ([selfI isForgottenI:selfI]) { + if ([selfI isGdprForgottenI:selfI]) { [selfI.logger debug:@"Re-enabling SDK for forgotten user not allowed"]; return; } @@ -1356,19 +1360,19 @@ - (void)setGdprForgetMeI:(ADJActivityHandler *)selfI { #pragma mark - private -- (BOOL)isForgottenI:(ADJActivityHandler *)selfI { +- (BOOL)isEnabledI:(ADJActivityHandler *)selfI { if (selfI.activityState != nil) { - return selfI.activityState.isForgotten; + return selfI.activityState.enabled; } else { - return NO; + return [selfI.internalState isEnabled]; } } -- (BOOL)isEnabledI:(ADJActivityHandler *)selfI { +- (BOOL)isGdprForgottenI:(ADJActivityHandler *)selfI { if (selfI.activityState != nil) { - return selfI.activityState.enabled; + return selfI.activityState.isForgotten; } else { - return [selfI.internalState isEnabled]; + return NO; } } From d76b674bf9d7dce372c5df2bb188c4d568448784 Mon Sep 17 00:00:00 2001 From: uerceg Date: Tue, 10 Apr 2018 10:21:00 +0200 Subject: [PATCH 16/39] Further isForgotten -> isGdprForgotten renaming --- Adjust/ADJActivityHandler.m | 4 ++-- Adjust/ADJActivityState.h | 2 +- Adjust/ADJActivityState.m | 16 ++++++++-------- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Adjust/ADJActivityHandler.m b/Adjust/ADJActivityHandler.m index 517d1ee07..f3da9425d 100644 --- a/Adjust/ADJActivityHandler.m +++ b/Adjust/ADJActivityHandler.m @@ -1335,7 +1335,7 @@ - (void)setDeviceTokenI:(ADJActivityHandler *)selfI } - (void)setGdprForgetMeI:(ADJActivityHandler *)selfI { - selfI.activityState.isForgotten = YES; + selfI.activityState.isGdprForgotten = YES; [selfI writeActivityStateI:selfI]; // Send GDPR package @@ -1370,7 +1370,7 @@ - (BOOL)isEnabledI:(ADJActivityHandler *)selfI { - (BOOL)isGdprForgottenI:(ADJActivityHandler *)selfI { if (selfI.activityState != nil) { - return selfI.activityState.isForgotten; + return selfI.activityState.isGdprForgotten; } else { return NO; } diff --git a/Adjust/ADJActivityState.h b/Adjust/ADJActivityState.h index 44145e77d..45327850c 100644 --- a/Adjust/ADJActivityState.h +++ b/Adjust/ADJActivityState.h @@ -12,7 +12,7 @@ // Persistent data @property (nonatomic, assign) BOOL enabled; -@property (nonatomic, assign) BOOL isForgotten; +@property (nonatomic, assign) BOOL isGdprForgotten; @property (nonatomic, assign) BOOL askingAttribution; @property (nonatomic, copy) NSString *uuid; diff --git a/Adjust/ADJActivityState.m b/Adjust/ADJActivityState.m index 40a2fe414..df58eaeb9 100644 --- a/Adjust/ADJActivityState.m +++ b/Adjust/ADJActivityState.m @@ -36,7 +36,7 @@ - (id)init { self.lastActivity = -1; self.lastInterval = -1; self.enabled = YES; - self.isForgotten = NO; + self.isGdprForgotten = NO; self.askingAttribution = NO; self.deviceToken = nil; self.transactionIds = [NSMutableArray arrayWithCapacity:kTransactionIdCount]; @@ -151,9 +151,9 @@ - (NSString *)generateUniqueKey { } - (NSString *)description { - return [NSString stringWithFormat:@"ec:%d sc:%d ssc:%d ask:%d sl:%.1f ts:%.1f la:%.1f dt:%@ fgt:%d", + return [NSString stringWithFormat:@"ec:%d sc:%d ssc:%d ask:%d sl:%.1f ts:%.1f la:%.1f dt:%@ gdprf:%d", self.eventCount, self.sessionCount, self.subsessionCount, self.askingAttribution, self.sessionLength, - self.timeSpent, self.lastActivity, self.deviceToken, self.isForgotten]; + self.timeSpent, self.lastActivity, self.deviceToken, self.isGdprForgotten]; } #pragma mark - NSCoding protocol methods @@ -195,10 +195,10 @@ - (id)initWithCoder:(NSCoder *)decoder { self.enabled = YES; } - if ([decoder containsValueForKey:@"isForgotten"]) { - self.isForgotten = [decoder decodeBoolForKey:@"isForgotten"]; + if ([decoder containsValueForKey:@"isGdprForgotten"]) { + self.isGdprForgotten = [decoder decodeBoolForKey:@"isGdprForgotten"]; } else { - self.isForgotten = NO; + self.isGdprForgotten = NO; } if ([decoder containsValueForKey:@"askingAttribution"]) { @@ -240,7 +240,7 @@ - (void)encodeWithCoder:(NSCoder *)encoder { [encoder encodeObject:self.uuid forKey:@"uuid"]; [encoder encodeObject:self.transactionIds forKey:@"transactionIds"]; [encoder encodeBool:self.enabled forKey:@"enabled"]; - [encoder encodeBool:self.isForgotten forKey:@"isForgotten"]; + [encoder encodeBool:self.isGdprForgotten forKey:@"isGdprForgotten"]; [encoder encodeBool:self.askingAttribution forKey:@"askingAttribution"]; [encoder encodeObject:self.deviceToken forKey:@"deviceToken"]; [encoder encodeBool:self.updatePackages forKey:@"updatePackages"]; @@ -263,7 +263,7 @@ - (id)copyWithZone:(NSZone *)zone { copy.lastInterval = self.lastInterval; copy.eventCount = self.eventCount; copy.enabled = self.enabled; - copy.isForgotten = self.isForgotten; + copy.isGdprForgotten = self.isGdprForgotten; copy.lastActivity = self.lastActivity; copy.askingAttribution = self.askingAttribution; copy.deviceToken = [self.deviceToken copyWithZone:zone]; From 8a468f2f43b82bdf92239e4b2e56c0cbe875be20 Mon Sep 17 00:00:00 2001 From: uerceg Date: Tue, 10 Apr 2018 10:27:44 +0200 Subject: [PATCH 17/39] Don't send any attribution packages if user is forgotten --- Adjust/ADJAttributionHandler.m | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Adjust/ADJAttributionHandler.m b/Adjust/ADJAttributionHandler.m index 033ebf0a1..4bef0e10c 100644 --- a/Adjust/ADJAttributionHandler.m +++ b/Adjust/ADJAttributionHandler.m @@ -184,6 +184,10 @@ - (void)requestAttributionI:(ADJAttributionHandler*)selfI { [selfI.logger debug:@"Attribution handler is paused"]; return; } + if (selfI.activityHandler.isGdprForgotten) { + [selfI.logger debug:@"Attribution request won't be fired for forgotten user"]; + return; + } [selfI.logger verbose:@"%@", selfI.attributionPackage.extendedString]; NSURL * baseUrl = [NSURL URLWithString:[ADJAdjustFactory baseUrl]]; From 854d9c84f6b407de77ab76cfabef92e9b76d8836 Mon Sep 17 00:00:00 2001 From: uerceg Date: Tue, 10 Apr 2018 10:27:58 +0200 Subject: [PATCH 18/39] Don't send any sdk_click packages if user is forgotten --- Adjust/ADJSdkClickHandler.m | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Adjust/ADJSdkClickHandler.m b/Adjust/ADJSdkClickHandler.m index 8781c9063..d831fcfea 100644 --- a/Adjust/ADJSdkClickHandler.m +++ b/Adjust/ADJSdkClickHandler.m @@ -122,6 +122,10 @@ - (void)sendNextSdkClickI:(ADJSdkClickHandler *)selfI if (selfI.paused) return; NSUInteger queueSize = selfI.packageQueue.count; if (queueSize == 0) return; + if (selfI.activityHandler.isGdprForgotten) { + [selfI.logger debug:@"sdk_click request won't be fired for forgotten user"]; + return; + } ADJActivityPackage *sdkClickPackage = [self.packageQueue objectAtIndex:0]; [self.packageQueue removeObjectAtIndex:0]; From af4c708b9597478c7eab67f46cdf569ba63ba283 Mon Sep 17 00:00:00 2001 From: uerceg Date: Tue, 10 Apr 2018 10:54:05 +0200 Subject: [PATCH 19/39] ADJSdkClickHandler cleanup --- Adjust/ADJSdkClickHandler.h | 7 ++-- Adjust/ADJSdkClickHandler.m | 84 ++++++++++++++++++------------------- 2 files changed, 45 insertions(+), 46 deletions(-) diff --git a/Adjust/ADJSdkClickHandler.h b/Adjust/ADJSdkClickHandler.h index 3f8c63bcd..b74ddfda7 100644 --- a/Adjust/ADJSdkClickHandler.h +++ b/Adjust/ADJSdkClickHandler.h @@ -1,9 +1,9 @@ // // ADJSdkClickHandler.h -// Adjust +// Adjust SDK // -// Created by Pedro Filipe on 21/04/16. -// Copyright © 2016 adjust GmbH. All rights reserved. +// Created by Pedro Filipe (@nonelse) on 21st April 2016. +// Copyright © 2016 Adjust GmbH. All rights reserved. // #import @@ -14,7 +14,6 @@ - (id)initWithActivityHandler:(id)activityHandler startsSending:(BOOL)startsSending; - - (void)pauseSending; - (void)resumeSending; - (void)sendSdkClick:(ADJActivityPackage *)sdkClickPackage; diff --git a/Adjust/ADJSdkClickHandler.m b/Adjust/ADJSdkClickHandler.m index d831fcfea..df9f6f24f 100644 --- a/Adjust/ADJSdkClickHandler.m +++ b/Adjust/ADJSdkClickHandler.m @@ -1,55 +1,59 @@ // // ADJSdkClickHandler.m -// Adjust +// Adjust SDK // -// Created by Pedro Filipe on 21/04/16. -// Copyright © 2016 adjust GmbH. All rights reserved. +// Created by Pedro Filipe (@nonelse) on 21st April 2016. +// Copyright © 2016 Adjust GmbH. All rights reserved. // -#import "ADJSdkClickHandler.h" +#import "ADJUtil.h" #import "ADJLogger.h" #import "ADJAdjustFactory.h" +#import "ADJSdkClickHandler.h" #import "ADJBackoffStrategy.h" -#import "ADJUtil.h" -static const char * const kInternalQueueName = "com.adjust.SdkClickQueue"; +static const char * const kInternalQueueName = "com.adjust.SdkClickQueue"; -#pragma mark - private @interface ADJSdkClickHandler() +@property (nonatomic, copy) NSString *basePath; +@property (nonatomic, strong) NSMutableArray *packageQueue; @property (nonatomic, strong) dispatch_queue_t internalQueue; -@property (nonatomic, weak) id logger; -@property (nonatomic, strong) ADJBackoffStrategy * backoffStrategy; + @property (nonatomic, assign) BOOL paused; -@property (nonatomic, strong) NSMutableArray *packageQueue; +@property (nonatomic, strong) ADJBackoffStrategy *backoffStrategy; + +@property (nonatomic, weak) id logger; @property (nonatomic, weak) id activityHandler; -@property (nonatomic, copy) NSString *basePath; @end @implementation ADJSdkClickHandler +#pragma mark - Public class methods + + (id)handlerWithActivityHandler:(id)activityHandler - startsSending:(BOOL)startsSending -{ + startsSending:(BOOL)startsSending { return [[ADJSdkClickHandler alloc] initWithActivityHandler:activityHandler - startsSending:startsSending]; + startsSending:startsSending]; } +#pragma mark - Public instance methods + - (id)initWithActivityHandler:(id)activityHandler - startsSending:(BOOL)startsSending -{ + startsSending:(BOOL)startsSending { self = [super init]; - if (self == nil) return nil; + if (self == nil) { + return nil; + } self.internalQueue = dispatch_queue_create(kInternalQueueName, DISPATCH_QUEUE_SERIAL); - self.logger = ADJAdjustFactory.logger; self.basePath = [activityHandler getBasePath]; [ADJUtil launchInQueue:self.internalQueue selfInject:self - block:^(ADJSdkClickHandler * selfI) { + block:^(ADJSdkClickHandler *selfI) { [selfI initI:selfI activityHandler:activityHandler startsSending:startsSending]; @@ -63,14 +67,13 @@ - (void)pauseSending { - (void)resumeSending { self.paused = NO; - [self sendNextSdkClick]; } - (void)sendSdkClick:(ADJActivityPackage *)sdkClickPackage { [ADJUtil launchInQueue:self.internalQueue selfInject:self - block:^(ADJSdkClickHandler * selfI) { + block:^(ADJSdkClickHandler *selfI) { [selfI sendSdkClickI:selfI sdkClickPackage:sdkClickPackage]; }]; } @@ -78,16 +81,18 @@ - (void)sendSdkClick:(ADJActivityPackage *)sdkClickPackage { - (void)sendNextSdkClick { [ADJUtil launchInQueue:self.internalQueue selfInject:self - block:^(ADJSdkClickHandler * selfI) { + block:^(ADJSdkClickHandler *selfI) { [selfI sendNextSdkClickI:selfI]; }]; } - (void)teardown { [ADJAdjustFactory.logger verbose:@"ADJSdkClickHandler teardown"]; + if (self.packageQueue != nil) { [self.packageQueue removeAllObjects]; } + self.internalQueue = nil; self.logger = nil; self.backoffStrategy = nil; @@ -95,11 +100,11 @@ - (void)teardown { self.activityHandler = nil; } -#pragma mark - internal -- (void)initI:(ADJSdkClickHandler *)selfI +#pragma mark - Private & helper methods + +- (void)initI:(ADJSdkClickHandler *)selfI activityHandler:(id)activityHandler -startsSending:(BOOL)startsSending -{ + startsSending:(BOOL)startsSending { selfI.activityHandler = activityHandler; selfI.paused = !startsSending; selfI.backoffStrategy = [ADJAdjustFactory sdkClickHandlerBackoffStrategy]; @@ -107,21 +112,21 @@ - (void)initI:(ADJSdkClickHandler *)selfI } - (void)sendSdkClickI:(ADJSdkClickHandler *)selfI - sdkClickPackage:(ADJActivityPackage *)sdkClickPackage -{ + sdkClickPackage:(ADJActivityPackage *)sdkClickPackage { [selfI.packageQueue addObject:sdkClickPackage]; - [selfI.logger debug:@"Added sdk_click %d", selfI.packageQueue.count]; [selfI.logger verbose:@"%@", sdkClickPackage.extendedString]; - [selfI sendNextSdkClick]; } -- (void)sendNextSdkClickI:(ADJSdkClickHandler *)selfI -{ - if (selfI.paused) return; +- (void)sendNextSdkClickI:(ADJSdkClickHandler *)selfI { + if (selfI.paused) { + return; + } NSUInteger queueSize = selfI.packageQueue.count; - if (queueSize == 0) return; + if (queueSize == 0) { + return; + } if (selfI.activityHandler.isGdprForgotten) { [selfI.logger debug:@"sdk_click request won't be fired for forgotten user"]; return; @@ -132,14 +137,12 @@ - (void)sendNextSdkClickI:(ADJSdkClickHandler *)selfI if (![sdkClickPackage isKindOfClass:[ADJActivityPackage class]]) { [selfI.logger error:@"Failed to read sdk_click package"]; - [selfI sendNextSdkClick]; - return; } NSURL *url; - NSString * baseUrl = [ADJAdjustFactory baseUrl]; + NSString *baseUrl = [ADJAdjustFactory baseUrl]; if (selfI.basePath != nil) { url = [NSURL URLWithString:[NSString stringWithFormat:@"%@%@", baseUrl, selfI.basePath]]; } else { @@ -152,12 +155,10 @@ - (void)sendNextSdkClickI:(ADJSdkClickHandler *)selfI prefixErrorMessage:sdkClickPackage.failureMessage suffixErrorMessage:@"Will retry later" activityPackage:sdkClickPackage - responseDataHandler:^(ADJResponseData * responseData) - { + responseDataHandler:^(ADJResponseData *responseData) { if (responseData.jsonResponse == nil) { NSInteger retries = [sdkClickPackage increaseRetries]; [selfI.logger error:@"Retrying sdk_click package for the %d time", retries]; - [selfI sendSdkClick:sdkClickPackage]; return; } @@ -169,14 +170,13 @@ - (void)sendNextSdkClickI:(ADJSdkClickHandler *)selfI }; NSInteger retries = [sdkClickPackage retries]; - if (retries <= 0) { work(); return; } NSTimeInterval waitTime = [ADJUtil waitingTime:retries backoffStrategy:self.backoffStrategy]; - NSString * waitTimeFormatted = [ADJUtil secondsNumberFormat:waitTime]; + NSString *waitTimeFormatted = [ADJUtil secondsNumberFormat:waitTime]; [self.logger verbose:@"Waiting for %@ seconds before retrying sdk_click for the %d time", waitTimeFormatted, retries]; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(waitTime * NSEC_PER_SEC)), self.internalQueue, work); From 8da5bb5e77b854a55b0de1ac1819d06ea7f2d832 Mon Sep 17 00:00:00 2001 From: uerceg Date: Tue, 10 Apr 2018 14:28:21 +0200 Subject: [PATCH 20/39] Except tracking_state=opted_out from backend once user is forgotten --- Adjust/ADJRequestHandler.m | 14 ++++---------- Adjust/ADJResponseData.h | 6 ++++++ Adjust/ADJResponseData.m | 5 +++-- Adjust/ADJUtil.m | 7 +++++++ 4 files changed, 20 insertions(+), 12 deletions(-) diff --git a/Adjust/ADJRequestHandler.m b/Adjust/ADJRequestHandler.m index 984ea3d63..e470e3d8b 100644 --- a/Adjust/ADJRequestHandler.m +++ b/Adjust/ADJRequestHandler.m @@ -96,17 +96,11 @@ - (void)sendI:(ADJRequestHandler *)selfI activityPackage:(ADJActivityPackage *)a return; } - // Check if successfully sent package is GDPR forget me. + // Check if any package response contains information that user has opted out. // If yes, disable SDK and flush any potentially stored packages that happened afterwards. - if (activityPackage.activityKind == ADJActivityKindGdpr) { - // TODO: For now accept all answers to GDPR type of package. - // if (responseData.success) { - // TODO: Dummy string assumption, check with backend. - // if ([responseData.message containsString:@"user forgotten"]) { - [self.activityHandler setEnabled:NO]; - [self.packageHandler flush]; - // } - // } + if (responseData.trackingState == ADJTrackingStateOptedOut) { + [self.activityHandler setEnabled:NO]; + [self.packageHandler flush]; } [selfI.packageHandler sendNextPackage:responseData]; diff --git a/Adjust/ADJResponseData.h b/Adjust/ADJResponseData.h index 378a9bb03..edf0f6f6a 100644 --- a/Adjust/ADJResponseData.h +++ b/Adjust/ADJResponseData.h @@ -15,6 +15,10 @@ #import "ADJSessionFailure.h" #import "ADJActivityPackage.h" +typedef NS_ENUM(int, ADJTrackingState) { + ADJTrackingStateOptedOut = 1 +}; + @interface ADJResponseData : NSObject @property (nonatomic, assign) ADJActivityKind activityKind; @@ -29,6 +33,8 @@ @property (nonatomic, assign) BOOL willRetry; +@property (nonatomic, assign) ADJTrackingState trackingState; + @property (nonatomic, strong) NSDictionary *jsonResponse; @property (nonatomic, copy) ADJAttribution *attribution; diff --git a/Adjust/ADJResponseData.m b/Adjust/ADJResponseData.m index 9ca71e45b..a929a6095 100644 --- a/Adjust/ADJResponseData.m +++ b/Adjust/ADJResponseData.m @@ -60,8 +60,8 @@ + (id)buildResponseData:(ADJActivityPackage *)activityPackage { } - (NSString *)description { - return [NSString stringWithFormat:@"message:%@ timestamp:%@ adid:%@ success:%d willRetry:%d attribution:%@ json:%@", - self.message, self.timeStamp, self.adid, self.success, self.willRetry, self.attribution, self.jsonResponse]; + return [NSString stringWithFormat:@"message:%@ timestamp:%@ adid:%@ success:%d willRetry:%d attribution:%@ trackingState:%d, json:%@", + self.message, self.timeStamp, self.adid, self.success, self.willRetry, self.attribution, self.trackingState, self.jsonResponse]; } #pragma mark - NSCopying @@ -75,6 +75,7 @@ - (id)copyWithZone:(NSZone *)zone { copy.adid = [self.adid copyWithZone:zone]; copy.success = self.success; copy.willRetry = self.willRetry; + copy.trackingState = self.trackingState; copy.jsonResponse = [self.jsonResponse copyWithZone:zone]; copy.attribution = [self.attribution copyWithZone:zone]; } diff --git a/Adjust/ADJUtil.m b/Adjust/ADJUtil.m index d796ba92b..53b343adf 100644 --- a/Adjust/ADJUtil.m +++ b/Adjust/ADJUtil.m @@ -872,6 +872,13 @@ + (ADJResponseData *)completionHandler:(NSData *)data responseData.timeStamp = [responseData.jsonResponse objectForKey:@"timestamp"]; responseData.adid = [responseData.jsonResponse objectForKey:@"adid"]; + NSString *trackingState = [responseData.jsonResponse objectForKey:@"tracking_state"]; + if (trackingState != nil) { + if ([trackingState isEqualToString:@"opted_out"]) { + responseData.trackingState = ADJTrackingStateOptedOut; + } + } + if (messageResponse == nil) { messageResponse = @"No message found"; } From 28544dafd1bca2aa359f50fa24ffcfff282c4ca0 Mon Sep 17 00:00:00 2001 From: nonelse Date: Fri, 13 Apr 2018 10:17:12 +0200 Subject: [PATCH 21/39] Call trackingStateOptedOut from all responses --- Adjust/ADJActivityHandler.h | 1 + Adjust/ADJActivityHandler.m | 6 ++++++ Adjust/ADJAttributionHandler.m | 6 ++++++ Adjust/ADJRequestHandler.m | 3 +-- Adjust/ADJSdkClickHandler.m | 6 ++++++ 5 files changed, 20 insertions(+), 2 deletions(-) diff --git a/Adjust/ADJActivityHandler.h b/Adjust/ADJActivityHandler.h index 17367a6cf..e7b2f9c55 100644 --- a/Adjust/ADJActivityHandler.h +++ b/Adjust/ADJActivityHandler.h @@ -72,6 +72,7 @@ - (void)appWillOpenUrl:(NSURL*)url; - (void)setDeviceToken:(NSData *)deviceToken; - (void)setGdprForgetMe; +- (void)trackingStateOptedOut; - (void)setAskingAttribution:(BOOL)askingAttribution; - (BOOL)updateAttributionI:(id)selfI attribution:(ADJAttribution *)attribution; diff --git a/Adjust/ADJActivityHandler.m b/Adjust/ADJActivityHandler.m index f3da9425d..00e72c75f 100644 --- a/Adjust/ADJActivityHandler.m +++ b/Adjust/ADJActivityHandler.m @@ -366,6 +366,12 @@ - (void)setGdprForgetMe { }]; } +- (void)trackingStateOptedOut { + [self setEnabled:NO]; + [self.packageHandler flush]; +} + + - (void)setAttributionDetails:(NSDictionary *)attributionDetails error:(NSError *)error retriesLeft:(int)retriesLeft diff --git a/Adjust/ADJAttributionHandler.m b/Adjust/ADJAttributionHandler.m index 4bef0e10c..c596b4587 100644 --- a/Adjust/ADJAttributionHandler.m +++ b/Adjust/ADJAttributionHandler.m @@ -198,6 +198,12 @@ - (void)requestAttributionI:(ADJAttributionHandler*)selfI { activityPackage:selfI.attributionPackage responseDataHandler:^(ADJResponseData * responseData) { + // Check if any package response contains information that user has opted out. + // If yes, disable SDK and flush any potentially stored packages that happened afterwards. + if (responseData.trackingState == ADJTrackingStateOptedOut) { + [self.activityHandler trackingStateOptedOut]; + } + if ([responseData isKindOfClass:[ADJAttributionResponseData class]]) { [selfI checkAttributionResponse:(ADJAttributionResponseData*)responseData]; } diff --git a/Adjust/ADJRequestHandler.m b/Adjust/ADJRequestHandler.m index e470e3d8b..ff8a51637 100644 --- a/Adjust/ADJRequestHandler.m +++ b/Adjust/ADJRequestHandler.m @@ -99,8 +99,7 @@ - (void)sendI:(ADJRequestHandler *)selfI activityPackage:(ADJActivityPackage *)a // Check if any package response contains information that user has opted out. // If yes, disable SDK and flush any potentially stored packages that happened afterwards. if (responseData.trackingState == ADJTrackingStateOptedOut) { - [self.activityHandler setEnabled:NO]; - [self.packageHandler flush]; + [self.activityHandler trackingStateOptedOut]; } [selfI.packageHandler sendNextPackage:responseData]; diff --git a/Adjust/ADJSdkClickHandler.m b/Adjust/ADJSdkClickHandler.m index df9f6f24f..fe76602bc 100644 --- a/Adjust/ADJSdkClickHandler.m +++ b/Adjust/ADJSdkClickHandler.m @@ -163,6 +163,12 @@ - (void)sendNextSdkClickI:(ADJSdkClickHandler *)selfI { return; } + // Check if any package response contains information that user has opted out. + // If yes, disable SDK and flush any potentially stored packages that happened afterwards. + if (responseData.trackingState == ADJTrackingStateOptedOut) { + [self.activityHandler trackingStateOptedOut]; + } + [selfI.activityHandler finishedTracking:responseData]; }]; From 3ec39cd4220d5a2db75ea49138fe1f3660b114ed Mon Sep 17 00:00:00 2001 From: uerceg Date: Mon, 16 Apr 2018 13:27:01 +0200 Subject: [PATCH 22/39] Handling of GDPR URL path --- Adjust/ADJActivityHandler.h | 2 ++ Adjust/ADJActivityHandler.m | 8 +++++++ Adjust/ADJAdjustFactory.h | 2 ++ Adjust/ADJAdjustFactory.m | 11 ++++++++++ Adjust/ADJPackageHandler.h | 1 + Adjust/ADJPackageHandler.m | 6 ++++++ Adjust/ADJRequestHandler.m | 21 +++++++++++++++---- Adjust/Adjust.h | 2 ++ Adjust/Adjust.m | 6 ++++++ .../AdjustTestApp/ATAAdjustCommandExecutor.m | 13 ++++++++++-- .../AdjustTestApp/ViewController.h | 1 + 11 files changed, 67 insertions(+), 6 deletions(-) diff --git a/Adjust/ADJActivityHandler.h b/Adjust/ADJActivityHandler.h index e7b2f9c55..b450def12 100644 --- a/Adjust/ADJActivityHandler.h +++ b/Adjust/ADJActivityHandler.h @@ -42,6 +42,7 @@ @property (nonatomic, copy) NSNumber *enabled; @property (nonatomic, assign) BOOL offline; @property (nonatomic, copy) NSString *basePath; +@property (nonatomic, copy) NSString *gdprPath; - (id)init; @@ -93,6 +94,7 @@ - (void)resetSessionCallbackParameters; - (void)resetSessionPartnerParameters; - (NSString *)getBasePath; +- (NSString *)getGdprPath; - (void)teardown; + (void)deleteState; diff --git a/Adjust/ADJActivityHandler.m b/Adjust/ADJActivityHandler.m index 00e72c75f..1c106012b 100644 --- a/Adjust/ADJActivityHandler.m +++ b/Adjust/ADJActivityHandler.m @@ -102,6 +102,7 @@ @interface ADJActivityHandler() @property (nonatomic, copy) ADJConfig *adjustConfig; @property (nonatomic, copy) NSData* deviceTokenData; @property (nonatomic, copy) NSString* basePath; +@property (nonatomic, copy) NSString* gdprPath; @end @@ -192,6 +193,9 @@ - (id)initWithConfig:(ADJConfig *)adjustConfig if (savedPreLaunch.basePath != nil) { self.basePath = savedPreLaunch.basePath; } + if (savedPreLaunch.gdprPath != nil) { + self.gdprPath = savedPreLaunch.gdprPath; + } self.internalQueue = dispatch_queue_create(kInternalQueueName, DISPATCH_QUEUE_SERIAL); [ADJUtil launchInQueue:self.internalQueue @@ -551,6 +555,10 @@ - (NSString *)getBasePath { return _basePath; } +- (NSString *)getGdprPath { + return _gdprPath; +} + - (void)teardown { [ADJAdjustFactory.logger verbose:@"ADJActivityHandler teardown"]; diff --git a/Adjust/ADJAdjustFactory.h b/Adjust/ADJAdjustFactory.h index 85fd4ed40..e8d73160d 100644 --- a/Adjust/ADJAdjustFactory.h +++ b/Adjust/ADJAdjustFactory.h @@ -41,6 +41,7 @@ + (BOOL)testing; + (NSTimeInterval)maxDelayStart; + (NSString *)baseUrl; ++ (NSString *)gdprUrl; + (void)setPackageHandler:(id)packageHandler; + (void)setRequestHandler:(id)requestHandler; @@ -57,6 +58,7 @@ + (void)setTesting:(BOOL)testing; + (void)setMaxDelayStart:(NSTimeInterval)maxDelayStart; + (void)setBaseUrl:(NSString *)baseUrl; ++ (void)setGdprUrl:(NSString *)gdprUrl; + (void)teardown:(BOOL)deleteState; @end diff --git a/Adjust/ADJAdjustFactory.m b/Adjust/ADJAdjustFactory.m index 1030ab1dd..5f515eecf 100644 --- a/Adjust/ADJAdjustFactory.m +++ b/Adjust/ADJAdjustFactory.m @@ -26,6 +26,8 @@ static NSString * const kBaseUrl = @"https://app.adjust.com"; static NSString * internalBaseUrl = @"https://app.adjust.com"; +static NSString * const kGdprUrl = @"https://gdpr.adjust.com"; +static NSString * internalGdprUrl = @"https://gdpr.adjust.com"; @implementation ADJAdjustFactory @@ -150,6 +152,10 @@ + (NSString *)baseUrl { return internalBaseUrl; } ++ (NSString *)gdprUrl { + return internalGdprUrl; +} + + (void)setPackageHandler:(id)packageHandler { internalPackageHandler = packageHandler; } @@ -210,6 +216,10 @@ + (void)setBaseUrl:(NSString *)baseUrl { internalBaseUrl = baseUrl; } ++ (void)setGdprUrl:(NSString *)gdprUrl { + internalGdprUrl = gdprUrl; +} + + (void)teardown:(BOOL)deleteState { if (deleteState) { [ADJActivityHandler deleteState]; @@ -231,5 +241,6 @@ + (void)teardown:(BOOL)deleteState { internalTesting = NO; internalMaxDelayStart = -1; internalBaseUrl = kBaseUrl; + internalGdprUrl = kGdprUrl; } @end diff --git a/Adjust/ADJPackageHandler.h b/Adjust/ADJPackageHandler.h index a84442a94..a69a2df97 100644 --- a/Adjust/ADJPackageHandler.h +++ b/Adjust/ADJPackageHandler.h @@ -28,6 +28,7 @@ - (void)updatePackages:(ADJSessionParameters *)sessionParameters; - (void)flush; - (NSString *)getBasePath; +- (NSString *)getGdprPath; - (void)teardown; + (void)deleteState; diff --git a/Adjust/ADJPackageHandler.m b/Adjust/ADJPackageHandler.m index cb8bd3cf7..48f22115f 100644 --- a/Adjust/ADJPackageHandler.m +++ b/Adjust/ADJPackageHandler.m @@ -30,6 +30,7 @@ @interface ADJPackageHandler() @property (nonatomic, weak) id activityHandler; @property (nonatomic, weak) id logger; @property (nonatomic, copy) NSString *basePath; +@property (nonatomic, copy) NSString *gdprPath; @end @@ -51,6 +52,7 @@ - (id)initWithActivityHandler:(id)activityHandler self.internalQueue = dispatch_queue_create(kInternalQueueName, DISPATCH_QUEUE_SERIAL); self.backoffStrategy = [ADJAdjustFactory packageHandlerBackoffStrategy]; self.basePath = [activityHandler getBasePath]; + self.gdprPath = [activityHandler getGdprPath]; [ADJUtil launchInQueue:self.internalQueue selfInject:self @@ -145,6 +147,10 @@ - (NSString *)getBasePath { return _basePath; } +- (NSString *)getGdprPath { + return _gdprPath; +} + - (void)teardown { [ADJAdjustFactory.logger verbose:@"ADJPackageHandler teardown"]; if (self.sendingSemaphore != nil) { diff --git a/Adjust/ADJRequestHandler.m b/Adjust/ADJRequestHandler.m index ff8a51637..40fa98314 100644 --- a/Adjust/ADJRequestHandler.m +++ b/Adjust/ADJRequestHandler.m @@ -28,6 +28,8 @@ @interface ADJRequestHandler() @property (nonatomic, copy) NSString *basePath; +@property (nonatomic, copy) NSString *gdprPath; + @end @implementation ADJRequestHandler @@ -53,6 +55,7 @@ - (id)initWithPackageHandler:(id)packageHandler self.activityHandler = activityHandler; self.logger = ADJAdjustFactory.logger; self.basePath = [packageHandler getBasePath]; + self.gdprPath = [packageHandler getGdprPath]; return self; } @@ -77,11 +80,21 @@ - (void)teardown { - (void)sendI:(ADJRequestHandler *)selfI activityPackage:(ADJActivityPackage *)activityPackage queueSize:(NSUInteger)queueSize { NSURL *url; - NSString * baseUrl = [ADJAdjustFactory baseUrl]; - if (selfI.basePath != nil) { - url = [NSURL URLWithString:[NSString stringWithFormat:@"%@%@", baseUrl, selfI.basePath]]; + + if (activityPackage.activityKind == ADJActivityKindGdpr) { + NSString *gdprUrl = [ADJAdjustFactory gdprUrl]; + if (selfI.gdprPath != nil) { + url = [NSURL URLWithString:[NSString stringWithFormat:@"%@%@", gdprUrl, selfI.gdprPath]]; + } else { + url = [NSURL URLWithString:gdprUrl]; + } } else { - url = [NSURL URLWithString:baseUrl]; + NSString *baseUrl = [ADJAdjustFactory baseUrl]; + if (selfI.basePath != nil) { + url = [NSURL URLWithString:[NSString stringWithFormat:@"%@%@", baseUrl, selfI.basePath]]; + } else { + url = [NSURL URLWithString:baseUrl]; + } } [ADJUtil sendPostRequest:url diff --git a/Adjust/Adjust.h b/Adjust/Adjust.h index c4afd504c..0918d0c80 100644 --- a/Adjust/Adjust.h +++ b/Adjust/Adjust.h @@ -14,7 +14,9 @@ @interface AdjustTestOptions : NSObject @property (nonatomic, copy, nullable) NSString *baseUrl; +@property (nonatomic, copy, nullable) NSString *gdprUrl; @property (nonatomic, copy, nullable) NSString *basePath; +@property (nonatomic, copy, nullable) NSString *gdprPath; @property (nonatomic, copy, nullable) NSNumber *timerIntervalInMilliseconds; @property (nonatomic, copy, nullable) NSNumber *timerStartInMilliseconds; @property (nonatomic, copy, nullable) NSNumber *sessionIntervalInMilliseconds; diff --git a/Adjust/Adjust.m b/Adjust/Adjust.m index 418c2c2f5..6f18c4092 100644 --- a/Adjust/Adjust.m +++ b/Adjust/Adjust.m @@ -396,9 +396,15 @@ - (void)setTestOptions:(AdjustTestOptions *)testOptions { if (testOptions.basePath != nil) { self.savedPreLaunch.basePath = testOptions.basePath; } + if (testOptions.gdprPath != nil) { + self.savedPreLaunch.gdprPath = testOptions.gdprPath; + } if (testOptions.baseUrl != nil) { [ADJAdjustFactory setBaseUrl:testOptions.baseUrl]; } + if (testOptions.gdprUrl != nil) { + [ADJAdjustFactory setGdprUrl:testOptions.gdprUrl]; + } if (testOptions.timerIntervalInMilliseconds != nil) { NSTimeInterval timerIntervalInSeconds = [testOptions.timerIntervalInMilliseconds intValue] / 1000.0; [ADJAdjustFactory setTimerInterval:timerIntervalInSeconds]; diff --git a/AdjustTests/AdjustTestApp/AdjustTestApp/ATAAdjustCommandExecutor.m b/AdjustTests/AdjustTestApp/AdjustTestApp/ATAAdjustCommandExecutor.m index a620ad4e7..b5ab6a950 100644 --- a/AdjustTests/AdjustTestApp/AdjustTestApp/ATAAdjustCommandExecutor.m +++ b/AdjustTests/AdjustTestApp/AdjustTestApp/ATAAdjustCommandExecutor.m @@ -19,10 +19,11 @@ @interface ATAAdjustCommandExecutor () +@property (nonatomic, copy) NSString *basePath; +@property (nonatomic, copy) NSString *gdprPath; @property (nonatomic, strong) NSMutableDictionary *savedConfigs; @property (nonatomic, strong) NSMutableDictionary *savedEvents; @property (nonatomic, strong) NSObject *adjustDelegate; -@property (nonatomic, copy) NSString *basePath; @end @@ -39,6 +40,7 @@ - (id)init { self.savedEvents = [NSMutableDictionary dictionary]; self.adjustDelegate = nil; self.basePath = nil; + self.gdprPath = nil; return self; } @@ -90,10 +92,13 @@ - (void)executeCommand:(NSString *)className } - (void)testOptions:(NSDictionary *)parameters { - AdjustTestOptions * testOptions = [[AdjustTestOptions alloc] init]; + AdjustTestOptions *testOptions = [[AdjustTestOptions alloc] init]; testOptions.baseUrl = baseUrl; + testOptions.gdprUrl = gdprUrl; + if ([parameters objectForKey:@"basePath"]) { self.basePath = [parameters objectForKey:@"basePath"][0]; + self.gdprPath = [parameters objectForKey:@"basePath"][0]; } if ([parameters objectForKey:@"timerInterval"]) { NSString *timerIntervalMilliS = [parameters objectForKey:@"timerInterval"][0]; @@ -118,6 +123,7 @@ - (void)testOptions:(NSDictionary *)parameters { if ([teardownOption isEqualToString:@"resetSdk"]) { testOptions.teardown = YES; testOptions.basePath = self.basePath; + testOptions.gdprPath = self.gdprPath; } if ([teardownOption isEqualToString:@"deleteState"]) { testOptions.deleteState = YES; @@ -133,12 +139,14 @@ - (void)testOptions:(NSDictionary *)parameters { if ([teardownOption isEqualToString:@"sdk"]) { testOptions.teardown = YES; testOptions.basePath = nil; + testOptions.gdprPath = nil; } if ([teardownOption isEqualToString:@"test"]) { self.savedConfigs = nil; self.savedEvents = nil; self.adjustDelegate = nil; self.basePath = nil; + self.gdprPath = nil; testOptions.timerIntervalInMilliseconds = [NSNumber numberWithInt:-1000]; testOptions.timerStartInMilliseconds = [NSNumber numberWithInt:-1000]; testOptions.sessionIntervalInMilliseconds = [NSNumber numberWithInt:-1000]; @@ -146,6 +154,7 @@ - (void)testOptions:(NSDictionary *)parameters { } } } + [Adjust setTestOptions:testOptions]; } diff --git a/AdjustTests/AdjustTestApp/AdjustTestApp/ViewController.h b/AdjustTests/AdjustTestApp/AdjustTestApp/ViewController.h index 6dda4cee2..3ba3c3188 100644 --- a/AdjustTests/AdjustTestApp/AdjustTestApp/ViewController.h +++ b/AdjustTests/AdjustTestApp/AdjustTestApp/ViewController.h @@ -9,6 +9,7 @@ #import static NSString * baseUrl = @"http://127.0.0.1:8080"; +static NSString * gdprUrl = @"http://127.0.0.1:8080"; @interface ViewController : UIViewController From c739b66c0220c00fe9fa7b4265f2c05b762bf515 Mon Sep 17 00:00:00 2001 From: uerceg Date: Tue, 17 Apr 2018 12:43:35 +0200 Subject: [PATCH 23/39] Write isGdprForgotten in case of web opt out and sync activity handler opt out actions --- Adjust/ADJActivityHandler.h | 2 +- Adjust/ADJActivityHandler.m | 19 ++++++++++++++++--- Adjust/ADJAttributionHandler.m | 2 +- Adjust/ADJRequestHandler.m | 2 +- Adjust/ADJSdkClickHandler.m | 2 +- 5 files changed, 20 insertions(+), 7 deletions(-) diff --git a/Adjust/ADJActivityHandler.h b/Adjust/ADJActivityHandler.h index b450def12..2070ffdc8 100644 --- a/Adjust/ADJActivityHandler.h +++ b/Adjust/ADJActivityHandler.h @@ -73,7 +73,7 @@ - (void)appWillOpenUrl:(NSURL*)url; - (void)setDeviceToken:(NSData *)deviceToken; - (void)setGdprForgetMe; -- (void)trackingStateOptedOut; +- (void)setTrackingStateOptedOut; - (void)setAskingAttribution:(BOOL)askingAttribution; - (BOOL)updateAttributionI:(id)selfI attribution:(ADJAttribution *)attribution; diff --git a/Adjust/ADJActivityHandler.m b/Adjust/ADJActivityHandler.m index 1c106012b..26ad3296c 100644 --- a/Adjust/ADJActivityHandler.m +++ b/Adjust/ADJActivityHandler.m @@ -370,9 +370,12 @@ - (void)setGdprForgetMe { }]; } -- (void)trackingStateOptedOut { - [self setEnabled:NO]; - [self.packageHandler flush]; +- (void)setTrackingStateOptedOut { + [ADJUtil launchInQueue:self.internalQueue + selfInject:self + block:^(ADJActivityHandler * selfI) { + [selfI setTrackingStateOptedOutI:selfI]; + }]; } @@ -1372,6 +1375,16 @@ - (void)setGdprForgetMeI:(ADJActivityHandler *)selfI { } } +- (void)setTrackingStateOptedOutI:(ADJActivityHandler *)selfI { + // In case of web opt out, once response from backend arrives isGdprForgotten field in this moment defaults to NO. + // Set it to YES regardless of state, since at this moment it should be YES. + selfI.activityState.isGdprForgotten = YES; + [selfI writeActivityStateI:selfI]; + + [selfI setEnabled:NO]; + [selfI.packageHandler flush]; +} + #pragma mark - private - (BOOL)isEnabledI:(ADJActivityHandler *)selfI { diff --git a/Adjust/ADJAttributionHandler.m b/Adjust/ADJAttributionHandler.m index c596b4587..b90e463ae 100644 --- a/Adjust/ADJAttributionHandler.m +++ b/Adjust/ADJAttributionHandler.m @@ -201,7 +201,7 @@ - (void)requestAttributionI:(ADJAttributionHandler*)selfI { // Check if any package response contains information that user has opted out. // If yes, disable SDK and flush any potentially stored packages that happened afterwards. if (responseData.trackingState == ADJTrackingStateOptedOut) { - [self.activityHandler trackingStateOptedOut]; + [self.activityHandler setTrackingStateOptedOut]; } if ([responseData isKindOfClass:[ADJAttributionResponseData class]]) { diff --git a/Adjust/ADJRequestHandler.m b/Adjust/ADJRequestHandler.m index 40fa98314..9d020514c 100644 --- a/Adjust/ADJRequestHandler.m +++ b/Adjust/ADJRequestHandler.m @@ -112,7 +112,7 @@ - (void)sendI:(ADJRequestHandler *)selfI activityPackage:(ADJActivityPackage *)a // Check if any package response contains information that user has opted out. // If yes, disable SDK and flush any potentially stored packages that happened afterwards. if (responseData.trackingState == ADJTrackingStateOptedOut) { - [self.activityHandler trackingStateOptedOut]; + [self.activityHandler setTrackingStateOptedOut]; } [selfI.packageHandler sendNextPackage:responseData]; diff --git a/Adjust/ADJSdkClickHandler.m b/Adjust/ADJSdkClickHandler.m index fe76602bc..49bf61380 100644 --- a/Adjust/ADJSdkClickHandler.m +++ b/Adjust/ADJSdkClickHandler.m @@ -166,7 +166,7 @@ - (void)sendNextSdkClickI:(ADJSdkClickHandler *)selfI { // Check if any package response contains information that user has opted out. // If yes, disable SDK and flush any potentially stored packages that happened afterwards. if (responseData.trackingState == ADJTrackingStateOptedOut) { - [self.activityHandler trackingStateOptedOut]; + [self.activityHandler setTrackingStateOptedOut]; } [selfI.activityHandler finishedTracking:responseData]; From d0f0ad58719d06bb2c914b04ad5cf403bd2f568f Mon Sep 17 00:00:00 2001 From: uerceg Date: Tue, 17 Apr 2018 13:06:17 +0200 Subject: [PATCH 24/39] Don't send forget package for already fogotten user due to defaults caching --- Adjust/ADJActivityHandler.m | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Adjust/ADJActivityHandler.m b/Adjust/ADJActivityHandler.m index 26ad3296c..6ee8ce239 100644 --- a/Adjust/ADJActivityHandler.m +++ b/Adjust/ADJActivityHandler.m @@ -1352,6 +1352,11 @@ - (void)setDeviceTokenI:(ADJActivityHandler *)selfI } - (void)setGdprForgetMeI:(ADJActivityHandler *)selfI { + if (selfI.activityState.isGdprForgotten == YES) { + [ADJUserDefaults removeGdprForgetMe]; + return; + } + selfI.activityState.isGdprForgotten = YES; [selfI writeActivityStateI:selfI]; From 7732cc6f8023b32991d762d6372b56c3b607ae61 Mon Sep 17 00:00:00 2001 From: uerceg Date: Tue, 17 Apr 2018 17:10:13 +0200 Subject: [PATCH 25/39] Save new enabled state sooner upon (re)enabling --- Adjust/ADJActivityHandler.m | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Adjust/ADJActivityHandler.m b/Adjust/ADJActivityHandler.m index 6ee8ce239..95a1c4aba 100644 --- a/Adjust/ADJActivityHandler.m +++ b/Adjust/ADJActivityHandler.m @@ -1100,6 +1100,10 @@ - (void)setEnabledI:(ADJActivityHandler *)selfI enabled:(BOOL)enabled { return; } + // Save new enabled state in activity state. + selfI.activityState.enabled = enabled; + [selfI writeActivityStateI:selfI]; + // Check if upon enabling install has been tracked. if (enabled) { if (![ADJUserDefaults getInstallTracked]) { @@ -1118,10 +1122,6 @@ - (void)setEnabledI:(ADJActivityHandler *)selfI enabled:(BOOL)enabled { } } - // save new enabled state in activity state - selfI.activityState.enabled = enabled; - [selfI writeActivityStateI:selfI]; - [selfI checkStatusI:selfI pausingState:!enabled pausingMessage:@"Pausing handlers due to SDK being disabled" From 55dbd7f7cd1e7a75efaa3bcd0397c8b26c26a397 Mon Sep 17 00:00:00 2001 From: uerceg Date: Tue, 17 Apr 2018 20:49:23 +0200 Subject: [PATCH 26/39] New version 4.12.3 --- Adjust.podspec | 4 ++-- Adjust/ADJUtil.m | 2 +- Adjust/Adjust.h | 2 +- AdjustTests/AdjustTestApp/AdjustTestApp/ViewController.m | 2 +- AdjustTests/AdjustUnitTests/ADJPackageFields.m | 2 +- README.md | 4 ++-- VERSION | 2 +- doc/english/migrate.md | 2 +- doc/japanese/migrate_ja.md | 2 +- doc/migrate.md | 2 +- 10 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Adjust.podspec b/Adjust.podspec index 445c89093..ae51132a3 100644 --- a/Adjust.podspec +++ b/Adjust.podspec @@ -1,11 +1,11 @@ Pod::Spec.new do |s| s.name = "Adjust" - s.version = "4.12.3" + s.version = "4.13.0" s.summary = "This is the iOS SDK of adjust. You can read more about it at http://adjust.com." s.homepage = "https://github.com/adjust/ios_sdk" s.license = { :type => 'MIT', :file => 'MIT-LICENSE' } s.author = { "Christian Wellenbrock" => "welle@adjust.com" } - s.source = { :git => "https://github.com/adjust/ios_sdk.git", :tag => "v4.12.3" } + s.source = { :git => "https://github.com/adjust/ios_sdk.git", :tag => "v4.13.0" } s.ios.deployment_target = '6.0' s.tvos.deployment_target = '9.0' s.framework = 'SystemConfiguration' diff --git a/Adjust/ADJUtil.m b/Adjust/ADJUtil.m index 53b343adf..cf00eeab9 100644 --- a/Adjust/ADJUtil.m +++ b/Adjust/ADJUtil.m @@ -41,7 +41,7 @@ static NSString *userAgent = nil; -static NSString * const kClientSdk = @"ios4.12.3"; +static NSString * const kClientSdk = @"ios4.13.0"; static NSString * const kDeeplinkParam = @"deep_link="; static NSString * const kSchemeDelimiter = @"://"; static NSString * const kDefaultScheme = @"AdjustUniversalScheme"; diff --git a/Adjust/Adjust.h b/Adjust/Adjust.h index 0918d0c80..d2fca9a10 100644 --- a/Adjust/Adjust.h +++ b/Adjust/Adjust.h @@ -2,7 +2,7 @@ // Adjust.h // Adjust // -// V4.12.3 +// V4.13.0 // Created by Christian Wellenbrock (wellle) on 23rd July 2013. // Copyright © 2012-2017 Adjust GmbH. All rights reserved. // diff --git a/AdjustTests/AdjustTestApp/AdjustTestApp/ViewController.m b/AdjustTests/AdjustTestApp/AdjustTestApp/ViewController.m index 80552bd99..7e956bfdb 100644 --- a/AdjustTests/AdjustTestApp/AdjustTestApp/ViewController.m +++ b/AdjustTests/AdjustTestApp/AdjustTestApp/ViewController.m @@ -37,7 +37,7 @@ - (void)viewDidLoad { } - (void)startTestSession { - [self.testLibrary startTestSession:@"ios4.12.3"]; + [self.testLibrary startTestSession:@"ios4.13.0"]; } - (void)didReceiveMemoryWarning { diff --git a/AdjustTests/AdjustUnitTests/ADJPackageFields.m b/AdjustTests/AdjustUnitTests/ADJPackageFields.m index 068da236a..351007fb6 100644 --- a/AdjustTests/AdjustUnitTests/ADJPackageFields.m +++ b/AdjustTests/AdjustUnitTests/ADJPackageFields.m @@ -16,7 +16,7 @@ - (id) init { // default values self.appToken = @"qwerty123456"; - self.clientSdk = @"ios4.12.3"; + self.clientSdk = @"ios4.13.0"; self.suffix = @""; self.environment = @"sandbox"; diff --git a/README.md b/README.md index c1a9dd642..2f661de5d 100644 --- a/README.md +++ b/README.md @@ -67,13 +67,13 @@ We will describe the steps to integrate the adjust SDK into your iOS project. We If you're using [CocoaPods][cocoapods], you can add the following line to your `Podfile` and continue from [this step](#sdk-integrate): ```ruby -pod 'Adjust', '~> 4.12.3' +pod 'Adjust', '~> 4.13.0' ``` or: ```ruby -pod 'Adjust', :git => 'https://github.com/adjust/ios_sdk.git', :tag => 'v4.12.3' +pod 'Adjust', :git => 'https://github.com/adjust/ios_sdk.git', :tag => 'v4.13.0' ``` --- diff --git a/VERSION b/VERSION index d140ced1c..813b83b65 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -4.12.3 +4.13.0 diff --git a/doc/english/migrate.md b/doc/english/migrate.md index b3fca2602..10de70383 100644 --- a/doc/english/migrate.md +++ b/doc/english/migrate.md @@ -1,4 +1,4 @@ -## Migrate your adjust SDK for iOS to v4.12.3 from v3.4.0 +## Migrate your adjust SDK for iOS to v4.13.0 from v3.4.0 ### Initial setup diff --git a/doc/japanese/migrate_ja.md b/doc/japanese/migrate_ja.md index 2c7766780..07d26a30b 100644 --- a/doc/japanese/migrate_ja.md +++ b/doc/japanese/migrate_ja.md @@ -1,4 +1,4 @@ -## iOS用adjust SDKのv3.4.0からv4.12.3への移行 +## iOS用adjust SDKのv3.4.0からv4.13.0への移行 ### 初期設定 diff --git a/doc/migrate.md b/doc/migrate.md index b3fca2602..10de70383 100644 --- a/doc/migrate.md +++ b/doc/migrate.md @@ -1,4 +1,4 @@ -## Migrate your adjust SDK for iOS to v4.12.3 from v3.4.0 +## Migrate your adjust SDK for iOS to v4.13.0 from v3.4.0 ### Initial setup From 26adfdcf9bea0a7367873d4ce581666df87397d7 Mon Sep 17 00:00:00 2001 From: uerceg Date: Fri, 20 Apr 2018 09:57:26 +0200 Subject: [PATCH 27/39] Small cleanups from GDPR PR --- Adjust/ADJAttributionHandler.m | 4 ++-- Adjust/ADJRequestHandler.m | 3 ++- Adjust/ADJSdkClickHandler.m | 4 ++-- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/Adjust/ADJAttributionHandler.m b/Adjust/ADJAttributionHandler.m index b90e463ae..878b43ab1 100644 --- a/Adjust/ADJAttributionHandler.m +++ b/Adjust/ADJAttributionHandler.m @@ -184,7 +184,7 @@ - (void)requestAttributionI:(ADJAttributionHandler*)selfI { [selfI.logger debug:@"Attribution handler is paused"]; return; } - if (selfI.activityHandler.isGdprForgotten) { + if ([selfI.activityHandler isGdprForgotten]) { [selfI.logger debug:@"Attribution request won't be fired for forgotten user"]; return; } @@ -201,7 +201,7 @@ - (void)requestAttributionI:(ADJAttributionHandler*)selfI { // Check if any package response contains information that user has opted out. // If yes, disable SDK and flush any potentially stored packages that happened afterwards. if (responseData.trackingState == ADJTrackingStateOptedOut) { - [self.activityHandler setTrackingStateOptedOut]; + [selfI.activityHandler setTrackingStateOptedOut]; } if ([responseData isKindOfClass:[ADJAttributionResponseData class]]) { diff --git a/Adjust/ADJRequestHandler.m b/Adjust/ADJRequestHandler.m index 9d020514c..ce9ea61e9 100644 --- a/Adjust/ADJRequestHandler.m +++ b/Adjust/ADJRequestHandler.m @@ -74,6 +74,7 @@ - (void)teardown { self.logger = nil; self.internalQueue = nil; self.packageHandler = nil; + self.activityHandler = nil; } #pragma mark - Private & helper methods @@ -112,7 +113,7 @@ - (void)sendI:(ADJRequestHandler *)selfI activityPackage:(ADJActivityPackage *)a // Check if any package response contains information that user has opted out. // If yes, disable SDK and flush any potentially stored packages that happened afterwards. if (responseData.trackingState == ADJTrackingStateOptedOut) { - [self.activityHandler setTrackingStateOptedOut]; + [selfI.activityHandler setTrackingStateOptedOut]; } [selfI.packageHandler sendNextPackage:responseData]; diff --git a/Adjust/ADJSdkClickHandler.m b/Adjust/ADJSdkClickHandler.m index 49bf61380..c3eecbd7b 100644 --- a/Adjust/ADJSdkClickHandler.m +++ b/Adjust/ADJSdkClickHandler.m @@ -127,7 +127,7 @@ - (void)sendNextSdkClickI:(ADJSdkClickHandler *)selfI { if (queueSize == 0) { return; } - if (selfI.activityHandler.isGdprForgotten) { + if ([selfI.activityHandler isGdprForgotten]) { [selfI.logger debug:@"sdk_click request won't be fired for forgotten user"]; return; } @@ -166,7 +166,7 @@ - (void)sendNextSdkClickI:(ADJSdkClickHandler *)selfI { // Check if any package response contains information that user has opted out. // If yes, disable SDK and flush any potentially stored packages that happened afterwards. if (responseData.trackingState == ADJTrackingStateOptedOut) { - [self.activityHandler setTrackingStateOptedOut]; + [selfI.activityHandler setTrackingStateOptedOut]; } [selfI.activityHandler finishedTracking:responseData]; From 0ce05e3489d12f10a9e29666e5feb89635ba4a10 Mon Sep 17 00:00:00 2001 From: uerceg Date: Wed, 25 Apr 2018 11:05:39 +0200 Subject: [PATCH 28/39] Sync behaviour with Android and Windows --- Adjust/ADJActivityHandler.m | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/Adjust/ADJActivityHandler.m b/Adjust/ADJActivityHandler.m index 95a1c4aba..4f9743b5a 100644 --- a/Adjust/ADJActivityHandler.m +++ b/Adjust/ADJActivityHandler.m @@ -669,8 +669,10 @@ - (void)initI:(ADJActivityHandler *)selfI } } - if ([ADJUserDefaults getGdprForgetMe]) { - [selfI setGdprForgetMe]; + if (selfI.activityState != nil) { + if ([ADJUserDefaults getGdprForgetMe]) { + [selfI setGdprForgetMe]; + } } selfI.foregroundTimer = [ADJTimerCycle timerWithBlock:^{ @@ -774,6 +776,8 @@ - (void)processSessionI:(ADJActivityHandler *)selfI { if (![ADJUserDefaults getGdprForgetMe]) { selfI.activityState.sessionCount = 1; // this is the first session [selfI transferSessionPackageI:selfI now:now]; + } else { + [selfI setGdprForgetMeI:selfI]; } } @@ -1352,6 +1356,12 @@ - (void)setDeviceTokenI:(ADJActivityHandler *)selfI } - (void)setGdprForgetMeI:(ADJActivityHandler *)selfI { + if (![selfI isEnabledI:selfI]) { + return; + } + if (!selfI.activityState) { + return; + } if (selfI.activityState.isGdprForgotten == YES) { [ADJUserDefaults removeGdprForgetMe]; return; From 2b13626fd5d1a22fcb1dd3a4c1a8d6add8efca88 Mon Sep 17 00:00:00 2001 From: uerceg Date: Wed, 25 Apr 2018 11:09:50 +0200 Subject: [PATCH 29/39] Add PREFS_KEY_GDPR_FORGET_ME to clearAdjustStuff method --- Adjust/ADJUserDefaults.m | 1 + 1 file changed, 1 insertion(+) diff --git a/Adjust/ADJUserDefaults.m b/Adjust/ADJUserDefaults.m index 290e0a7b6..09d92b853 100644 --- a/Adjust/ADJUserDefaults.m +++ b/Adjust/ADJUserDefaults.m @@ -56,6 +56,7 @@ + (void)removeGdprForgetMe { + (void)clearAdjustStuff { [[NSUserDefaults standardUserDefaults] removeObjectForKey:PREFS_KEY_PUSH_TOKEN]; [[NSUserDefaults standardUserDefaults] removeObjectForKey:PREFS_KEY_INSTALL_TRACKED]; + [[NSUserDefaults standardUserDefaults] removeObjectForKey:PREFS_KEY_GDPR_FORGET_ME]; [[NSUserDefaults standardUserDefaults] synchronize]; } From 5960abb1eac434d0fbe8eec40fa5c6fa5a11ad99 Mon Sep 17 00:00:00 2001 From: uerceg Date: Wed, 25 Apr 2018 11:14:37 +0200 Subject: [PATCH 30/39] Test app cleanup --- .../AdjustTestApp/ATAAdjustCommandExecutor.h | 4 +- .../AdjustTestApp/ATAAdjustCommandExecutor.m | 38 ++++++------------- .../AdjustTestApp/AdjustTestApp/AppDelegate.h | 6 +-- .../AdjustTestApp/AdjustTestApp/AppDelegate.m | 11 +----- .../AdjustTestApp/ViewController.h | 4 +- .../AdjustTestApp/ViewController.m | 22 +++++------ 6 files changed, 30 insertions(+), 55 deletions(-) diff --git a/AdjustTests/AdjustTestApp/AdjustTestApp/ATAAdjustCommandExecutor.h b/AdjustTests/AdjustTestApp/AdjustTestApp/ATAAdjustCommandExecutor.h index c3282565d..f63688305 100644 --- a/AdjustTests/AdjustTestApp/AdjustTestApp/ATAAdjustCommandExecutor.h +++ b/AdjustTests/AdjustTestApp/AdjustTestApp/ATAAdjustCommandExecutor.h @@ -2,8 +2,8 @@ // ATAAdjustCommandExecutor.h // AdjustTestApp // -// Created by Pedro da Silva (@nonelse) on 23rd August 2017. -// Copyright © 2017 Adjust GmbH. All rights reserved. +// Created by Pedro Silva (@nonelse) on 23rd August 2017. +// Copyright © 2017-2018 Adjust GmbH. All rights reserved. // #import diff --git a/AdjustTests/AdjustTestApp/AdjustTestApp/ATAAdjustCommandExecutor.m b/AdjustTests/AdjustTestApp/AdjustTestApp/ATAAdjustCommandExecutor.m index b5ab6a950..879b9fab7 100644 --- a/AdjustTests/AdjustTestApp/AdjustTestApp/ATAAdjustCommandExecutor.m +++ b/AdjustTests/AdjustTestApp/AdjustTestApp/ATAAdjustCommandExecutor.m @@ -2,8 +2,8 @@ // ATAAdjustCommandExecutor.m // AdjustTestApp // -// Created by Pedro da Silva (@nonelse) on 23rd August 2017. -// Copyright © 2017 Adjust GmbH. All rights reserved. +// Created by Pedro Silva (@nonelse) on 23rd August 2017. +// Copyright © 2017-2018 Adjust GmbH. All rights reserved. // #import "Adjust.h" @@ -261,41 +261,36 @@ - (void)config:(NSDictionary *)parameters { if ([parameters objectForKey:@"attributionCallbackSendAll"]) { NSLog(@"attributionCallbackSendAll detected"); - - self.adjustDelegate = [[ATAAdjustDelegateAttribution alloc] initWithTestLibrary:self.testLibrary andBasePath:self.basePath]; - + self.adjustDelegate = [[ATAAdjustDelegateAttribution alloc] initWithTestLibrary:self.testLibrary + andBasePath:self.basePath]; // swizzleAttributionCallback = YES; } if ([parameters objectForKey:@"sessionCallbackSendSuccess"]) { NSLog(@"sessionCallbackSendSuccess detected"); - - self.adjustDelegate = [[ATAAdjustDelegateSessionSuccess alloc] initWithTestLibrary:self.testLibrary andBasePath:self.basePath]; - + self.adjustDelegate = [[ATAAdjustDelegateSessionSuccess alloc] initWithTestLibrary:self.testLibrary + andBasePath:self.basePath]; // swizzleSessionSuccessCallback = YES; } if ([parameters objectForKey:@"sessionCallbackSendFailure"]) { NSLog(@"sessionCallbackSendFailure detected"); - - self.adjustDelegate = [[ATAAdjustDelegateSessionFailure alloc] initWithTestLibrary:self.testLibrary andBasePath:self.basePath]; - + self.adjustDelegate = [[ATAAdjustDelegateSessionFailure alloc] initWithTestLibrary:self.testLibrary + andBasePath:self.basePath]; // swizzleSessionFailureCallback = YES; } if ([parameters objectForKey:@"eventCallbackSendSuccess"]) { NSLog(@"eventCallbackSendSuccess detected"); - - self.adjustDelegate = [[ATAAdjustDelegateEventSuccess alloc] initWithTestLibrary:self.testLibrary andBasePath:self.basePath]; - + self.adjustDelegate = [[ATAAdjustDelegateEventSuccess alloc] initWithTestLibrary:self.testLibrary + andBasePath:self.basePath]; // swizzleEventSuccessCallback = YES; } if ([parameters objectForKey:@"eventCallbackSendFailure"]) { NSLog(@"eventCallbackSendFailure detected"); - - self.adjustDelegate = [[ATAAdjustDelegateEventFailure alloc] initWithTestLibrary:self.testLibrary andBasePath:self.basePath]; - + self.adjustDelegate = [[ATAAdjustDelegateEventFailure alloc] initWithTestLibrary:self.testLibrary + andBasePath:self.basePath]; // swizzleEventFailureCallback = YES; } @@ -314,7 +309,6 @@ - (void)start:(NSDictionary *)parameters { [self config:parameters]; NSNumber *configNumber = [NSNumber numberWithInt:0]; - if ([parameters objectForKey:@"configName"]) { NSString *configName = [parameters objectForKey:@"configName"][0]; NSString *configNumberS = [configName substringFromIndex:[configName length] - 1]; @@ -322,15 +316,12 @@ - (void)start:(NSDictionary *)parameters { } ADJConfig *adjustConfig = [self.savedConfigs objectForKey:configNumber]; - [Adjust appDidLaunch:adjustConfig]; - [self.savedConfigs removeObjectForKey:[NSNumber numberWithInt:0]]; } - (void)event:(NSDictionary *)parameters { NSNumber *eventNumber = [NSNumber numberWithInt:0]; - if ([parameters objectForKey:@"eventName"]) { NSString *eventName = [parameters objectForKey:@"eventName"][0]; NSString *eventNumberS = [eventName substringFromIndex:[eventName length] - 1]; @@ -343,7 +334,6 @@ - (void)event:(NSDictionary *)parameters { adjustEvent = [self.savedEvents objectForKey:eventNumber]; } else { NSString *eventToken = [parameters objectForKey:@"eventToken"][0]; - adjustEvent = [ADJEvent eventWithEventToken:eventToken]; [self.savedEvents setObject:adjustEvent forKey:eventNumber]; } @@ -352,7 +342,6 @@ - (void)event:(NSDictionary *)parameters { NSArray *currencyAndRevenue = [parameters objectForKey:@"revenue"]; NSString *currency = currencyAndRevenue[0]; double revenue = [currencyAndRevenue[1] doubleValue]; - [adjustEvent setRevenue:revenue currency:currency]; } @@ -387,7 +376,6 @@ - (void)trackEvent:(NSDictionary *)parameters { [self event:parameters]; NSNumber *eventNumber = [NSNumber numberWithInt:0]; - if ([parameters objectForKey:@"eventName"]) { NSString *eventName = [parameters objectForKey:@"eventName"][0]; NSString *eventNumberS = [eventName substringFromIndex:[eventName length] - 1]; @@ -395,9 +383,7 @@ - (void)trackEvent:(NSDictionary *)parameters { } ADJEvent *adjustEvent = [self.savedEvents objectForKey:eventNumber]; - [Adjust trackEvent:adjustEvent]; - [self.savedEvents removeObjectForKey:[NSNumber numberWithInt:0]]; } diff --git a/AdjustTests/AdjustTestApp/AdjustTestApp/AppDelegate.h b/AdjustTests/AdjustTestApp/AdjustTestApp/AppDelegate.h index cd4666705..3c4b6f468 100644 --- a/AdjustTests/AdjustTestApp/AdjustTestApp/AppDelegate.h +++ b/AdjustTests/AdjustTestApp/AdjustTestApp/AppDelegate.h @@ -2,8 +2,8 @@ // AppDelegate.h // AdjustTestApp // -// Created by Pedro on 23.08.17. -// Copyright © 2017 adjust. All rights reserved. +// Created by Pedro Silva (@nonelse) on 23rd August 2017. +// Copyright © 2017-2018 Adjust GmbH. All rights reserved. // #import @@ -12,6 +12,4 @@ @property (strong, nonatomic) UIWindow *window; - @end - diff --git a/AdjustTests/AdjustTestApp/AdjustTestApp/AppDelegate.m b/AdjustTests/AdjustTestApp/AdjustTestApp/AppDelegate.m index 2ca9ff07f..34bfc054c 100644 --- a/AdjustTests/AdjustTestApp/AdjustTestApp/AppDelegate.m +++ b/AdjustTests/AdjustTestApp/AdjustTestApp/AppDelegate.m @@ -2,8 +2,8 @@ // AppDelegate.m // AdjustTestApp // -// Created by Pedro on 23.08.17. -// Copyright © 2017 adjust. All rights reserved. +// Created by Pedro Silva (@nonelse) on 23rd August 2017. +// Copyright © 2017-2018 Adjust GmbH. All rights reserved. // #import "AppDelegate.h" @@ -14,38 +14,31 @@ @interface AppDelegate () @implementation AppDelegate - - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { // Override point for customization after application launch. return YES; } - - (void)applicationWillResignActive:(UIApplication *)application { // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. } - - (void)applicationDidEnterBackground:(UIApplication *)application { // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. } - - (void)applicationWillEnterForeground:(UIApplication *)application { // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. } - - (void)applicationDidBecomeActive:(UIApplication *)application { // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. } - - (void)applicationWillTerminate:(UIApplication *)application { // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. } - @end diff --git a/AdjustTests/AdjustTestApp/AdjustTestApp/ViewController.h b/AdjustTests/AdjustTestApp/AdjustTestApp/ViewController.h index 3ba3c3188..80b41dd90 100644 --- a/AdjustTests/AdjustTestApp/AdjustTestApp/ViewController.h +++ b/AdjustTests/AdjustTestApp/AdjustTestApp/ViewController.h @@ -2,8 +2,8 @@ // ViewController.h // AdjustTestApp // -// Created by Pedro on 23.08.17. -// Copyright © 2017 adjust. All rights reserved. +// Created by Pedro Silva (@nonelse) on 23rd August 2017. +// Copyright © 2017-2018 Adjust GmbH. All rights reserved. // #import diff --git a/AdjustTests/AdjustTestApp/AdjustTestApp/ViewController.m b/AdjustTests/AdjustTestApp/AdjustTestApp/ViewController.m index 7e956bfdb..bfc1ce488 100644 --- a/AdjustTests/AdjustTestApp/AdjustTestApp/ViewController.m +++ b/AdjustTests/AdjustTestApp/AdjustTestApp/ViewController.m @@ -2,19 +2,20 @@ // ViewController.m // AdjustTestApp // -// Created by Pedro on 23.08.17. -// Copyright © 2017 adjust. All rights reserved. +// Created by Pedro Silva (@nonelse) on 23rd August 2017. +// Copyright © 2017-2018 Adjust GmbH. All rights reserved. // -#import "ViewController.h" #import "Adjust.h" +#import "ViewController.h" #import "ATLTestLibrary.h" -#import "ATAAdjustCommandExecutor.h" #import "ADJAdjustFactory.h" +#import "ATAAdjustCommandExecutor.h" @interface ViewController () -@property (nonatomic, strong) ATLTestLibrary * testLibrary; -@property (nonatomic, strong) ATAAdjustCommandExecutor * adjustCommandExecutor; + +@property (nonatomic, strong) ATLTestLibrary *testLibrary; +@property (nonatomic, strong) ATAAdjustCommandExecutor *adjustCommandExecutor; @end @@ -22,12 +23,10 @@ @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; - // Do any additional setup after loading the view, typically from a nib. self.adjustCommandExecutor = [[ATAAdjustCommandExecutor alloc] init]; - - self.testLibrary = [ATLTestLibrary testLibraryWithBaseUrl:baseUrl andCommandDelegate:self.adjustCommandExecutor]; - + self.testLibrary = [ATLTestLibrary testLibraryWithBaseUrl:baseUrl + andCommandDelegate:self.adjustCommandExecutor]; [self.adjustCommandExecutor setTestLibrary:self.testLibrary]; // [self.testLibrary addTestDirectory:@"current/sdkInfo"]; @@ -42,11 +41,10 @@ - (void)startTestSession { - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; - // Dispose of any resources that can be recreated. } + - (IBAction)restartTestClick:(UIButton *)sender { [self startTestSession]; } - @end From d6274ae0d8c3ac830a5fbc0ba0c5f55379cb391a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uglje=C5=A1a=20Erceg?= Date: Thu, 26 Apr 2018 15:54:53 +0200 Subject: [PATCH 31/39] Update CHANGELOG.md --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ca27be8b1..7449cc35f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +### Version 4.13.0 (27th April 2018) +#### Added +- Added `gdprForgetMe` method to `Adjust` interface to enable possibility for user to be forgotten in accordance with GDPR law. + +--- + ### Version 4.12.3 (23rd February 2018) #### Added - Added `AdjustTestLibraryStatic` target to the project. From bb6d0271204cd591ed14e22f4b19f730613f4103 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uglje=C5=A1a=20Erceg?= Date: Thu, 26 Apr 2018 16:08:39 +0200 Subject: [PATCH 32/39] Update README.md --- README.md | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 2f661de5d..5735605c9 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ ## Summary -This is the iOS SDK of adjust™. You can read more about adjust™ at [adjust.com]. +This is the iOS SDK of Adjust™. You can read more about Adjust™ at [adjust.com]. If your app is an app which uses web views you would like to use adjust tracking from Javascript code, please consult our [iOS web views SDK guide][ios-web-views-guide]. @@ -30,6 +30,7 @@ If your app is an app which uses web views you would like to use adjust tracking * [Disable tracking](#disable-tracking) * [Offline mode](#offline-mode) * [Event buffering](#event-buffering) + * [GDPR right to be forgotten](#gdpr-forget-me) * [SDK signature](#sdk-signature) * [Background tracking](#background-tracking) * [Device IDs](#device-ids) @@ -512,6 +513,16 @@ If your app makes heavy use of event tracking, you might want to delay some HTTP If nothing is set, event buffering is **disabled by default**. +### GDPR right to be forgotten + +In accordance with article 17 of the EU's General Data Protection Regulation (GDPR), you can notify Adjust when a user has exercised their right to be forgotten. Calling the following method will instruct the Adjust SDK to communicate the user's choice to be forgotten to the Adjust backend: + +```objc +[Adjust gdprForgetMe]; +``` + +Upon receiving this information, Adjust will erase the user's data and the Adjust SDK will stop tracking the user. No requests from this device will be sent to Adjust in the future. + ### SDK signature The Adjust SDK signature is enabled on a client-by-client basis. If you are interested in using this feature, please contact your account manager. From 319b3120585f7c353aa694ba0e6b118a29d44d66 Mon Sep 17 00:00:00 2001 From: uerceg Date: Thu, 26 Apr 2018 19:41:27 +0200 Subject: [PATCH 33/39] Retry on HTTP 429 --- Adjust/ADJUtil.m | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Adjust/ADJUtil.m b/Adjust/ADJUtil.m index cf00eeab9..54b9783ea 100644 --- a/Adjust/ADJUtil.m +++ b/Adjust/ADJUtil.m @@ -860,6 +860,11 @@ + (ADJResponseData *)completionHandler:(NSData *)data NSInteger statusCode = urlResponse.statusCode; [ADJAdjustFactory.logger verbose:@"Response: %@", responseString]; + + if (statusCode == 429) { + return responseData; + } + [ADJUtil saveJsonResponse:data responseData:responseData]; if ([ADJUtil isNull:responseData.jsonResponse]) { From b812f5a34ffab92867c34f4cc9500788d24ed1c8 Mon Sep 17 00:00:00 2001 From: uerceg Date: Thu, 26 Apr 2018 19:42:10 +0200 Subject: [PATCH 34/39] Return after noticing about being opted out --- Adjust/ADJRequestHandler.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Adjust/ADJRequestHandler.m b/Adjust/ADJRequestHandler.m index ce9ea61e9..de93fc4de 100644 --- a/Adjust/ADJRequestHandler.m +++ b/Adjust/ADJRequestHandler.m @@ -106,7 +106,6 @@ - (void)sendI:(ADJRequestHandler *)selfI activityPackage:(ADJActivityPackage *)a responseDataHandler:^(ADJResponseData *responseData) { if (responseData.jsonResponse == nil) { [selfI.packageHandler closeFirstPackage:responseData activityPackage:activityPackage]; - return; } @@ -114,6 +113,7 @@ - (void)sendI:(ADJRequestHandler *)selfI activityPackage:(ADJActivityPackage *)a // If yes, disable SDK and flush any potentially stored packages that happened afterwards. if (responseData.trackingState == ADJTrackingStateOptedOut) { [selfI.activityHandler setTrackingStateOptedOut]; + return; } [selfI.packageHandler sendNextPackage:responseData]; From d8478383525cef93d45ac3320f0e918976c65879 Mon Sep 17 00:00:00 2001 From: uerceg Date: Fri, 27 Apr 2018 00:14:40 +0200 Subject: [PATCH 35/39] Return after setTrackingStateOptedOut --- Adjust/ADJAttributionHandler.m | 1 + Adjust/ADJSdkClickHandler.m | 1 + 2 files changed, 2 insertions(+) diff --git a/Adjust/ADJAttributionHandler.m b/Adjust/ADJAttributionHandler.m index 878b43ab1..b6fafc384 100644 --- a/Adjust/ADJAttributionHandler.m +++ b/Adjust/ADJAttributionHandler.m @@ -202,6 +202,7 @@ - (void)requestAttributionI:(ADJAttributionHandler*)selfI { // If yes, disable SDK and flush any potentially stored packages that happened afterwards. if (responseData.trackingState == ADJTrackingStateOptedOut) { [selfI.activityHandler setTrackingStateOptedOut]; + return; } if ([responseData isKindOfClass:[ADJAttributionResponseData class]]) { diff --git a/Adjust/ADJSdkClickHandler.m b/Adjust/ADJSdkClickHandler.m index c3eecbd7b..2d1430eaa 100644 --- a/Adjust/ADJSdkClickHandler.m +++ b/Adjust/ADJSdkClickHandler.m @@ -167,6 +167,7 @@ - (void)sendNextSdkClickI:(ADJSdkClickHandler *)selfI { // If yes, disable SDK and flush any potentially stored packages that happened afterwards. if (responseData.trackingState == ADJTrackingStateOptedOut) { [selfI.activityHandler setTrackingStateOptedOut]; + return; } [selfI.activityHandler finishedTracking:responseData]; From c29fc30d998c76f8e929747c5827c21a7333e56a Mon Sep 17 00:00:00 2001 From: uerceg Date: Fri, 27 Apr 2018 08:24:45 +0200 Subject: [PATCH 36/39] Close the door for session creation if isGdprForgotten --- Adjust/ADJActivityHandler.m | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Adjust/ADJActivityHandler.m b/Adjust/ADJActivityHandler.m index 4f9743b5a..d84cbec37 100644 --- a/Adjust/ADJActivityHandler.m +++ b/Adjust/ADJActivityHandler.m @@ -821,11 +821,13 @@ - (void)processSessionI:(ADJActivityHandler *)selfI { } - (void)trackNewSessionI:(double)now withActivityHandler:(ADJActivityHandler *)selfI { - double lastInterval = now - selfI.activityState.lastActivity; + if (selfI.activityState.isGdprForgotten) { + return; + } + double lastInterval = now - selfI.activityState.lastActivity; selfI.activityState.sessionCount++; selfI.activityState.lastInterval = lastInterval; - [selfI transferSessionPackageI:selfI now:now]; [selfI.activityState resetSessionAttributes:now]; [selfI writeActivityStateI:selfI]; From 59b83bf5b3ebcf241e8c0d53ae17428f2e76d9bc Mon Sep 17 00:00:00 2001 From: uerceg Date: Fri, 27 Apr 2018 09:28:31 +0200 Subject: [PATCH 37/39] Add log message for 429 case --- Adjust/ADJUtil.m | 1 + 1 file changed, 1 insertion(+) diff --git a/Adjust/ADJUtil.m b/Adjust/ADJUtil.m index 54b9783ea..7ab079c32 100644 --- a/Adjust/ADJUtil.m +++ b/Adjust/ADJUtil.m @@ -862,6 +862,7 @@ + (ADJResponseData *)completionHandler:(NSData *)data [ADJAdjustFactory.logger verbose:@"Response: %@", responseString]; if (statusCode == 429) { + [ADJAdjustFactory.logger error:@"Too frequent requests to the endpoint (429)"]; return responseData; } From 7506af45707bb7558dac2914ba3d043339571be0 Mon Sep 17 00:00:00 2001 From: uerceg Date: Fri, 27 Apr 2018 09:28:46 +0200 Subject: [PATCH 38/39] Check for isGdprForgotten first --- Adjust/ADJRequestHandler.m | 9 ++++----- Adjust/ADJSdkClickHandler.m | 13 ++++++------- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/Adjust/ADJRequestHandler.m b/Adjust/ADJRequestHandler.m index de93fc4de..5e8e1bc90 100644 --- a/Adjust/ADJRequestHandler.m +++ b/Adjust/ADJRequestHandler.m @@ -104,17 +104,16 @@ - (void)sendI:(ADJRequestHandler *)selfI activityPackage:(ADJActivityPackage *)a suffixErrorMessage:@"Will retry later" activityPackage:activityPackage responseDataHandler:^(ADJResponseData *responseData) { - if (responseData.jsonResponse == nil) { - [selfI.packageHandler closeFirstPackage:responseData activityPackage:activityPackage]; - return; - } - // Check if any package response contains information that user has opted out. // If yes, disable SDK and flush any potentially stored packages that happened afterwards. if (responseData.trackingState == ADJTrackingStateOptedOut) { [selfI.activityHandler setTrackingStateOptedOut]; return; } + if (responseData.jsonResponse == nil) { + [selfI.packageHandler closeFirstPackage:responseData activityPackage:activityPackage]; + return; + } [selfI.packageHandler sendNextPackage:responseData]; }]; diff --git a/Adjust/ADJSdkClickHandler.m b/Adjust/ADJSdkClickHandler.m index 2d1430eaa..fe8da9019 100644 --- a/Adjust/ADJSdkClickHandler.m +++ b/Adjust/ADJSdkClickHandler.m @@ -156,19 +156,18 @@ - (void)sendNextSdkClickI:(ADJSdkClickHandler *)selfI { suffixErrorMessage:@"Will retry later" activityPackage:sdkClickPackage responseDataHandler:^(ADJResponseData *responseData) { - if (responseData.jsonResponse == nil) { - NSInteger retries = [sdkClickPackage increaseRetries]; - [selfI.logger error:@"Retrying sdk_click package for the %d time", retries]; - [selfI sendSdkClick:sdkClickPackage]; - return; - } - // Check if any package response contains information that user has opted out. // If yes, disable SDK and flush any potentially stored packages that happened afterwards. if (responseData.trackingState == ADJTrackingStateOptedOut) { [selfI.activityHandler setTrackingStateOptedOut]; return; } + if (responseData.jsonResponse == nil) { + NSInteger retries = [sdkClickPackage increaseRetries]; + [selfI.logger error:@"Retrying sdk_click package for the %d time", retries]; + [selfI sendSdkClick:sdkClickPackage]; + return; + } [selfI.activityHandler finishedTracking:responseData]; }]; From 64ecfb53c51e732f68a55c96a709d77226e92023 Mon Sep 17 00:00:00 2001 From: uerceg Date: Fri, 27 Apr 2018 13:43:38 +0200 Subject: [PATCH 39/39] Close the doors for setDeviceToken and trackEvent if isGdprForgotten --- Adjust/ADJActivityHandler.m | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Adjust/ADJActivityHandler.m b/Adjust/ADJActivityHandler.m index d84cbec37..54ddd6ba5 100644 --- a/Adjust/ADJActivityHandler.m +++ b/Adjust/ADJActivityHandler.m @@ -882,6 +882,7 @@ - (void)eventI:(ADJActivityHandler *)selfI if (![selfI isEnabledI:selfI]) return; if (![selfI checkEventI:selfI event:event]) return; if (![selfI checkTransactionIdI:selfI transactionId:event.transactionId]) return; + if (selfI.activityState.isGdprForgotten) { return; } double now = [NSDate.date timeIntervalSince1970]; @@ -1320,6 +1321,9 @@ - (void)setDeviceTokenI:(ADJActivityHandler *)selfI if (!selfI.activityState) { return; } + if (selfI.activityState.isGdprForgotten) { + return; + } NSString *deviceTokenString = [ADJUtil convertDeviceToken:deviceToken];