Skip to content

Commit ccfec7d

Browse files
authored
Merge pull request #329 from adjust/v4130
Version 4.13.0
2 parents 593ac06 + 64ecfb5 commit ccfec7d

40 files changed

+483
-156
lines changed

Adjust.podspec

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
Pod::Spec.new do |s|
22
s.name = "Adjust"
3-
s.version = "4.12.3"
3+
s.version = "4.13.0"
44
s.summary = "This is the iOS SDK of adjust. You can read more about it at http://adjust.com."
55
s.homepage = "https://github.com/adjust/ios_sdk"
66
s.license = { :type => 'MIT', :file => 'MIT-LICENSE' }
77
s.author = { "Christian Wellenbrock" => "[email protected]" }
8-
s.source = { :git => "https://github.com/adjust/ios_sdk.git", :tag => "v4.12.3" }
8+
s.source = { :git => "https://github.com/adjust/ios_sdk.git", :tag => "v4.13.0" }
99
s.ios.deployment_target = '6.0'
1010
s.tvos.deployment_target = '9.0'
1111
s.framework = 'SystemConfiguration'
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3+
<plist version="1.0">
4+
<dict>
5+
<key>IDEDidComputeMac32BitWarning</key>
6+
<true/>
7+
</dict>
8+
</plist>

Adjust/ADJActivityHandler.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
@property (nonatomic, copy) NSNumber *enabled;
4343
@property (nonatomic, assign) BOOL offline;
4444
@property (nonatomic, copy) NSString *basePath;
45+
@property (nonatomic, copy) NSString *gdprPath;
4546

4647
- (id)init;
4748

@@ -67,10 +68,12 @@
6768
- (void)launchAttributionResponseTasks:(ADJAttributionResponseData *)attributionResponseData;
6869
- (void)setEnabled:(BOOL)enabled;
6970
- (BOOL)isEnabled;
71+
- (BOOL)isGdprForgotten;
7072

7173
- (void)appWillOpenUrl:(NSURL*)url;
7274
- (void)setDeviceToken:(NSData *)deviceToken;
73-
75+
- (void)setGdprForgetMe;
76+
- (void)setTrackingStateOptedOut;
7477
- (void)setAskingAttribution:(BOOL)askingAttribution;
7578

7679
- (BOOL)updateAttributionI:(id<ADJActivityHandler>)selfI attribution:(ADJAttribution *)attribution;
@@ -91,6 +94,7 @@
9194
- (void)resetSessionCallbackParameters;
9295
- (void)resetSessionPartnerParameters;
9396
- (NSString *)getBasePath;
97+
- (NSString *)getGdprPath;
9498

9599
- (void)teardown;
96100
+ (void)deleteState;

Adjust/ADJActivityHandler.m

Lines changed: 121 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ @interface ADJActivityHandler()
102102
@property (nonatomic, copy) ADJConfig *adjustConfig;
103103
@property (nonatomic, copy) NSData* deviceTokenData;
104104
@property (nonatomic, copy) NSString* basePath;
105+
@property (nonatomic, copy) NSString* gdprPath;
105106

106107
@end
107108

@@ -192,6 +193,9 @@ - (id)initWithConfig:(ADJConfig *)adjustConfig
192193
if (savedPreLaunch.basePath != nil) {
193194
self.basePath = savedPreLaunch.basePath;
194195
}
196+
if (savedPreLaunch.gdprPath != nil) {
197+
self.gdprPath = savedPreLaunch.gdprPath;
198+
}
195199

196200
self.internalQueue = dispatch_queue_create(kInternalQueueName, DISPATCH_QUEUE_SERIAL);
197201
[ADJUtil launchInQueue:self.internalQueue
@@ -201,11 +205,12 @@ - (id)initWithConfig:(ADJConfig *)adjustConfig
201205
preLaunchActionsArray:savedPreLaunch.preLaunchActionsArray];
202206
}];
203207

204-
208+
/* Not needed, done already in initI:preLaunchActionsArray: method.
205209
// self.deviceTokenData = savedPreLaunch.deviceTokenData;
206210
if (self.activityState != nil) {
207211
[self setDeviceToken:[ADJUserDefaults getPushToken]];
208212
}
213+
*/
209214

210215
[self addNotificationObserver];
211216

@@ -330,6 +335,10 @@ - (BOOL)isEnabled {
330335
return [self isEnabledI:self];
331336
}
332337

338+
- (BOOL)isGdprForgotten {
339+
return [self isGdprForgottenI:self];
340+
}
341+
333342
- (NSString *)adid {
334343
if (self.activityState == nil) {
335344
return nil;
@@ -353,6 +362,23 @@ - (void)setDeviceToken:(NSData *)deviceToken {
353362
}];
354363
}
355364

365+
- (void)setGdprForgetMe {
366+
[ADJUtil launchInQueue:self.internalQueue
367+
selfInject:self
368+
block:^(ADJActivityHandler * selfI) {
369+
[selfI setGdprForgetMeI:selfI];
370+
}];
371+
}
372+
373+
- (void)setTrackingStateOptedOut {
374+
[ADJUtil launchInQueue:self.internalQueue
375+
selfInject:self
376+
block:^(ADJActivityHandler * selfI) {
377+
[selfI setTrackingStateOptedOutI:selfI];
378+
}];
379+
}
380+
381+
356382
- (void)setAttributionDetails:(NSDictionary *)attributionDetails
357383
error:(NSError *)error
358384
retriesLeft:(int)retriesLeft
@@ -532,6 +558,10 @@ - (NSString *)getBasePath {
532558
return _basePath;
533559
}
534560

561+
- (NSString *)getGdprPath {
562+
return _gdprPath;
563+
}
564+
535565
- (void)teardown
536566
{
537567
[ADJAdjustFactory.logger verbose:@"ADJActivityHandler teardown"];
@@ -635,11 +665,16 @@ - (void)initI:(ADJActivityHandler *)selfI
635665
} else {
636666
if (selfI.activityState != nil) {
637667
NSData *deviceToken = [ADJUserDefaults getPushToken];
638-
639668
[selfI setDeviceToken:deviceToken];
640669
}
641670
}
642671

672+
if (selfI.activityState != nil) {
673+
if ([ADJUserDefaults getGdprForgetMe]) {
674+
[selfI setGdprForgetMe];
675+
}
676+
}
677+
643678
selfI.foregroundTimer = [ADJTimerCycle timerWithBlock:^{
644679
[selfI foregroundTimerFired];
645680
}
@@ -737,8 +772,13 @@ - (void)processSessionI:(ADJActivityHandler *)selfI {
737772

738773
// track the first session package only if it's enabled
739774
if ([selfI.internalState isEnabled]) {
740-
selfI.activityState.sessionCount = 1; // this is the first session
741-
[selfI transferSessionPackageI:selfI now:now];
775+
// If user chose to be forgotten before install has ever tracked, don't track it.
776+
if (![ADJUserDefaults getGdprForgetMe]) {
777+
selfI.activityState.sessionCount = 1; // this is the first session
778+
[selfI transferSessionPackageI:selfI now:now];
779+
} else {
780+
[selfI setGdprForgetMeI:selfI];
781+
}
742782
}
743783

744784
[selfI.activityState resetSessionAttributes:now];
@@ -781,11 +821,13 @@ - (void)processSessionI:(ADJActivityHandler *)selfI {
781821
}
782822

783823
- (void)trackNewSessionI:(double)now withActivityHandler:(ADJActivityHandler *)selfI {
784-
double lastInterval = now - selfI.activityState.lastActivity;
824+
if (selfI.activityState.isGdprForgotten) {
825+
return;
826+
}
785827

828+
double lastInterval = now - selfI.activityState.lastActivity;
786829
selfI.activityState.sessionCount++;
787830
selfI.activityState.lastInterval = lastInterval;
788-
789831
[selfI transferSessionPackageI:selfI now:now];
790832
[selfI.activityState resetSessionAttributes:now];
791833
[selfI writeActivityStateI:selfI];
@@ -840,6 +882,7 @@ - (void)eventI:(ADJActivityHandler *)selfI
840882
if (![selfI isEnabledI:selfI]) return;
841883
if (![selfI checkEventI:selfI event:event]) return;
842884
if (![selfI checkTransactionIdI:selfI transactionId:event.transactionId]) return;
885+
if (selfI.activityState.isGdprForgotten) { return; }
843886

844887
double now = [NSDate.date timeIntervalSince1970];
845888

@@ -1044,6 +1087,14 @@ - (void)setEnabledI:(ADJActivityHandler *)selfI enabled:(BOOL)enabled {
10441087
return;
10451088
}
10461089

1090+
// If user is forgotten, forbid re-enabling.
1091+
if (enabled) {
1092+
if ([selfI isGdprForgottenI:selfI]) {
1093+
[selfI.logger debug:@"Re-enabling SDK for forgotten user not allowed"];
1094+
return;
1095+
}
1096+
}
1097+
10471098
// save new enabled state in internal state
10481099
selfI.internalState.enabled = enabled;
10491100

@@ -1056,6 +1107,10 @@ - (void)setEnabledI:(ADJActivityHandler *)selfI enabled:(BOOL)enabled {
10561107
return;
10571108
}
10581109

1110+
// Save new enabled state in activity state.
1111+
selfI.activityState.enabled = enabled;
1112+
[selfI writeActivityStateI:selfI];
1113+
10591114
// Check if upon enabling install has been tracked.
10601115
if (enabled) {
10611116
if (![ADJUserDefaults getInstallTracked]) {
@@ -1068,12 +1123,12 @@ - (void)setEnabledI:(ADJActivityHandler *)selfI enabled:(BOOL)enabled {
10681123
if (deviceToken != nil && ![selfI.activityState.deviceToken isEqualToString:[ADJUtil convertDeviceToken:deviceToken]]) {
10691124
[self setDeviceToken:deviceToken];
10701125
}
1126+
1127+
if ([ADJUserDefaults getGdprForgetMe]) {
1128+
[selfI setGdprForgetMe];
1129+
}
10711130
}
10721131

1073-
// save new enabled state in activity state
1074-
selfI.activityState.enabled = enabled;
1075-
[selfI writeActivityStateI:selfI];
1076-
10771132
[selfI checkStatusI:selfI
10781133
pausingState:!enabled
10791134
pausingMessage:@"Pausing handlers due to SDK being disabled"
@@ -1266,6 +1321,9 @@ - (void)setDeviceTokenI:(ADJActivityHandler *)selfI
12661321
if (!selfI.activityState) {
12671322
return;
12681323
}
1324+
if (selfI.activityState.isGdprForgotten) {
1325+
return;
1326+
}
12691327

12701328
NSString *deviceTokenString = [ADJUtil convertDeviceToken:deviceToken];
12711329

@@ -1303,6 +1361,51 @@ - (void)setDeviceTokenI:(ADJActivityHandler *)selfI
13031361
}
13041362
}
13051363

1364+
- (void)setGdprForgetMeI:(ADJActivityHandler *)selfI {
1365+
if (![selfI isEnabledI:selfI]) {
1366+
return;
1367+
}
1368+
if (!selfI.activityState) {
1369+
return;
1370+
}
1371+
if (selfI.activityState.isGdprForgotten == YES) {
1372+
[ADJUserDefaults removeGdprForgetMe];
1373+
return;
1374+
}
1375+
1376+
selfI.activityState.isGdprForgotten = YES;
1377+
[selfI writeActivityStateI:selfI];
1378+
1379+
// Send GDPR package
1380+
double now = [NSDate.date timeIntervalSince1970];
1381+
ADJPackageBuilder *gdprBuilder = [[ADJPackageBuilder alloc] initWithDeviceInfo:selfI.deviceInfo
1382+
activityState:selfI.activityState
1383+
config:selfI.adjustConfig
1384+
sessionParameters:selfI.sessionParameters
1385+
createdAt:now];
1386+
1387+
ADJActivityPackage *gdprPackage = [gdprBuilder buildGdprPackage];
1388+
[selfI.packageHandler addPackage:gdprPackage];
1389+
1390+
[ADJUserDefaults removeGdprForgetMe];
1391+
1392+
if (selfI.adjustConfig.eventBufferingEnabled) {
1393+
[selfI.logger info:@"Buffered gdpr %@", gdprPackage.suffix];
1394+
} else {
1395+
[selfI.packageHandler sendFirstPackage];
1396+
}
1397+
}
1398+
1399+
- (void)setTrackingStateOptedOutI:(ADJActivityHandler *)selfI {
1400+
// In case of web opt out, once response from backend arrives isGdprForgotten field in this moment defaults to NO.
1401+
// Set it to YES regardless of state, since at this moment it should be YES.
1402+
selfI.activityState.isGdprForgotten = YES;
1403+
[selfI writeActivityStateI:selfI];
1404+
1405+
[selfI setEnabled:NO];
1406+
[selfI.packageHandler flush];
1407+
}
1408+
13061409
#pragma mark - private
13071410

13081411
- (BOOL)isEnabledI:(ADJActivityHandler *)selfI {
@@ -1313,6 +1416,14 @@ - (BOOL)isEnabledI:(ADJActivityHandler *)selfI {
13131416
}
13141417
}
13151418

1419+
- (BOOL)isGdprForgottenI:(ADJActivityHandler *)selfI {
1420+
if (selfI.activityState != nil) {
1421+
return selfI.activityState.isGdprForgotten;
1422+
} else {
1423+
return NO;
1424+
}
1425+
}
1426+
13161427
- (BOOL)itHasToUpdatePackagesI:(ADJActivityHandler *)selfI {
13171428
if (selfI.activityState != nil) {
13181429
return selfI.activityState.updatePackages;

Adjust/ADJActivityKind.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ typedef NS_ENUM(int, ADJActivityKind) {
2020
ADJActivityKindClick = 4,
2121
ADJActivityKindAttribution = 5,
2222
ADJActivityKindInfo = 6,
23+
ADJActivityKindGdpr = 7
2324
};
2425

2526
@interface ADJActivityKindUtil : NSObject

Adjust/ADJActivityKind.m

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ + (ADJActivityKind)activityKindFromString:(NSString *)activityKindString {
2323
return ADJActivityKindAttribution;
2424
} else if ([@"info" isEqualToString:activityKindString]) {
2525
return ADJActivityKindInfo;
26+
} else if ([@"gdpr" isEqualToString:activityKindString]) {
27+
return ADJActivityKindGdpr;
2628
} else {
2729
return ADJActivityKindUnknown;
2830
}
@@ -40,6 +42,8 @@ + (NSString *)activityKindToString:(ADJActivityKind)activityKind {
4042
return @"attribution";
4143
case ADJActivityKindInfo:
4244
return @"info";
45+
case ADJActivityKindGdpr:
46+
return @"gdpr";
4347
default:
4448
return @"unknown";
4549
}

Adjust/ADJActivityState.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
// Persistent data
1414
@property (nonatomic, assign) BOOL enabled;
15+
@property (nonatomic, assign) BOOL isGdprForgotten;
1516
@property (nonatomic, assign) BOOL askingAttribution;
1617

1718
@property (nonatomic, copy) NSString *uuid;

Adjust/ADJActivityState.m

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ - (id)init {
3636
self.lastActivity = -1;
3737
self.lastInterval = -1;
3838
self.enabled = YES;
39+
self.isGdprForgotten = NO;
3940
self.askingAttribution = NO;
4041
self.deviceToken = nil;
4142
self.transactionIds = [NSMutableArray arrayWithCapacity:kTransactionIdCount];
@@ -150,9 +151,9 @@ - (NSString *)generateUniqueKey {
150151
}
151152

152153
- (NSString *)description {
153-
return [NSString stringWithFormat:@"ec:%d sc:%d ssc:%d ask:%d sl:%.1f ts:%.1f la:%.1f dt:%@",
154+
return [NSString stringWithFormat:@"ec:%d sc:%d ssc:%d ask:%d sl:%.1f ts:%.1f la:%.1f dt:%@ gdprf:%d",
154155
self.eventCount, self.sessionCount, self.subsessionCount, self.askingAttribution, self.sessionLength,
155-
self.timeSpent, self.lastActivity, self.deviceToken];
156+
self.timeSpent, self.lastActivity, self.deviceToken, self.isGdprForgotten];
156157
}
157158

158159
#pragma mark - NSCoding protocol methods
@@ -193,6 +194,12 @@ - (id)initWithCoder:(NSCoder *)decoder {
193194
} else {
194195
self.enabled = YES;
195196
}
197+
198+
if ([decoder containsValueForKey:@"isGdprForgotten"]) {
199+
self.isGdprForgotten = [decoder decodeBoolForKey:@"isGdprForgotten"];
200+
} else {
201+
self.isGdprForgotten = NO;
202+
}
196203

197204
if ([decoder containsValueForKey:@"askingAttribution"]) {
198205
self.askingAttribution = [decoder decodeBoolForKey:@"askingAttribution"];
@@ -233,6 +240,7 @@ - (void)encodeWithCoder:(NSCoder *)encoder {
233240
[encoder encodeObject:self.uuid forKey:@"uuid"];
234241
[encoder encodeObject:self.transactionIds forKey:@"transactionIds"];
235242
[encoder encodeBool:self.enabled forKey:@"enabled"];
243+
[encoder encodeBool:self.isGdprForgotten forKey:@"isGdprForgotten"];
236244
[encoder encodeBool:self.askingAttribution forKey:@"askingAttribution"];
237245
[encoder encodeObject:self.deviceToken forKey:@"deviceToken"];
238246
[encoder encodeBool:self.updatePackages forKey:@"updatePackages"];
@@ -255,6 +263,7 @@ - (id)copyWithZone:(NSZone *)zone {
255263
copy.lastInterval = self.lastInterval;
256264
copy.eventCount = self.eventCount;
257265
copy.enabled = self.enabled;
266+
copy.isGdprForgotten = self.isGdprForgotten;
258267
copy.lastActivity = self.lastActivity;
259268
copy.askingAttribution = self.askingAttribution;
260269
copy.deviceToken = [self.deviceToken copyWithZone:zone];

0 commit comments

Comments
 (0)