diff --git a/Adjust.podspec b/Adjust.podspec index ccc9db0c5..4fc93751e 100644 --- a/Adjust.podspec +++ b/Adjust.podspec @@ -1,11 +1,11 @@ Pod::Spec.new do |s| s.name = "Adjust" - s.version = "4.10.3" + s.version = "4.11.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.10.3" } + s.source = { :git => "https://github.com/adjust/ios_sdk.git", :tag => "v4.11.0" } s.ios.deployment_target = '6.0' s.tvos.deployment_target = '9.0' s.framework = 'SystemConfiguration' diff --git a/Adjust.xcodeproj/xcshareddata/xcschemes/AdjustSdkTv.xcscheme b/Adjust.xcodeproj/xcshareddata/xcschemes/AdjustSdkTv.xcscheme new file mode 100644 index 000000000..4c362e073 --- /dev/null +++ b/Adjust.xcodeproj/xcshareddata/xcschemes/AdjustSdkTv.xcscheme @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Adjust/ADJActivityHandler.h b/Adjust/ADJActivityHandler.h index d1f89b779..db365491b 100644 --- a/Adjust/ADJActivityHandler.h +++ b/Adjust/ADJActivityHandler.h @@ -16,7 +16,6 @@ @property (nonatomic, assign) BOOL background; @property (nonatomic, assign) BOOL delayStart; @property (nonatomic, assign) BOOL updatePackages; -@property (nonatomic, copy) NSData* deviceToken; - (id)init; @@ -34,6 +33,9 @@ @protocol ADJActivityHandler +@property (nonatomic, copy) ADJAttribution *attribution; +- (NSString *)adid; + - (id)initWithConfig:(ADJConfig *)adjustConfig sessionParametersActionsArray:(NSArray*)sessionParametersActionsArray deviceToken:(NSData*)deviceToken; @@ -53,14 +55,13 @@ sessionParametersActionsArray:(NSArray*)sessionParametersActionsArray - (void)appWillOpenUrl:(NSURL*)url; - (void)setDeviceToken:(NSData *)deviceToken; -- (void)setAttribution:(ADJAttribution*)attribution; - (void)setAskingAttribution:(BOOL)askingAttribution; - (BOOL)updateAttributionI:(id)selfI attribution:(ADJAttribution *)attribution; - (void)setIadDate:(NSDate*)iAdImpressionDate withPurchaseDate:(NSDate*)appPurchaseDate; -- (void)setIadDetails:(NSDictionary *)attributionDetails - error:(NSError *)error - retriesLeft:(int)retriesLeft; +- (void)setAttributionDetails:(NSDictionary *)attributionDetails + error:(NSError *)error + retriesLeft:(int)retriesLeft; - (void)setOfflineMode:(BOOL)offline; - (ADJInternalState*) internalState; @@ -83,7 +84,6 @@ sessionParametersActionsArray:(NSArray*)sessionParametersActionsArray + (id)handlerWithConfig:(ADJConfig *)adjustConfig sessionParametersActionsArray:(NSArray*)sessionParametersActionsArray deviceToken:(NSData*)deviceToken; -- (ADJAttribution*) attribution; - (void)addSessionCallbackParameterI:(ADJActivityHandler *)selfI key:(NSString *)key diff --git a/Adjust/ADJActivityHandler.m b/Adjust/ADJActivityHandler.m index 684187a9a..fcd86e74c 100644 --- a/Adjust/ADJActivityHandler.m +++ b/Adjust/ADJActivityHandler.m @@ -83,8 +83,8 @@ @interface ADJActivityHandler() @property (nonatomic, weak) id logger; @property (nonatomic, weak) NSObject *adjustDelegate; // copy for objects shared with the user -@property (nonatomic, copy) ADJAttribution *attribution; @property (nonatomic, copy) ADJConfig *adjustConfig; +@property (nonatomic, copy) NSData* deviceTokenData; @end @@ -97,6 +97,8 @@ typedef NS_ENUM(NSInteger, AdjADClientError) { #pragma mark - @implementation ADJActivityHandler +@synthesize attribution = _attribution; + + (id)handlerWithConfig:(ADJConfig *)adjustConfig sessionParametersActionsArray:(NSArray*)sessionParametersActionsArray deviceToken:(NSData*)deviceToken @@ -156,7 +158,7 @@ - (id)initWithConfig:(ADJConfig *)adjustConfig } else { self.internalState.updatePackages = self.activityState.updatePackages; } - self.internalState.deviceToken = deviceToken; + self.deviceTokenData = deviceToken; self.internalQueue = dispatch_queue_create(kInternalQueueName, DISPATCH_QUEUE_SERIAL); [ADJUtil launchInQueue:self.internalQueue @@ -318,6 +320,13 @@ - (BOOL)isEnabled { return [self isEnabledI:self]; } +- (NSString *)adid { + if (self.activityState == nil) { + return nil; + } + return self.activityState.adid; +} + - (BOOL)hasChangedState:(BOOL)previousState nextState:(BOOL)nextState trueMessage:(NSString *)trueMessage @@ -401,9 +410,9 @@ - (void)setIadDate:(NSDate *)iAdImpressionDate withPurchaseDate:(NSDate *)appPur [self.sdkClickHandler sendSdkClick:clickPackage]; } -- (void)setIadDetails:(NSDictionary *)attributionDetails - error:(NSError *)error - retriesLeft:(int)retriesLeft +- (void)setAttributionDetails:(NSDictionary *)attributionDetails + error:(NSError *)error + retriesLeft:(int)retriesLeft { if (![ADJUtil isNull:error]) { [self.logger warn:@"Unable to read iAd details"]; @@ -422,23 +431,67 @@ - (void)setIadDetails:(NSDictionary *)attributionDetails return; } - if ([ADJUtil isNull:attributionDetails]) { + // check if it's a valid attribution details + if (![ADJUtil checkAttributionDetails:attributionDetails]) { return; } - double now = [NSDate.date timeIntervalSince1970]; - ADJPackageBuilder *clickBuilder = [[ADJPackageBuilder alloc] - initWithDeviceInfo:self.deviceInfo - activityState:self.activityState - config:self.adjustConfig - createdAt:now]; + // send immediately if there is no previous attribution details + if (self.activityState == nil || + self.activityState.attributionDetails == nil) + { + // send immediately + [self sendIad3ClickPackage:self attributionDetails:attributionDetails]; + // save in the background queue + [ADJUtil launchInQueue:self.internalQueue + selfInject:self + block:^(ADJActivityHandler * selfI) { + [selfI saveAttributionDetailsI:selfI + attributionDetails:attributionDetails]; + + }]; + return; + } - clickBuilder.iadDetails = attributionDetails; + // check if new updates previous written one + [ADJUtil launchInQueue:self.internalQueue + selfInject:self + block:^(ADJActivityHandler * selfI) { + if ([attributionDetails isEqualToDictionary:selfI.activityState.attributionDetails]) { + return; + } - ADJActivityPackage *clickPackage = [clickBuilder buildClickPackage:@"iad3"]; - [self.sdkClickHandler sendSdkClick:clickPackage]; + [selfI sendIad3ClickPackage:selfI attributionDetails:attributionDetails]; + + // save new iAd details + [selfI saveAttributionDetailsI:selfI + attributionDetails:attributionDetails]; + }]; } +- (void)sendIad3ClickPackage:(ADJActivityHandler *)selfI + attributionDetails:(NSDictionary *)attributionDetails + { + double now = [NSDate.date timeIntervalSince1970]; + ADJPackageBuilder *clickBuilder = [[ADJPackageBuilder alloc] + initWithDeviceInfo:selfI.deviceInfo + activityState:selfI.activityState + config:selfI.adjustConfig + createdAt:now]; + + clickBuilder.attributionDetails = attributionDetails; + + ADJActivityPackage *clickPackage = [clickBuilder buildClickPackage:@"iad3"]; + [selfI.sdkClickHandler sendSdkClick:clickPackage]; +} + +- (void)saveAttributionDetailsI:(ADJActivityHandler *)selfI + attributionDetails:(NSDictionary *)attributionDetails +{ + // save new iAd details + selfI.activityState.attributionDetails = attributionDetails; + [selfI writeAttributionI:selfI]; +} - (void)setAskingAttribution:(BOOL)askingAttribution { [self writeActivityStateS:self changesInStateBlock:^{ @@ -595,6 +648,13 @@ - (void)initI:(ADJActivityHandler *)selfI [selfI.logger info:@"Default tracker: '%@'", selfI.adjustConfig.defaultTracker]; } + if (selfI.deviceTokenData != nil) { + [selfI.logger info:@"Push token: '%@'", selfI.deviceTokenData]; + if (selfI.activityState != nil) { + [selfI setDeviceToken:selfI.deviceTokenData]; + } + } + selfI.foregroundTimer = [ADJTimerCycle timerWithBlock:^{ [selfI foregroundTimerFired]; } @@ -675,7 +735,7 @@ - (void)processSessionI:(ADJActivityHandler *)selfI { if (selfI.activityState == nil) { selfI.activityState = [[ADJActivityState alloc] init]; selfI.activityState.sessionCount = 1; // this is the first session - selfI.activityState.deviceToken = [ADJUtil convertDeviceToken:self.internalState.deviceToken]; + selfI.activityState.deviceToken = [ADJUtil convertDeviceToken:selfI.deviceTokenData]; [selfI transferSessionPackageI:selfI now:now]; [selfI.activityState resetSessionAttributes:now]; @@ -795,6 +855,8 @@ - (void)eventI:(ADJActivityHandler *)selfI - (void)launchEventResponseTasksI:(ADJActivityHandler *)selfI eventResponseData:(ADJEventResponseData *)eventResponseData { + [selfI updateAdidI:selfI adid:eventResponseData.adid]; + // event success callback if (eventResponseData.success && [selfI.adjustDelegate respondsToSelector:@selector(adjustEventTrackingSucceeded:)]) @@ -819,6 +881,8 @@ - (void)launchEventResponseTasksI:(ADJActivityHandler *)selfI - (void)launchSessionResponseTasksI:(ADJActivityHandler *)selfI sessionResponseData:(ADJSessionResponseData *)sessionResponseData { + [selfI updateAdidI:selfI adid:sessionResponseData.adid]; + BOOL toLaunchAttributionDelegate = [selfI updateAttributionI:selfI attribution:sessionResponseData.attribution]; // session success callback @@ -851,6 +915,8 @@ - (void)launchSessionResponseTasksI:(ADJActivityHandler *)selfI - (void)launchAttributionResponseTasksI:(ADJActivityHandler *)selfI attributionResponseData:(ADJAttributionResponseData *)attributionResponseData { + [selfI updateAdidI:selfI adid:attributionResponseData.adid]; + BOOL toLaunchAttributionDelegate = [selfI updateAttributionI:selfI attribution:attributionResponseData.attribution]; @@ -890,6 +956,20 @@ - (void)prepareDeeplinkI:(ADJActivityHandler *)selfI }]; } +- (void)updateAdidI:(ADJActivityHandler *)selfI + adid:(NSString *)adid { + if (adid == nil) { + return; + } + + if ([adid isEqualToString:selfI.activityState.adid]) { + return; + } + + selfI.activityState.adid = adid; + [selfI writeActivityStateI:selfI]; +} + - (BOOL)updateAttributionI:(ADJActivityHandler *)selfI attribution:(ADJAttribution *)attribution { if (attribution == nil) { @@ -1018,6 +1098,11 @@ - (void)setDeviceTokenI:(ADJActivityHandler *)selfI return; } + // save new push token + selfI.activityState.deviceToken = deviceTokenString; + [selfI writeActivityStateI:selfI]; + + // send info package double now = [NSDate.date timeIntervalSince1970]; ADJPackageBuilder * infoBuilder = [[ADJPackageBuilder alloc] initWithDeviceInfo:selfI.deviceInfo @@ -1025,15 +1110,10 @@ - (void)setDeviceTokenI:(ADJActivityHandler *)selfI config:selfI.adjustConfig createdAt:now]; - infoBuilder.deviceToken = deviceTokenString; + ADJActivityPackage * infoPackage = [infoBuilder buildInfoPackage:@"push"]; - ADJActivityPackage * clickPackage = [infoBuilder buildInfoPackage:@"push"]; - - [selfI.sdkClickHandler sendSdkClick:clickPackage]; - - // save new push token - selfI.activityState.deviceToken = deviceTokenString; - [selfI writeActivityStateI:selfI]; + [selfI.packageHandler addPackage:infoPackage]; + [selfI.packageHandler sendFirstPackage]; } #pragma mark - private diff --git a/Adjust/ADJActivityState.h b/Adjust/ADJActivityState.h index a19c5dc4f..107ba95bf 100644 --- a/Adjust/ADJActivityState.h +++ b/Adjust/ADJActivityState.h @@ -18,6 +18,9 @@ @property (nonatomic, copy) NSString *deviceToken; @property (nonatomic, assign) BOOL updatePackages; +@property (nonatomic, copy) NSString *adid; +@property (nonatomic, strong) NSDictionary *attributionDetails; + // Global counters @property (nonatomic, assign) int eventCount; @property (nonatomic, assign) int sessionCount; diff --git a/Adjust/ADJActivityState.m b/Adjust/ADJActivityState.m index 659f6c7f6..482017667 100644 --- a/Adjust/ADJActivityState.m +++ b/Adjust/ADJActivityState.m @@ -162,6 +162,14 @@ - (id)initWithCoder:(NSCoder *)decoder { self.updatePackages = NO; } + if ([decoder containsValueForKey:@"adid"]) { + self.adid = [decoder decodeObjectForKey:@"adid"]; + } + + if ([decoder containsValueForKey:@"attributionDetails"]) { + self.attributionDetails = [decoder decodeObjectForKey:@"attributionDetails"]; + } + self.lastInterval = -1; return self; @@ -180,11 +188,14 @@ - (void)encodeWithCoder:(NSCoder *)encoder { [encoder encodeBool:self.askingAttribution forKey:@"askingAttribution"]; [encoder encodeObject:self.deviceToken forKey:@"deviceToken"]; [encoder encodeBool:self.updatePackages forKey:@"updatePackages"]; + [encoder encodeObject:self.adid forKey:@"adid"]; + [encoder encodeObject:self.attributionDetails forKey:@"attributionDetails"]; } - (id)copyWithZone:(NSZone *)zone { ADJActivityState *copy = [[[self class] allocWithZone:zone] init]; + // copy only values used by package builder if (copy) { copy.sessionCount = self.sessionCount; copy.subsessionCount = self.subsessionCount; @@ -197,9 +208,7 @@ - (id)copyWithZone:(NSZone *)zone { copy.lastActivity = self.lastActivity; copy.askingAttribution = self.askingAttribution; copy.deviceToken = [self.deviceToken copyWithZone:zone]; - copy.updatePackages = self.updatePackages; - - // transactionIds not copied. + copy.updatePackages = self.updatePackages; } return copy; diff --git a/Adjust/ADJAdditions/UIDevice+ADJAdditions.m b/Adjust/ADJAdditions/UIDevice+ADJAdditions.m index 31df68164..2a566a242 100644 --- a/Adjust/ADJAdditions/UIDevice+ADJAdditions.m +++ b/Adjust/ADJAdditions/UIDevice+ADJAdditions.m @@ -99,7 +99,7 @@ - (NSString *)adjIdForAdvertisers { } - (NSString *)adjFbAttributionId { -#if ADJUST_NO_UIPASTEBOARD || defined (TARGET_OS_TV) +#if ADJUST_NO_UIPASTEBOARD || TARGET_OS_TV return @""; #else NSString *result = [UIPasteboard pasteboardWithName:@"fb_app_attribution" create:NO].string; @@ -139,7 +139,7 @@ - (NSString *)adjVendorId { return @""; } -- (void) adjSetIad:(ADJActivityHandler *) activityHandler +- (void)adjSetIad:(ADJActivityHandler *)activityHandler triesV3Left:(int)triesV3Left { id logger = [ADJAdjustFactory logger]; @@ -202,7 +202,7 @@ - (BOOL)adjSetIadWithDetails:(ADJActivityHandler *)activityHandler #pragma clang diagnostic ignored "-Warc-performSelector-leaks" [ADClientSharedClientInstance performSelector:iadDetailsSelector withObject:^(NSDictionary *attributionDetails, NSError *error) { - [activityHandler setIadDetails:attributionDetails error:error retriesLeft:retriesLeft]; + [activityHandler setAttributionDetails:attributionDetails error:error retriesLeft:retriesLeft]; }]; #pragma clang diagnostic pop diff --git a/Adjust/ADJAttribution.h b/Adjust/ADJAttribution.h index 21faee13e..9eae036ec 100644 --- a/Adjust/ADJAttribution.h +++ b/Adjust/ADJAttribution.h @@ -34,10 +34,14 @@ // tracker click_label @property (nonatomic, copy) NSString *clickLabel; +@property (nonatomic, copy) NSString *adid; + - (BOOL)isEqualToAttribution:(ADJAttribution *)attribution; -+ (ADJAttribution *)dataWithJsonDict:(NSDictionary *)jsonDict; -- (id)initWithJsonDict:(NSDictionary *)jsonDict; ++ (ADJAttribution *)dataWithJsonDict:(NSDictionary *)jsonDict + adid:(NSString *)adid; +- (id)initWithJsonDict:(NSDictionary *)jsonDict + adid:(NSString *)adid; - (NSDictionary *)dictionary; @end diff --git a/Adjust/ADJAttribution.m b/Adjust/ADJAttribution.m index ada3ca19a..cec04a707 100644 --- a/Adjust/ADJAttribution.m +++ b/Adjust/ADJAttribution.m @@ -12,11 +12,13 @@ @implementation ADJAttribution -+ (ADJAttribution *)dataWithJsonDict:(NSDictionary *)jsonDict { - return [[ADJAttribution alloc] initWithJsonDict:jsonDict]; ++ (ADJAttribution *)dataWithJsonDict:(NSDictionary *)jsonDict + adid:(NSString *)adid { + return [[ADJAttribution alloc] initWithJsonDict:jsonDict adid:adid]; } -- (id)initWithJsonDict:(NSDictionary *)jsonDict { +- (id)initWithJsonDict:(NSDictionary *)jsonDict + adid:(NSString *)adid { self = [super init]; if (self == nil) return nil; @@ -31,6 +33,7 @@ - (id)initWithJsonDict:(NSDictionary *)jsonDict { self.adgroup = [jsonDict objectForKey:@"adgroup"]; self.creative = [jsonDict objectForKey:@"creative"]; self.clickLabel = [jsonDict objectForKey:@"click_label"]; + self.adid = adid; return self; } @@ -60,6 +63,9 @@ - (BOOL)isEqualToAttribution:(ADJAttribution *)attribution { if (![NSString adjIsEqual:self.clickLabel toString:attribution.clickLabel]) { return NO; } + if (![NSString adjIsEqual:self.adid toString:attribution.adid]) { + return NO; + } return YES; } @@ -95,13 +101,17 @@ - (NSDictionary *)dictionary { [responseDataDic setObject:self.clickLabel forKey:@"click_label"]; } + if (self.adid != nil) { + [responseDataDic setObject:self.adid forKey:@"adid"]; + } + return responseDataDic; } - (NSString *)description { - return [NSString stringWithFormat:@"tt:%@ tn:%@ net:%@ cam:%@ adg:%@ cre:%@ cl:%@", + return [NSString stringWithFormat:@"tt:%@ tn:%@ net:%@ cam:%@ adg:%@ cre:%@ cl:%@ adid:%@", self.trackerToken, self.trackerName, self.network, self.campaign, - self.adgroup, self.creative, self.clickLabel]; + self.adgroup, self.creative, self.clickLabel, self.adid]; } @@ -136,6 +146,7 @@ -(id)copyWithZone:(NSZone *)zone copy.adgroup = [self.adgroup copyWithZone:zone]; copy.creative = [self.creative copyWithZone:zone]; copy.clickLabel = [self.clickLabel copyWithZone:zone]; + copy.adid = [self.adid copyWithZone:zone]; } return copy; @@ -155,6 +166,7 @@ - (id)initWithCoder:(NSCoder *)decoder { self.adgroup = [decoder decodeObjectForKey:@"adgroup"]; self.creative = [decoder decodeObjectForKey:@"creative"]; self.clickLabel = [decoder decodeObjectForKey:@"click_label"]; + self.adid = [decoder decodeObjectForKey:@"adid"]; return self; } @@ -167,6 +179,7 @@ - (void)encodeWithCoder:(NSCoder *)encoder { [encoder encodeObject:self.adgroup forKey:@"adgroup"]; [encoder encodeObject:self.creative forKey:@"creative"]; [encoder encodeObject:self.clickLabel forKey:@"click_label"]; + [encoder encodeObject:self.adid forKey:@"adid"]; } @end diff --git a/Adjust/ADJAttributionHandler.m b/Adjust/ADJAttributionHandler.m index cde895521..a38f438c6 100644 --- a/Adjust/ADJAttributionHandler.m +++ b/Adjust/ADJAttributionHandler.m @@ -139,7 +139,7 @@ - (void)checkAttributionI:(ADJAttributionHandler*)selfI [selfI.activityHandler setAskingAttribution:NO]; NSDictionary * jsonAttribution = [responseData.jsonResponse objectForKey:@"attribution"]; - responseData.attribution = [ADJAttribution dataWithJsonDict:jsonAttribution]; + responseData.attribution = [ADJAttribution dataWithJsonDict:jsonAttribution adid:responseData.adid]; } - (void)checkDeeplinkI:(ADJAttributionHandler*)selfI diff --git a/Adjust/ADJConfig.h b/Adjust/ADJConfig.h index 7f5f97155..768ce6251 100644 --- a/Adjust/ADJConfig.h +++ b/Adjust/ADJConfig.h @@ -170,7 +170,5 @@ */ @property (nonatomic, copy) NSString *userAgent; -@property (nonatomic, assign, readonly) BOOL hasResponseDelegate; - - (BOOL) isValid; @end diff --git a/Adjust/ADJConfig.m b/Adjust/ADJConfig.m index 8a0e84e3c..9417606a6 100644 --- a/Adjust/ADJConfig.m +++ b/Adjust/ADJConfig.m @@ -59,7 +59,6 @@ - (id)initWithAppToken:(NSString *)appToken _appToken = appToken; _environment = environment; // default values - _hasResponseDelegate = NO; self.eventBufferingEnabled = NO; return self; @@ -90,7 +89,7 @@ - (void)setLogLevel:(ADJLogLevel)logLevel - (void)setDelegate:(NSObject *)delegate { - _hasResponseDelegate = NO; + BOOL hasResponseDelegate = NO; BOOL implementsDeeplinkCallback = NO; if ([ADJUtil isNull:delegate]) { @@ -102,31 +101,31 @@ - (void)setDelegate:(NSObject *)delegate { if ([delegate respondsToSelector:@selector(adjustAttributionChanged:)]) { [self.logger debug:@"Delegate implements adjustAttributionChanged:"]; - _hasResponseDelegate = YES; + hasResponseDelegate = YES; } if ([delegate respondsToSelector:@selector(adjustEventTrackingSucceeded:)]) { [self.logger debug:@"Delegate implements adjustEventTrackingSucceeded:"]; - _hasResponseDelegate = YES; + hasResponseDelegate = YES; } if ([delegate respondsToSelector:@selector(adjustEventTrackingFailed:)]) { [self.logger debug:@"Delegate implements adjustEventTrackingFailed:"]; - _hasResponseDelegate = YES; + hasResponseDelegate = YES; } if ([delegate respondsToSelector:@selector(adjustSessionTrackingSucceeded:)]) { [self.logger debug:@"Delegate implements adjustSessionTrackingSucceeded:"]; - _hasResponseDelegate = YES; + hasResponseDelegate = YES; } if ([delegate respondsToSelector:@selector(adjustSessionTrackingFailed:)]) { [self.logger debug:@"Delegate implements adjustSessionTrackingFailed:"]; - _hasResponseDelegate = YES; + hasResponseDelegate = YES; } if ([delegate respondsToSelector:@selector(adjustDeeplinkResponse:)]) { @@ -136,7 +135,7 @@ - (void)setDelegate:(NSObject *)delegate { implementsDeeplinkCallback = YES; } - if (!(self.hasResponseDelegate || implementsDeeplinkCallback)) { + if (!(hasResponseDelegate || implementsDeeplinkCallback)) { [self.logger error:@"Delegate does not implement any optional method"]; _delegate = nil; return; @@ -188,7 +187,6 @@ -(id)copyWithZone:(NSZone *)zone copy.sdkPrefix = [self.sdkPrefix copyWithZone:zone]; copy.defaultTracker = [self.defaultTracker copyWithZone:zone]; copy.eventBufferingEnabled = self.eventBufferingEnabled; - copy->_hasResponseDelegate = self.hasResponseDelegate; copy.sendInBackground = self.sendInBackground; copy.delayStart = self.delayStart; copy.userAgent = [self.userAgent copyWithZone:zone]; diff --git a/Adjust/ADJPackageBuilder.h b/Adjust/ADJPackageBuilder.h index 3f472c28d..9c0bf75cb 100644 --- a/Adjust/ADJPackageBuilder.h +++ b/Adjust/ADJPackageBuilder.h @@ -21,9 +21,8 @@ @property (nonatomic, copy) NSDate *purchaseTime; @property (nonatomic, copy) NSString *deeplink; -@property (nonatomic, copy) NSString *deviceToken; -@property (nonatomic, strong) NSDictionary *iadDetails; +@property (nonatomic, strong) NSDictionary *attributionDetails; @property (nonatomic, strong) NSDictionary* deeplinkParameters; @property (nonatomic, copy) ADJAttribution *attribution; diff --git a/Adjust/ADJPackageBuilder.m b/Adjust/ADJPackageBuilder.m index 53d45773a..2bae80605 100644 --- a/Adjust/ADJPackageBuilder.m +++ b/Adjust/ADJPackageBuilder.m @@ -123,7 +123,7 @@ - (ADJActivityPackage *)buildClickPackage:(NSString *)clickSource { [ADJPackageBuilder parameters:parameters setString:self.attribution.adgroup forKey:@"adgroup"]; [ADJPackageBuilder parameters:parameters setString:self.attribution.creative forKey:@"creative"]; } - [ADJPackageBuilder parameters:parameters setDictionary:self.iadDetails forKey:@"details"]; + [ADJPackageBuilder parameters:parameters setDictionary:self.attributionDetails forKey:@"details"]; [ADJPackageBuilder parameters:parameters setString:self.deeplink forKey:@"deeplink"]; ADJActivityPackage *clickPackage = [self defaultActivityPackage]; @@ -140,7 +140,7 @@ - (ADJActivityPackage *)buildInfoPackage:(NSString *)infoSource { [ADJPackageBuilder parameters:parameters setString:infoSource forKey:@"source"]; - [ADJPackageBuilder parameters:parameters setString:self.deviceToken forKey:@"push_token"]; + [self injectPushToken:self.activityState intoParamters:parameters]; ADJActivityPackage *infoPackage = [self defaultActivityPackage]; infoPackage.path = @"/sdk_info"; @@ -176,6 +176,7 @@ - (NSMutableDictionary *)idsParameters { [self injectDeviceInfoIds:self.deviceInfo intoParameters:parameters]; [self injectConfig:self.adjustConfig intoParameters:parameters]; + [self injectIosUuid:self.activityState intoParamters:parameters]; [self injectCommonParameters:parameters]; return parameters; @@ -195,6 +196,7 @@ - (NSMutableDictionary *)defaultParameters { - (void)injectCommonParameters:(NSMutableDictionary *)parameters { [ADJPackageBuilder parameters:parameters setDate1970:self.createdAt forKey:@"created_at"]; [ADJPackageBuilder parameters:parameters setBool:YES forKey:@"attribution_deeplink"]; + [ADJPackageBuilder parameters:parameters setBool:YES forKey:@"needs_response_details"]; } - (void) injectDeviceInfoIds:(ADJDeviceInfo *)deviceInfo @@ -231,26 +233,48 @@ - (void)injectConfig:(ADJConfig*) adjustConfig { [ADJPackageBuilder parameters:parameters setString:adjustConfig.appToken forKey:@"app_token"]; [ADJPackageBuilder parameters:parameters setString:adjustConfig.environment forKey:@"environment"]; - [ADJPackageBuilder parameters:parameters setBool:adjustConfig.hasResponseDelegate forKey:@"needs_response_details"]; [ADJPackageBuilder parameters:parameters setBool:adjustConfig.eventBufferingEnabled forKey:@"event_buffering_enabled"]; } -- (void) injectActivityState:(ADJActivityState *)activityState +- (void)injectActivityState:(ADJActivityState *)activityState intoParamters:(NSMutableDictionary *)parameters { + if (activityState == nil) { + return; + } + + [self injectIosUuid:activityState intoParamters:parameters]; + [self injectPushToken:activityState intoParamters:parameters]; + [ADJPackageBuilder parameters:parameters setInt:activityState.sessionCount forKey:@"session_count"]; [ADJPackageBuilder parameters:parameters setInt:activityState.subsessionCount forKey:@"subsession_count"]; [ADJPackageBuilder parameters:parameters setDuration:activityState.sessionLength forKey:@"session_length"]; [ADJPackageBuilder parameters:parameters setDuration:activityState.timeSpent forKey:@"time_spent"]; - [ADJPackageBuilder parameters:parameters setString:activityState.deviceToken forKey:@"push_token"]; +} + +- (void)injectIosUuid:(ADJActivityState *)activityState + intoParamters:(NSMutableDictionary *)parameters +{ + if (activityState == nil) { + return; + } // Check if UUID was persisted or not. // If yes, assign it to persistent_ios_uuid parameter. // If not, assign it to ios_uuid parameter. if (activityState.isPersisted) { - [ADJPackageBuilder parameters:parameters setString:activityState.uuid forKey:@"persistent_ios_uuid"]; + [ADJPackageBuilder parameters:parameters setString:activityState.uuid forKey:@"persistent_ios_uuid"]; } else { - [ADJPackageBuilder parameters:parameters setString:activityState.uuid forKey:@"ios_uuid"]; + [ADJPackageBuilder parameters:parameters setString:activityState.uuid forKey:@"ios_uuid"]; + } +} + +- (void)injectPushToken:(ADJActivityState *)activityState + intoParamters:(NSMutableDictionary *)parameters +{ + if (activityState == nil) { + return; } + [ADJPackageBuilder parameters:parameters setString:activityState.deviceToken forKey:@"push_token"]; } - (NSString *)eventSuffix:(ADJEvent *)event { diff --git a/Adjust/ADJUtil.h b/Adjust/ADJUtil.h index 62cd39e91..5aec0de72 100644 --- a/Adjust/ADJUtil.h +++ b/Adjust/ADJUtil.h @@ -86,4 +86,5 @@ responseDataHandler:(void (^) (ADJResponseData * responseData))responseDataHandl + (void)launchDeepLinkMain:(NSURL *)deepLinkUrl; + (NSString*)convertDeviceToken:(NSData*)deviceToken; ++ (BOOL)checkAttributionDetails:(NSDictionary *)attributionDetails; @end diff --git a/Adjust/ADJUtil.m b/Adjust/ADJUtil.m index 1cf9372cc..927620579 100644 --- a/Adjust/ADJUtil.m +++ b/Adjust/ADJUtil.m @@ -26,7 +26,7 @@ static NSRegularExpression *optionalRedirectRegex = nil; static NSNumberFormatter * secondsNumberFormatter = nil; -static NSString * const kClientSdk = @"ios4.10.3"; +static NSString * const kClientSdk = @"ios4.11.0"; static NSURLSessionConfiguration * urlSessionConfiguration = nil; static NSString * userAgent = nil; static NSString * const kDeeplinkParam = @"deep_link="; @@ -438,6 +438,8 @@ + (void)sendNSURLSessionRequest:(NSMutableURLRequest *)request responseDataHandler(responseData); }]; [task resume]; + + [session finishTasksAndInvalidate]; } + (void)sendNSURLConnectionRequest:(NSMutableURLRequest *)request @@ -914,4 +916,57 @@ + (NSString*)convertDeviceToken:(NSData*)deviceToken { return deviceTokenString; } ++ (BOOL)checkAttributionDetails:(NSDictionary *)attributionDetails { + if ([ADJUtil isNull:attributionDetails]) { + return NO; + } + + NSDictionary* details = [attributionDetails objectForKey:@"Version3.1"]; + + if ([ADJUtil isNull:details]) { + return YES; + } + + // Common fields for both iAd3 and Apple Search Ads + if (![ADJUtil contains:details key:@"iad-org-name" value:@"OrgName"] || + ![ADJUtil contains:details key:@"iad-campaign-id" value:@"1234567890"] || + ![ADJUtil contains:details key:@"iad-campaign-name" value:@"CampaignName"] || + ![ADJUtil contains:details key:@"iad-lineitem-id" value:@"1234567890"] || + ![ADJUtil contains:details key:@"iad-lineitem-name" value:@"LineName"]) + { + [ADJAdjustFactory.logger debug:@"iAd attribution details has dummy common fields for both iAd3 and Apple Search Ads"]; + return YES; + } + + // Apple Search Ads fields + if ([ADJUtil contains:details key:@"iad-adgroup-id" value:@"1234567890"] && + [ADJUtil contains:details key:@"iad-adgroup-name" value:@"AdgroupName"] && + [ADJUtil contains:details key:@"iad-keyword" value:@"Keyword"]) + { + [ADJAdjustFactory.logger debug:@"iAd attribution details has dummy Apple Search Ads fields"]; + + return NO; + } + + // iAd3 fields + if ([ADJUtil contains:details key:@"iad-adgroup-id" value:@"1234567890"] && + [ADJUtil contains:details key:@"iad-creative-name" value:@"CreativeName"]) + { + [ADJAdjustFactory.logger debug:@"iAd attribution details has dummy iAd3 fields"]; + return NO; + } + return YES; +} + ++ (BOOL)contains:(NSDictionary *)dictionary + key:(NSString *)key + value:(NSString *)value +{ + id readValue = [dictionary objectForKey:key]; + if ([ADJUtil isNull:readValue]) { + return NO; + } + return [value isEqualToString:[readValue description]]; +} + @end diff --git a/Adjust/Adjust.h b/Adjust/Adjust.h index 4143e7b5a..4bf15164c 100644 --- a/Adjust/Adjust.h +++ b/Adjust/Adjust.h @@ -2,7 +2,7 @@ // Adjust.h // Adjust // -// V4.10.3 +// V4.11.0 // Created by Christian Wellenbrock on 2012-07-23. // Copyright (c) 2012-2014 adjust GmbH. All rights reserved. // @@ -171,6 +171,9 @@ extern NSString * const ADJEnvironmentProduction; */ + (void)resetSessionPartnerParameters; ++ (ADJAttribution *)attribution; ++ (NSString *)adid; + /** * Obtain singleton Adjust object */ @@ -197,5 +200,7 @@ extern NSString * const ADJEnvironmentProduction; - (void)removeSessionCallbackParameter:(NSString *)key; - (void)addSessionPartnerParameter:(NSString *)key value:(NSString *)value; - (void)addSessionCallbackParameter:(NSString *)key value:(NSString *)value; +- (ADJAttribution *)attribution; +- (NSString *)adid; @end diff --git a/Adjust/Adjust.m b/Adjust/Adjust.m index 72aabb397..eb6eb3a7a 100644 --- a/Adjust/Adjust.m +++ b/Adjust/Adjust.m @@ -112,6 +112,14 @@ + (void)resetSessionPartnerParameters { [[Adjust getInstance] resetSessionPartnerParameters]; } ++ (ADJAttribution *)attribution { + return [[Adjust getInstance] attribution]; +} + ++ (NSString *)adid { + return [[Adjust getInstance] adid]; +} + + (id)getInstance { static Adjust *defaultInstance = nil; static dispatch_once_t onceToken; @@ -290,6 +298,16 @@ - (void)resetSessionPartnerParameters { }]; } +- (ADJAttribution *)attribution { + if (![self checkActivityHandler]) return nil; + return [self.activityHandler attribution]; +} + +- (NSString *)adid { + if (![self checkActivityHandler]) return nil; + return [self.activityHandler adid]; +} + - (void)teardown:(BOOL)deleteState { if (self.activityHandler == nil) { [self.logger error:@"Adjust already down or not initialized"]; diff --git a/AdjustTests/ADJPackageFields.m b/AdjustTests/ADJPackageFields.m index f3b5cbe1f..49667e9ef 100644 --- a/AdjustTests/ADJPackageFields.m +++ b/AdjustTests/ADJPackageFields.m @@ -16,7 +16,7 @@ - (id) init { // default values self.appToken = @"qwerty123456"; - self.clientSdk = @"ios4.10.3"; + self.clientSdk = @"ios4.11.0"; self.suffix = @""; self.environment = @"sandbox"; diff --git a/CHANGELOG.md b/CHANGELOG.md index 29e677829..767b2387f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,26 @@ +### Version 4.11.0 (27th December 2016) +#### Added +- Added `adid` field to the attribution callback response. +- Added accessor `[Adjust adid]` to be able to get `adid` value at any time after obtaining it, not only when session/event callbacks have been triggered. +- Added accessor `[Adjust attribution]` to be able to get current attribution value at any time after obtaining it, not only when attribution callback has been triggered. +- Added `AdjustSdkTv` scheme to shared ones in order to allow `Carthage` build for `tvOS`. + +#### Changed +- Updated Criteo plugin: + - Added new partner parameter `user_segment` to be sent in `injectUserSegmentIntoCriteoEvents` (for all Criteo events). + - Moved `customer_id` to be sent in `injectCustomerIdIntoCriteoEvents` (for all Criteo events). + - Added new partner parameter `new_customer` to be sent in `injectTransactionConfirmedIntoEvent`. +- Firing attribution request as soon as install has been tracked, regardless of presence of attribution callback implementation in user's app. +- Saveing iAd/AdSearch details to prevent sending duplicated `sdk_click` packages. +- Updated docs. + +#### Fixed +- Now reading push token value from activity state file when sending package. +- Fixed memory leak by closing network session. +- Fixed `TARGET_OS_TV` pre processer check. + +--- + ### Version 4.10.3 (18th November 2016) #### Added - Added sending of `os_build` parameter. @@ -8,7 +31,7 @@ - It is no longer necessary to have attribution delegate implemented to get deferred deep links. - Sending `os_build` or permenent version, not both. --- +--- ### Version 4.10.2 (30th September 2016) #### Fixed diff --git a/README.md b/README.md index 06c3b3d22..d2f987739 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,7 @@ 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]. +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]. ## Table of contents @@ -34,6 +33,9 @@ If your app is an app which uses web views you would like to use adjust tracking * [Event buffering](#event-buffering) * [Background tracking](#background-tracking) * [Device IDs](#device-ids) + * [iOS Advertising Identifier](#di-idfa) + * [Adjust device identifier](#di-adid) + * [User attribution](#user-attribution) * [Push token](#push-token) * [Pre-installed trackers](#pre-installed-trackers) * [Deep linking](#deeplinking) @@ -54,46 +56,38 @@ If your app is an app which uses web views you would like to use adjust tracking ## Example apps -There are example apps inside the [`examples` directory][examples] for [`iOS (Objective-C)`][example-ios-objc], -[`iOS (Swift)`][example-ios-swift], [`tvOS`][example-tvos] and [`Apple Watch`][example-iwatch]. You can open any of these -Xcode projects to see an example of how the adjust SDK can be integrated. +There are example apps inside the [`examples` directory][examples] for [`iOS (Objective-C)`][example-ios-objc], [`iOS (Swift)`][example-ios-swift], [`tvOS`][example-tvos] and [`Apple Watch`][example-iwatch]. You can open any of these Xcode projects to see an example of how the adjust SDK can be integrated. ## Basic integration -We will describe the steps to integrate the adjust SDK into your iOS project. We are going to assume that you are using -Xcode for your iOS development. +We will describe the steps to integrate the adjust SDK into your iOS project. We are going to assume that you are using Xcode for your iOS development. ### Get the SDK -Download the latest adjust SDK version from our [releases page][releases]. Extract the archive into a directory of your -choice. +Download the latest adjust SDK version from our [releases page][releases]. Extract the archive into a directory of your choice. ### Add the SDK to your project -You can add the adjust SDK by adding all of it's source files direcly into your app. In Xcode's Project Navigator locate -the `Supporting Files` group (or any other group of your choice). From Finder, drag the `Adjust` subdirectory into Xcode's -`Supporting Files` group. +You can add the adjust SDK by adding all of it's source files direcly into your app. In Xcode's Project Navigator locate the `Supporting Files` group (or any other group of your choice). From Finder, drag the `Adjust` subdirectory into Xcode's `Supporting Files` group. ![][drag] -In the dialog `Choose options for adding these files` make sure to check the checkbox for `Copy items if needed` and select -the radio button to `Create groups`. +In the dialog `Choose options for adding these files` make sure to check the checkbox for `Copy items if needed` and select the radio button to `Create groups`. ![][add] -- -If you're using [CocoaPods][cocoapods], you can add the following line to your `Podfile` and continue from -[this step](#sdk-integrate): +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.10.3' +pod 'Adjust', '~> 4.11.0' ``` or: ```ruby -pod 'Adjust', :git => 'https://github.com/adjust/ios_sdk.git', :tag => 'v4.10.3' +pod 'Adjust', :git => 'https://github.com/adjust/ios_sdk.git', :tag => 'v4.11.0' ``` -- @@ -107,29 +101,24 @@ github "adjust/ios_sdk" -- -You can also choose to integrate the adjust SDK by adding it to your project as a framework. On the -[releases page][releases] you can find the following archives: +You can also choose to integrate the adjust SDK by adding it to your project as a framework. On the [releases page][releases] you can find the following archives: * `AdjustSdkStatic.framework.zip` * `AdjustSdkDynamic.framework.zip` +* `AdjustSdkDynamicWithoutSimulator.framework.zip` * `AdjustSdkTv.framework.zip` -Since the release of iOS 8, Apple has introduced dynamic frameworks (also known as embedded frameworks). If your app is -targeting iOS 8 or higher, you can use the adjust SDK dynamic framework. Choose which framework you want to use – static or -dynamic – and add it to your project. +Since the release of iOS 8, Apple has introduced dynamic frameworks (also known as embedded frameworks). If your app is targeting iOS 8 or higher, you can use the adjust SDK dynamic framework. Choose which framework you want to use – static or dynamic – and add it to your project. -If you are having `tvOS` app, you can use the adjust SDK with it as well with usage of our tvOS framework which you can -extract from `AdjustSdkTv.framework.zip` archive. +If you want to use dynamic framework without architectures used for simulator (`x86_64` and `i386`), you can use SDK inside `AdjustSdkDynamicWithoutSimulator.framework.zip` archive. -If you have chosen one of these ways to integrate the adjust SDK, you may continue from [this step](#sdk-frameworks). If -you want to add the adjust SDK by adding its source files to your project, you can continue from [this step](#sdk-get). +If you are having `tvOS` app, you can use the adjust SDK with it as well with usage of our tvOS framework which you can extract from `AdjustSdkTv.framework.zip` archive. + +If you have chosen one of these ways to integrate the adjust SDK, you may continue from [this step](#sdk-frameworks). If you want to add the adjust SDK by adding its source files to your project, you can continue from [this step](#sdk-get). ### Add the AdSupport and iAd framework -Select your project in the Project Navigator. In the left hand side of the main view, select your target. In the tab -`Build Phases`, expand the group `Link Binary with Libraries`. On the bottom of that section click on the `+` button. -Select the `AdSupport.framework` and click the `Add` button. Unless you -are using tvOS, repeat the same steps to add the `iAd.framework`. Change the `Status` of both frameworks to `Optional`. +Select your project in the Project Navigator. In the left hand side of the main view, select your target. In the tab `Build Phases`, expand the group `Link Binary with Libraries`. On the bottom of that section click on the `+` button. Select the `AdSupport.framework` and click the `Add` button. Unless you are using tvOS, repeat the same steps to add the `iAd.framework`. Change the `Status` of both frameworks to `Optional`. ![][framework] @@ -175,9 +164,7 @@ Next, we'll set up basic session tracking. ### Basic setup -In the Project Navigator, open the source file of your application delegate. Add the `import` statement at the top of the -file, then add the following call to `Adjust` in the `didFinishLaunching` or `didFinishLaunchingWithOptions` method of your -app delegate: +In the Project Navigator, open the source file of your application delegate. Add the `import` statement at the top of the file, then add the following call to `Adjust` in the `didFinishLaunching` or `didFinishLaunchingWithOptions` method of your app delegate: ```objc #import "Adjust.h" @@ -197,8 +184,7 @@ ADJConfig *adjustConfig = [ADJConfig configWithAppToken:yourAppToken ![][delegate] -**Note**: Initialising the adjust SDK like this is `very important`. Otherwise, you may encounter different kinds of -issues as described in our [troubleshooting section](#ts-delayed-init). +**Note**: Initialising the adjust SDK like this is `very important`. Otherwise, you may encounter different kinds of issues as described in our [troubleshooting section](#ts-delayed-init). Replace `{YourAppToken}` with your app token. You can find this in your [dashboard]. @@ -209,17 +195,13 @@ NSString *environment = ADJEnvironmentSandbox; NSString *environment = ADJEnvironmentProduction; ``` -**Important:** This value should be set to `ADJEnvironmentSandbox` if and only if you or someone else is testing your app. -Make sure to set the environment to `ADJEnvironmentProduction` just before you publish the app. Set it back to -`ADJEnvironmentSandbox` when you start developing and testing it again. +**Important:** This value should be set to `ADJEnvironmentSandbox` if and only if you or someone else is testing your app. Make sure to set the environment to `ADJEnvironmentProduction` just before you publish the app. Set it back to `ADJEnvironmentSandbox` when you start developing and testing it again. -We use this environment to distinguish between real traffic and test traffic from test devices. It is very important that -you keep this value meaningful at all times! This is especially important if you are tracking revenue. +We use this environment to distinguish between real traffic and test traffic from test devices. It is very important that you keep this value meaningful at all times! This is especially important if you are tracking revenue. ### Adjust logging -You can increase or decrease the amount of logs that you see during testing by calling `setLogLevel:` on your `ADJConfig` -instance with one of the following parameters: +You can increase or decrease the amount of logs that you see during testing by calling `setLogLevel:` on your `ADJConfig` instance with one of the following parameters: ```objc [adjustConfig setLogLevel:ADJLogLevelVerbose]; // enable all logging @@ -231,9 +213,7 @@ instance with one of the following parameters: [adjustConfig setLogLevel:ADJLogLevelSuppress]; // disable all logging ``` -If you don't want your app in production to display any logs coming from the adjust SDK, then you should select -`ADJLogLevelSuppress` and in addition to that, initialise `ADJConfig` object with another constructor where you should -enable suppress log level mode: +If you don't want your app in production to display any logs coming from the adjust SDK, then you should select `ADJLogLevelSuppress` and in addition to that, initialise `ADJConfig` object with another constructor where you should enable suppress log level mode: ```objc #import "Adjust.h" @@ -254,8 +234,7 @@ ADJConfig *adjustConfig = [ADJConfig configWithAppToken:yourAppToken ### Build your app -Build and run your app. If the build succeeds, you should carefully read the SDK logs in the console. After the app -launches for the first time, you should see the info log `Install tracked`. +Build and run your app. If the build succeeds, you should carefully read the SDK logs in the console. After the app launches for the first time, you should see the info log `Install tracked`. ![][run] @@ -265,9 +244,7 @@ Once you integrate the adjust SDK into your project, you can take advantage of t ### Event tracking -You can use adjust to track events. Lets say you want to track every tap on a particular button. You would create a new -event token in your [dashboard], which has an associated event token - looking something like `abc123`. In your button's -`buttonDown` method you would then add the following lines to track the tap: +You can use adjust to track events. Lets say you want to track every tap on a particular button. You would create a new event token in your [dashboard], which has an associated event token - looking something like `abc123`. In your button's `buttonDown` method you would then add the following lines to track the tap: ```objc ADJEvent *event = [ADJEvent eventWithEventToken:@"abc123"]; @@ -280,8 +257,7 @@ The event instance can be used to configure the event further before tracking it ### Revenue tracking -If your users can generate revenue by tapping on advertisements or making in-app purchases you can track those revenues -with events. Lets say a tap is worth one Euro cent. You could then track the revenue event like this: +If your users can generate revenue by tapping on advertisements or making in-app purchases you can track those revenues with events. Lets say a tap is worth one Euro cent. You could then track the revenue event like this: ```objc ADJEvent *event = [ADJEvent eventWithEventToken:@"abc123"]; @@ -293,21 +269,15 @@ ADJEvent *event = [ADJEvent eventWithEventToken:@"abc123"]; This can be combined with callback parameters of course. -When you set a currency token, adjust will automatically convert the incoming revenues into a reporting revenue of your -choice. Read more about [currency conversion here.][currency-conversion] +When you set a currency token, adjust will automatically convert the incoming revenues into a reporting revenue of your choice. Read more about [currency conversion here.][currency-conversion] -You can read more about revenue and event tracking in the [event tracking guide] -(https://docs.adjust.com/en/event-tracking/#reference-tracking-purchases-and-revenues). +You can read more about revenue and event tracking in the [event tracking guide] (https://docs.adjust.com/en/event-tracking/#reference-tracking-purchases-and-revenues). ### Revenue deduplication -You can also pass in an optional transaction ID to avoid tracking duplicate revenues. The last ten transaction IDs are -remembered and revenue events with duplicate transaction IDs are skipped. This is especially useful for in-app purchase -tracking. See an example below. +You can also pass in an optional transaction ID to avoid tracking duplicate revenues. The last ten transaction IDs are remembered and revenue events with duplicate transaction IDs are skipped. This is especially useful for in-app purchase tracking. See an example below. -If you want to track in-app purchases, please make sure to call `trackEvent` after `finishTransaction` in -`paymentQueue:updatedTransaction` only if the state changed to `SKPaymentTransactionStatePurchased`. That way you can avoid -tracking revenue that is not actually being generated. +If you want to track in-app purchases, please make sure to call `trackEvent` after `finishTransaction` in `paymentQueue:updatedTransaction` only if the state changed to `SKPaymentTransactionStatePurchased`. That way you can avoid tracking revenue that is not actually being generated. ```objc - (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions { @@ -330,14 +300,11 @@ tracking revenue that is not actually being generated. ### In-App Purchase verification -If you want to check the validity of In-App Purchases made in your app using Purchase Verification, adjust's server side -receipt verification tool, then check out our iOS purchase SDK and read more about it [here][ios-purchase-verification]. +If you want to check the validity of In-App Purchases made in your app using Purchase Verification, adjust's server side receipt verification tool, then check out our iOS purchase SDK and read more about it [here][ios-purchase-verification]. ### Callback parameters -You can register a callback URL for your events in your [dashboard]. We will send a GET request to that URL whenever the -event is tracked. You can add callback parameters to that event by calling `addCallbackParameter` to the event before -tracking it. We will then append these parameters to your callback URL. +You can register a callback URL for your events in your [dashboard]. We will send a GET request to that URL whenever the event is tracked. You can add callback parameters to that event by calling `addCallbackParameter` to the event before tracking it. We will then append these parameters to your callback URL. For example, suppose you have registered the URL `http://www.mydomain.com/callback` then track an event like this: @@ -354,20 +321,15 @@ In that case we would track the event and send a request to: http://www.mydomain.com/callback?key=value&foo=bar -It should be mentioned that we support a variety of placeholders like `{idfa}` that can be used as parameter values. In the -resulting callback this placeholder would be replaced with the ID for Advertisers of the current device. Also note that we -don't store any of your custom parameters, but only append them to your callbacks, thus without a callback they will not be -saved nor sent to you. +It should be mentioned that we support a variety of placeholders like `{idfa}` that can be used as parameter values. In the resulting callback this placeholder would be replaced with the ID for Advertisers of the current device. Also note that we don't store any of your custom parameters, but only append them to your callbacks, thus without a callback they will not be saved nor sent to you. -You can read more about using URL callbacks, including a full list of available values, in our -[callbacks guide][callbacks-guide]. +You can read more about using URL callbacks, including a full list of available values, in our [callbacks guide][callbacks-guide]. ### Partner parameters You can also add parameters to be transmitted to network partners, which have been activated in youradjust dashboard. -This works similarly to the callback parameters mentioned above, but can be added by calling the `addPartnerParameter` -method on your `ADJEvent` instance. +This works similarly to the callback parameters mentioned above, but can be added by calling the `addPartnerParameter` method on your `ADJEvent` instance. ```objc ADJEvent *event = [ADJEvent eventWithEventToken:@"abc123"]; @@ -382,40 +344,29 @@ You can read more about special partners and these integrations in our [guide to ### Session parameters -Some parameters are saved to be sent in every event and session of the adjust SDK. Once you have added any of these -parameters, you don't need to add them every time, since they will be saved locally. If you add the same parameter twice, -there will be no effect. +Some parameters are saved to be sent in every event and session of the adjust SDK. Once you have added any of these parameters, you don't need to add them every time, since they will be saved locally. If you add the same parameter twice, there will be no effect. -These session parameters can be called before the adjust SDK is launched to make sure they are sent even on install. If you -need to send them with an install, but can only obtain the needed values after launch, it's possible to -[delay](#delay-start) the first launch of the adjust SDK to allow this behaviour. +These session parameters can be called before the adjust SDK is launched to make sure they are sent even on install. If you need to send them with an install, but can only obtain the needed values after launch, it's possible to [delay](#delay-start) the first launch of the adjust SDK to allow this behaviour. ### Session callback parameters -The same callback parameters that are registered for [events](#callback-parameters) can be also saved to be sent in every -event or session of the adjust SDK. +The same callback parameters that are registered for [events](#callback-parameters) can be also saved to be sent in every event or session of the adjust SDK. -The session callback parameters have a similar interface of the event callback parameters. Instead of adding the key and -it's value to an event, it's added through a call to `Adjust` method `addSessionCallbackParameter:value:`: +The session callback parameters have a similar interface of the event callback parameters. Instead of adding the key and it's value to an event, it's added through a call to `Adjust` method `addSessionCallbackParameter:value:`: ```objc [Adjust addSessionCallbackParameter:@"foo" value:@"bar"]; ``` -The session callback parameters will be merged with the callback parameters added to an event. The callback parameters -added to an event have precedence over the session callback parameters. Meaning that, when adding a callback parameter to -an event with the same key to one added from the session, the value that prevails is the callback parameter added to the -event. +The session callback parameters will be merged with the callback parameters added to an event. The callback parameters added to an event have precedence over the session callback parameters. Meaning that, when adding a callback parameter to an event with the same key to one added from the session, the value that prevails is the callback parameter added to the event. -It's possible to remove a specific session callback parameter by passing the desiring key to the method -`removeSessionCallbackParameter`. +It's possible to remove a specific session callback parameter by passing the desiring key to the method `removeSessionCallbackParameter`. ```objc [Adjust removeSessionCallbackParameter:@"foo"]; ``` -If you wish to remove all key and values from the session callback parameters, you can reset it with the method -`resetSessionCallbackParameters`. +If you wish to remove all key and values from the session callback parameters, you can reset it with the method `resetSessionCallbackParameters`. ```objc [Adjust resetSessionCallbackParameters]; @@ -423,31 +374,25 @@ If you wish to remove all key and values from the session callback parameters, y ### Session partner parameters -In the same way that there is [session callback parameters](#session-callback-parameters) that are sent every in event or -session of the adjust SDK, there is also session partner parameters. +In the same way that there is [session callback parameters](#session-callback-parameters) that are sent every in event or session of the adjust SDK, there is also session partner parameters. These will be transmitted to network partners, for the integrations that have been activated in your adjust [dashboard]. -The session partner parameters have a similar interface to the event partner parameters. Instead of adding the key and it's -value to an event, it's added through a call to `Adjust` method `addSessionPartnerParameter:value:`: +The session partner parameters have a similar interface to the event partner parameters. Instead of adding the key and it's value to an event, it's added through a call to `Adjust` method `addSessionPartnerParameter:value:`: ```objc [Adjust addSessionPartnerParameter:@"foo" value:@"bar"]; ``` -The session partner parameters will be merged with the partner parameters added to an event. The partner parameters added -to an event have precedence over the session partner parameters. Meaning that, when adding a partner parameter to an event -with the same key to one added from the session, the value that prevails is the partner parameter added to the event. +The session partner parameters will be merged with the partner parameters added to an event. The partner parameters added to an event have precedence over the session partner parameters. Meaning that, when adding a partner parameter to an event with the same key to one added from the session, the value that prevails is the partner parameter added to the event. -It's possible to remove a specific session partner parameter by passing the desiring key to the method -`removeSessionPartnerParameter`. +It's possible to remove a specific session partner parameter by passing the desiring key to the method `removeSessionPartnerParameter`. ```objc [Adjust removeSessionPartnerParameter:@"foo"]; ``` -If you wish to remove all key and values from the session partner parameters, you can reset it with the method -`resetSessionPartnerParameters`. +If you wish to remove all key and values from the session partner parameters, you can reset it with the method `resetSessionPartnerParameters`. ```objc [Adjust resetSessionPartnerParameters]; @@ -455,8 +400,7 @@ If you wish to remove all key and values from the session partner parameters, yo ### Delay start -Delaying the start of the adjust SDK allows your app some time to obtain session parameters, such as unique identifiers, to -be send on install. +Delaying the start of the adjust SDK allows your app some time to obtain session parameters, such as unique identifiers, to be send on install. Set the initial delay time in seconds with the method `setDelayStart` in the `ADJConfig` instance: @@ -464,17 +408,13 @@ Set the initial delay time in seconds with the method `setDelayStart` in the `AD [adjustConfig setDelayStart:5.5]; ``` -In this case this will make the adjust SDK not send the initial install session and any event created for 5.5 seconds. -After this time is expired or if you call `[Adjust sendFirstPackages]` in the meanwhile, every session parameter will be -added to the delayed install session and events and the adjust SDK will resume as usual. +In this case this will make the adjust SDK not send the initial install session and any event created for 5.5 seconds. After this time is expired or if you call `[Adjust sendFirstPackages]` in the meanwhile, every session parameter will be added to the delayed install session and events and the adjust SDK will resume as usual. **The maximum delay start time of the adjust SDK is 10 seconds**. ### Attribution callback -You can register a delegate callback to be notified of tracker attribution changes. Due to the different sources considered -for attribution, this information can not be provided synchronously. Follow these steps to implement the optional delegate -protocol in your app delegate: +You can register a delegate callback to be notified of tracker attribution changes. Due to the different sources considered for attribution, this information can not be provided synchronously. Follow these steps to implement the optional delegate protocol in your app delegate: Please make sure to consider our [applicable attribution data policies.][attribution-data] @@ -497,11 +437,9 @@ Please make sure to consider our [applicable attribution data policies.][attribu [adjustConfig setDelegate:self]; ``` -As the delegate callback is configured using the `ADJConfig` instance, you should call `setDelegate` before calling -`[Adjust appDidLaunch:adjustConfig]`. +As the delegate callback is configured using the `ADJConfig` instance, you should call `setDelegate` before calling `[Adjust appDidLaunch:adjustConfig]`. -The delegate function will be called after the SDK receives the final attribution data. Within the delegate function you -have access to the `attribution` parameter. Here is a quick summary of its properties: +The delegate function will be called after the SDK receives the final attribution data. Within the delegate function you have access to the `attribution` parameter. Here is a quick summary of its properties: - `NSString trackerToken` the tracker token of the current install. - `NSString trackerName` the tracker name of the current install. @@ -510,11 +448,11 @@ have access to the `attribution` parameter. Here is a quick summary of its prope - `NSString adgroup` the ad group grouping level of the current install. - `NSString creative` the creative grouping level of the current install. - `NSString clickLabel` the click label of the current install. +- `NSString adid` the unique device identifier provided by adjust. ### Event and session callbacks -You can register a delegate callback to be notified of successful and failed tracked events and/or sessions. The same -optional protocol `AdjustDelegate` used for the [attribution callback](#attribution-callback) is used. +You can register a delegate callback to be notified of successful and failed tracked events and/or sessions. The same optional protocol `AdjustDelegate` used for the [attribution callback](#attribution-callback) is used. Follow the same steps and implement the following delegate callback function for successful tracked events: @@ -544,9 +482,7 @@ And for failed tracked sessions: } ``` -The delegate functions will be called after the SDK tries to send a package to the server. Within the delegate callback you -have access to a response data object specifically for the delegate callback. Here is a quick summary of the session -response data properties: +The delegate functions will be called after the SDK tries to send a package to the server. Within the delegate callback you have access to a response data object specifically for the delegate callback. Here is a quick summary of the session response data properties: - `NSString message` the message from the server or the error logged by the SDK. - `NSString timeStamp` timestamp from the server. @@ -563,21 +499,17 @@ And both event and session failed objects also contain: ### Disable tracking -You can disable the adjust SDK from tracking any activities of the current device by calling `setEnabled` with parameter -`NO`. **This setting is remembered between sessions**, but it can only be activated after the first session. +You can disable the adjust SDK from tracking any activities of the current device by calling `setEnabled` with parameter `NO`. **This setting is remembered between sessions**, but it can only be activated after the first session. ```objc [Adjust setEnabled:NO]; ``` -You can check if the adjust SDK is currently enabled by calling the function `isEnabled`. It is always -possible to activate the adjust SDK by invoking `setEnabled` with the enabled parameter as `YES`. +You can check if the adjust SDK is currently enabled by calling the function `isEnabled`. It is always possible to activate the adjust SDK by invoking `setEnabled` with the enabled parameter as `YES`. ### Offline mode -You can put the adjust SDK in offline mode to suspend transmission to our servers while retaining tracked data to be sent -later. While in offline mode, all information is saved in a file, so be careful not to trigger too many events while in -offline mode. +You can put the adjust SDK in offline mode to suspend transmission to our servers while retaining tracked data to be sent later. While in offline mode, all information is saved in a file, so be careful not to trigger too many events while in offline mode. You can activate offline mode by calling `setOfflineMode` with the parameter `YES`. @@ -585,16 +517,13 @@ You can activate offline mode by calling `setOfflineMode` with the parameter `YE [Adjust setOfflineMode:YES]; ``` -Conversely, you can deactivate offline mode by calling `setOfflineMode` with `NO`. When the adjust SDK is put back in -online mode, all saved information is sent to our servers with the correct time information. +Conversely, you can deactivate offline mode by calling `setOfflineMode` with `NO`. When the adjust SDK is put back in online mode, all saved information is sent to our servers with the correct time information. -Unlike disabling tracking, this setting is **not remembered** bettween sessions. This means that the SDK is in online mode -whenever it is started, even if the app was terminated in offline mode. +Unlike disabling tracking, this setting is **not remembered** bettween sessions. This means that the SDK is in online mode whenever it is started, even if the app was terminated in offline mode. ### Event buffering -If your app makes heavy use of event tracking, you might want to delay some HTTP requests in order to send them in one -batch every minute. You can enable event buffering with your `ADJConfig` instance: +If your app makes heavy use of event tracking, you might want to delay some HTTP requests in order to send them in one batch every minute. You can enable event buffering with your `ADJConfig` instance: ```objc [adjustConfig setEventBufferingEnabled:YES]; @@ -604,8 +533,7 @@ If nothing is set, event buffering is **disabled by default**. ### Background tracking -The default behaviour of the adjust SDK is to pause sending HTTP requests while the app is in the background. You can -change this in your `AdjustConfig` instance: +The default behaviour of the adjust SDK is to pause sending HTTP requests while the app is in the background. You can change this in your `AdjustConfig` instance: ```objc [adjustConfig setSendInBackground:YES]; @@ -615,8 +543,11 @@ If nothing is set, sending in background is **disabled by default**. ### Device IDs -Certain services (such as Google Analytics) require you to coordinate device and client IDs in order to prevent duplicate -reporting. +The adjust SDK offers you possibility to obtain some of the device identifiers. + +### iOS Advertising Identifier + +Certain services (such as Google Analytics) require you to coordinate device and client IDs in order to prevent duplicate reporting. To obtain the device identifier IDFA, call the function `idfa`: @@ -624,10 +555,29 @@ To obtain the device identifier IDFA, call the function `idfa`: NSString *idfa = [Adjust idfa]; ``` +### Adjust device identifier + +For each device with your app installed, adjust backend generates unique **adjust device identifier** (**adid**). In order to obtain this identifier, you can make a call to following the method on the `Adjust` instance: + +```objc +NSString *adid = [Adjust adid]; +``` + +**Note**: Information about the **adid** is available after the app's installation has been tracked by the adjust backend. From that moment on, the adjust SDK has information about the device **adid** and you can access it with this method. So, **it is not possible** to access the **adid** before the SDK has been initialised and the installation of your app has been tracked successfully. + +### User attribution + +The attribution callback will be triggered as described in the [attribution callback section](#attribution-callback), providing you with the information about any new attribution when ever it changes. In any other case, where you want to access information about your user's current attribution, you can make a call to the following method of the `Adjust` instance: + +```objc +ADJAttribution *attribution = [Adjust attribution]; +``` + +**Note**: Information about current attribution is available after app installation has been tracked by the adjust backend and attribution callback has been initially triggered. From that moment on, adjust SDK has information about your user's attribution and you can access it with this method. So, **it is not possible** to access user's attribution value before the SDK has been initialised and attribution callback has been initially triggered. + ### Push token -To send us the push notification token, add the following call to `Adjust` in the -`didRegisterForRemoteNotificationsWithDeviceToken` of your app delegate: +To send us the push notification token, add the following call to `Adjust` in the `didRegisterForRemoteNotificationsWithDeviceToken` of your app delegate: ```objc - (void)application:(UIApplication *)app didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken { @@ -660,35 +610,19 @@ If you want to use the Adjust SDK to recognize users that found your app pre-ins ### Deep linking -If you are using the adjust tracker URL with an option to deep link into your app from the URL, there is the possibility to -get info about the deep link URL and its content. Hitting the URL can happen when the user has your app already installed -(standard deep linking scenario) or if they don't have the app on their device (deferred deep linking scenario). Both of -these scenarios are supported by the adjust SDK and in both cases the deep link URL will be provided to you after you app -has been started after hitting the tracker URL. In order to use this feature in your app, you need to set it up properly. +If you are using the adjust tracker URL with an option to deep link into your app from the URL, there is the possibility to get info about the deep link URL and its content. Hitting the URL can happen when the user has your app already installed (standard deep linking scenario) or if they don't have the app on their device (deferred deep linking scenario). Both of these scenarios are supported by the adjust SDK and in both cases the deep link URL will be provided to you after you app has been started after hitting the tracker URL. In order to use this feature in your app, you need to set it up properly. ### Standard deep linking scenario -If your user already has the app installed and hits the tracker URL with deep link information in it, your application will -be opened and the content of the deep link will be sent to your app so that you can parse it and decide what to do next. -With introduction of iOS 9, Apple has changed the way how deep linking should be handled in the app. Depending on which -scenario you want to use for your app (or if you want to use them both to support wide range of devices), you need to set -up your app to handle one or both of the following scenarios. +If your user already has the app installed and hits the tracker URL with deep link information in it, your application will be opened and the content of the deep link will be sent to your app so that you can parse it and decide what to do next. With introduction of iOS 9, Apple has changed the way how deep linking should be handled in the app. Depending on which scenario you want to use for your app (or if you want to use them both to support wide range of devices), you need to set up your app to handle one or both of the following scenarios. ### Deep linking on iOS 8 and earlier -Deep linking on iOS 8 and earlier devices is being done with usage of a custom URL scheme setting. You need to pick a -custom URL scheme name which your app will be in charge for opening. This scheme name will also be used in the adjust -tracker URL as part of the `deep_link` parameter. In order to set this in your app, open your `Info.plist` file and add new -`URL types` row to it. In there, as `URL identifier` write you app's bundle ID and under `URL schemes` add scheme name(s) -which you want your app to handle. In the example below, we have chosen that our app should handle the `adjustExample` scheme -name. +Deep linking on iOS 8 and earlier devices is being done with usage of a custom URL scheme setting. You need to pick a custom URL scheme name which your app will be in charge for opening. This scheme name will also be used in the adjust tracker URL as part of the `deep_link` parameter. In order to set this in your app, open your `Info.plist` file and add new `URL types` row to it. In there, as `URL identifier` write you app's bundle ID and under `URL schemes` add scheme name(s) which you want your app to handle. In the example below, we have chosen that our app should handle the `adjustExample` scheme name. ![][custom-url-scheme] -After this has been set up, your app will be opened after you click the adjust tracker URL with `deep_link` parameter -which contains the scheme name which you have chosen. After app is opened, `openURL` method of your `AppDelegate` class will -be triggered and the place where the content of the `deep_link` parameter from the tracker URL will be delivered. If you -want to access the content of the deep link, override this method. +After this has been set up, your app will be opened after you click the adjust tracker URL with `deep_link` parameter which contains the scheme name which you have chosen. After app is opened, `openURL` method of your `AppDelegate` class will be triggered and the place where the content of the `deep_link` parameter from the tracker URL will be delivered. If you want to access the content of the deep link, override this method. ```objc - (BOOL)application:(UIApplication *)application openURL:(NSURL *)url @@ -706,25 +640,17 @@ With this setup, you have successfully set up deep linking handling for iOS devi ### Deep linking on iOS 9 and later -In order to set deep linking support for iOS 9 and later devices, you need to enable your app to handle Apple universal -links. To find out more about universal links and how their setup looks like, you can check [here][universal-links]. +In order to set deep linking support for iOS 9 and later devices, you need to enable your app to handle Apple universal links. To find out more about universal links and how their setup looks like, you can check [here][universal-links]. -Adjust is taking care of lots of things to do with universal links behind the scenes. But, in order to support -universal links with the adjust, you need to perform small setup for universal links in the adjust dashboard. For more -information on that should be done, please consult our official [docs][universal-links-guide]. +Adjust is taking care of lots of things to do with universal links behind the scenes. But, in order to support universal links with the adjust, you need to perform small setup for universal links in the adjust dashboard. For more information on that should be done, please consult our official [docs][universal-links-guide]. Once you have successfully enabled the universal links feature in the dashboard, you need to do this in your app as well: -After enabling `Associated Domains` for your app in Apple Developer Portal, you need to do the same thing in your app's -Xcode project. After enabling `Assciated Domains`, add the universal link which was generated for you in the adjust -dashboard in the `Domains` section by prefixing it with `applinks:` and make sure that you also remove the `http(s)` part of the -universal link. +After enabling `Associated Domains` for your app in Apple Developer Portal, you need to do the same thing in your app's Xcode project. After enabling `Assciated Domains`, add the universal link which was generated for you in the adjust dashboard in the `Domains` section by prefixing it with `applinks:` and make sure that you also remove the `http(s)` part of the universal link. ![][associated-domains-applinks] -After this has been set up, your app will be opened after you click the adjust tracker universal link. After app is -opened, `continueUserActivity` method of your `AppDelegate` class will be triggered and the place where the content of the -universal link URL will be delivered. If you want to access the content of the deep link, override this method. +After this has been set up, your app will be opened after you click the adjust tracker universal link. After app is opened, `continueUserActivity` method of your `AppDelegate` class will be triggered and the place where the content of the universal link URL will be delivered. If you want to access the content of the deep link, override this method. ``` objc - (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity @@ -744,10 +670,7 @@ universal link URL will be delivered. If you want to access the content of the d With this setup, you have successfully set up deep linking handling for iOS devices with iOS 9 and later versions. -We provide a helper function that allows you to convert a universal link to an old style deep link URL, in case you had -some custom logic in your code which was always expecting deep link info to arrive in old style custom URL scheme format. -You can call this method with universal link and the custom URL scheme name which you would like to see your deep link -prefixed with and we will generate the custom URL scheme deep link for you: +We provide a helper function that allows you to convert a universal link to an old style deep link URL, in case you had some custom logic in your code which was always expecting deep link info to arrive in old style custom URL scheme format. You can call this method with universal link and the custom URL scheme name which you would like to see your deep link prefixed with and we will generate the custom URL scheme deep link for you: ``` objc - (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity @@ -767,9 +690,7 @@ prefixed with and we will generate the custom URL scheme deep link for you: ### Deferred deep linking scenario -You can register a delegate callback to be notified before a deferred deep link is opened and decide if the adjust SDK will -try to open it. The same optional protocol `AdjustDelegate` used for the [attribution callback](#attribution-callback) and -for [event and session callbacks](#event-session-callbacks) is used. +You can register a delegate callback to be notified before a deferred deep link is opened and decide if the adjust SDK will try to open it. The same optional protocol `AdjustDelegate` used for the [attribution callback](#attribution-callback) and for [event and session callbacks](#event-session-callbacks) is used. Follow the same steps and implement the following delegate callback function for deferred deep links: @@ -784,26 +705,17 @@ Follow the same steps and implement the following delegate callback function for } ``` -The callback function will be called after the SDK receives a deffered deep link from our server and before opening it. -Within the callback function you have access to the deep link. The returned boolean value determines if the SDK will launch -the deep link. You could, for example, not allow the SDK to open the deep link at the current moment, save it, and open it -yourself later. +The callback function will be called after the SDK receives a deffered deep link from our server and before opening it. Within the callback function you have access to the deep link. The returned boolean value determines if the SDK will launch the deep link. You could, for example, not allow the SDK to open the deep link at the current moment, save it, and open it yourself later. If this callback is not implemented, **the adjust SDK will always try to open the deep link by default**. ### Reattribution via deep links -Adjust enables you to run re-engagement campaigns with usage of deep links. For more information on how to do that, please -check our [official docs][reattribution-with-deeplinks]. +Adjust enables you to run re-engagement campaigns with usage of deep links. For more information on how to do that, please check our [official docs][reattribution-with-deeplinks]. -If you are using this feature, in order for your user to be properly reattributed, you need to make one additional call to -the adjust SDK in your app. +If you are using this feature, in order for your user to be properly reattributed, you need to make one additional call to the adjust SDK in your app. -Once you have received deep link content information in your app, add a call to the `appWillOpenUrl` method. By making -this call, the adjust SDK will try to find if there is any new attribution info inside of the deep link and if any, it will -be sent to the adjust backend. If your user should be reattributed due to a click on the adjust tracker URL with deep link -content in it, you will see the [attribution callback](#attribution-callback) in your app being triggered with new -attribution info for this user. +Once you have received deep link content information in your app, add a call to the `appWillOpenUrl` method. By making this call, the adjust SDK will try to find if there is any new attribution info inside of the deep link and if any, it will be sent to the adjust backend. If your user should be reattributed due to a click on the adjust tracker URL with deep link content in it, you will see the [attribution callback](#attribution-callback) in your app being triggered with new attribution info for this user. The call to `appWillOpenUrl` should be done like this to support deep linking reattributions in all iOS versions: @@ -845,12 +757,9 @@ The call to `appWillOpenUrl` should be done like this to support deep linking re ### Issues with delayed SDK initialisation -As described in the [basic setup step](#basic-setup), we strongly advise you to initialise the adjust SDK in the -`didFinishLaunching` or `didFinishLaunchingWithOptions` method of your app delegate. It is imperative to initialise the -adjust SDK in as soon as possible so that you can use all the features of the SDK. +As described in the [basic setup step](#basic-setup), we strongly advise you to initialise the adjust SDK in the `didFinishLaunching` or `didFinishLaunchingWithOptions` method of your app delegate. It is imperative to initialise the adjust SDK in as soon as possible so that you can use all the features of the SDK. -Deciding not to initialise the adjust SDK immediately can have all kinds of impacts on the tracking in your app: -**In order to perform any kind of tracking in your app, the adjust SDK *must* be initialised.** +Deciding not to initialise the adjust SDK immediately can have all kinds of impacts on the tracking in your app: **In order to perform any kind of tracking in your app, the adjust SDK *must* be initialised.** If you decide to perform any of these actions: @@ -861,94 +770,60 @@ If you decide to perform any of these actions: before initialising the SDK, `they won't be performed`. -If you want any of these actions to be tracked with the adjust SDK before its actual initialisation, you must build a -`custom actions queueing mechanism` inside your app. You need to queue all the actions you want our SDK to perform and -perform them once the SDK is initialised. +If you want any of these actions to be tracked with the adjust SDK before its actual initialisation, you must build a `custom actions queueing mechanism` inside your app. You need to queue all the actions you want our SDK to perform and perform them once the SDK is initialised. -Offline mode state won't be changed, tracking enabled/disabled state won't be changed, deep link reattributions will not be -possible to happen, any of tracked events will be `dropped`. +Offline mode state won't be changed, tracking enabled/disabled state won't be changed, deep link reattributions will not be possible to happen, any of tracked events will be `dropped`. -Another thing which might be affected by delayed SDK initialisation is session tracking. The adjust SDK can't start to -collect any session length info before it is actually initialised. This can affect your DAU numbers in the dashboard which -might not be tracked properly. +Another thing which might be affected by delayed SDK initialisation is session tracking. The adjust SDK can't start to collect any session length info before it is actually initialised. This can affect your DAU numbers in the dashboard which might not be tracked properly. -As an example, let's assume this scenario: You are initialising the adjust SDK when some specific view or view controller -is loaded and let's say that this is not the splash nor the first screen in your app, but user has to navigate to it from -the home screen. If user downloads your app and opens it, the home screen will be displayed. At this moment, this user has -made an install which should be tracked. However, the adjust SDK doesn't know anything about this, because the user needs -to navigate to the screen mentioned previously where you decided to initialise the adjust SDK. Further, if the user decides -that he/she doesn't like the app and uninstalls it right after seeing home screen, all the information mentioned above will -never be tracked by our SDK, nor displayed in the dashboard. +As an example, let's assume this scenario: You are initialising the adjust SDK when some specific view or view controller is loaded and let's say that this is not the splash nor the first screen in your app, but user has to navigate to it from the home screen. If user downloads your app and opens it, the home screen will be displayed. At this moment, this user has made an install which should be tracked. However, the adjust SDK doesn't know anything about this, because the user needs to navigate to the screen mentioned previously where you decided to initialise the adjust SDK. Further, if the user decides that he/she doesn't like the app and uninstalls it right after seeing home screen, all the information mentioned above will never be tracked by our SDK, nor displayed in the dashboard. #### Event tracking -For the events you want to track, queue them with some internal queueing mechanism and track them after SDK is initialised. -Tracking events before initialising SDK will cause the events to be `dropped` and `permanently lost`, so make sure you are -tracking them once SDK is `initialised` and [`enabled`](#is-enabled). +For the events you want to track, queue them with some internal queueing mechanism and track them after SDK is initialised. Tracking events before initialising SDK will cause the events to be `dropped` and `permanently lost`, so make sure you are tracking them once SDK is `initialised` and [`enabled`](#is-enabled). #### Offline mode and enable/disable tracking -Offline mode is not the feature which is persisted between SDK initialisations, so it is set to `false` by default. If you -try to enable offline mode before initialising SDK, it will still be set to `false` when you eventually initialise the SDK. +Offline mode is not the feature which is persisted between SDK initialisations, so it is set to `false` by default. If you try to enable offline mode before initialising SDK, it will still be set to `false` when you eventually initialise the SDK. -Enabling/disabling tracking is the setting which is persisted between the SDK initialisations. If you try to toggle this -value before initialising the SDK, toggle attempt will be ignored. Once initialised, SDK will be in the state (enabled or -disabled) like before this toggle attempt. +Enabling/disabling tracking is the setting which is persisted between the SDK initialisations. If you try to toggle this value before initialising the SDK, toggle attempt will be ignored. Once initialised, SDK will be in the state (enabled or disabled) like before this toggle attempt. #### Reattribution via deep links -As described [above](#deeplinking-reattribution), when handling deep link reattributions, depending on deep linking -mechanism you are using (old style vs. universal links), you will obtain `NSURL` object after which you need to make -following call: +As described [above](#deeplinking-reattribution), when handling deep link reattributions, depending on deep linking mechanism you are using (old style vs. universal links), you will obtain `NSURL` object after which you need to make following call: ```objc [Adjust appWillOpenUrl:url] ``` -If you make this call before the SDK has been initialised, information about the attribution information from the deep link -URL will be permanetly lost. If you want the adjust SDK to successfully reattribute your user, you would need to queue this -`NSURL` object information and trigger `appWillOpenUrl` method once the SDK has been initialised. +If you make this call before the SDK has been initialised, information about the attribution information from the deep link URL will be permanetly lost. If you want the adjust SDK to successfully reattribute your user, you would need to queue this `NSURL` object information and trigger `appWillOpenUrl` method once the SDK has been initialised. #### Session tracking -Session tracking is something what the adjust SDK performs automatically and is beyond reach of an app developer. For -proper session tracking it is crucial to have the adjust SDK initialised as advised in this README. Not doing so can have -unpredicted influences on proper session tracking and DAU numbers in the dashboard. +Session tracking is something what the adjust SDK performs automatically and is beyond reach of an app developer. For proper session tracking it is crucial to have the adjust SDK initialised as advised in this README. Not doing so can have unpredicted influences on proper session tracking and DAU numbers in the dashboard. For example: -* A user opens but then deletes your app before the SDK was even inialised, causing the install and session to have never -been tracked, thus never reported in the dashboard. -* If a user downloads and opens your app before midnight, and the adjust SDK gets initialised after midnight, all queued -install and session data will be reported on wrong day. -* If a user didn't use your app on some day but opens it shortly after midnight and the SDK gets initialised after -midnight, causing DAU to be reported on another day from the day of the app opening. +* A user opens but then deletes your app before the SDK was even inialised, causing the install and session to have never been tracked, thus never reported in the dashboard. +* If a user downloads and opens your app before midnight, and the adjust SDK gets initialised after midnight, all queued install and session data will be reported on wrong day. +* If a user didn't use your app on some day but opens it shortly after midnight and the SDK gets initialised after midnight, causing DAU to be reported on another day from the day of the app opening. -For all these reasons, please follow the instructions in this document and initialise the adjust SDK in the -`didFinishLaunching` or `didFinishLaunchingWithOptions` method of your app delegate. +For all these reasons, please follow the instructions in this document and initialise the adjust SDK in the `didFinishLaunching` or `didFinishLaunchingWithOptions` method of your app delegate. ### I'm seeing "Adjust requires ARC" error -If your build failed with the error `Adjust requires ARC`, it looks like your project is not using [ARC][arc]. In that case -we recommend [transitioning your project][transition] so that it does use ARC. If you don't want to use ARC, you have to -enable ARC for all source files of adjust in the target's Build Phases: +If your build failed with the error `Adjust requires ARC`, it looks like your project is not using [ARC][arc]. In that case we recommend [transitioning your project][transition] so that it does use ARC. If you don't want to use ARC, you have to enable ARC for all source files of adjust in the target's Build Phases: -Expand the `Compile Sources` group, select all adjust files and change the `Compiler Flags` to `-fobjc-arc` (Select all and -press the `Return` key to change all at once). +Expand the `Compile Sources` group, select all adjust files and change the `Compiler Flags` to `-fobjc-arc` (Select all and press the `Return` key to change all at once). ### I'm seeing "[UIDevice adjTrackingEnabled]: unrecognized selector sent to instance" error -This error can occur when you are adding the adjust SDK framework to your app. The adjust SDK contains `categories` among -it's source files and for this reason, if you have chosen this SDK integration approach, you need to add `-ObjC` flags to -`Other Linker Flags` in your Xcode project settings. Adding this flag will fix this error. +This error can occur when you are adding the adjust SDK framework to your app. The adjust SDK contains `categories` among it's source files and for this reason, if you have chosen this SDK integration approach, you need to add `-ObjC` flags to `Other Linker Flags` in your Xcode project settings. Adding this flag will fix this error. ### I'm seeing the "Session failed (Ignoring too frequent session.)" error -This error typically occurs when testing installs. Uninstalling and reinstalling the app is not enough to trigger a new -install. The servers will determine that the SDK has lost its locally aggregated session data and ignore the erroneous -message, given the information available on the servers about the device. +This error typically occurs when testing installs. Uninstalling and reinstalling the app is not enough to trigger a new install. The servers will determine that the SDK has lost its locally aggregated session data and ignore the erroneous message, given the information available on the servers about the device. -This behaviour can be cumbersome during tests, but is necessary in order to have the sandbox behaviour match production as -much as possible. +This behaviour can be cumbersome during tests, but is necessary in order to have the sandbox behaviour match production as much as possible. You can reset the session data of the device in our servers. Check the error message in the logs: @@ -956,8 +831,7 @@ You can reset the session data of the device in our servers. Check the error mes Session failed (Ignoring too frequent session. Last session: YYYY-MM-DDTHH:mm:ss, this session: YYYY-MM-DDTHH:mm:ss, interval: XXs, min interval: 20m) (app_token: {yourAppToken}, adid: {adidValue}) ``` -With the `{yourAppToken}` and either `{adidValue}` or `{idfaValue}` values filled in below, open one -of the following links: +With the `{yourAppToken}` and either `{adidValue}` or `{idfaValue}` values filled in below, open one of the following links: ``` http://app.adjust.com/forget_device?app_token={yourAppToken}&adid={adidValue} @@ -967,16 +841,11 @@ http://app.adjust.com/forget_device?app_token={yourAppToken}&adid={adidValue} http://app.adjust.com/forget_device?app_token={yourAppToken}&idfa={idfaValue} ``` -When the device is forgotten, the link just returns `Forgot device`. If the device was already forgotten or the values were -incorrect, the link returns `Device not found`. +When the device is forgotten, the link just returns `Forgot device`. If the device was already forgotten or the values were incorrect, the link returns `Device not found`. ### I'm not seeing "Install tracked" in the logs -If you want to simulate the installation scenario of your app on your test device, it is not enough if you just re-run the -app from the Xcode on your test device. Re-running the app from the Xcode doesn't cause app data to be wiped out and all -internal files that our SDK is keeping inside your app will still be there, so upon re-run, our SDK will see those files -and think of your app was already installed (and that SDK was already launched in it) but just opened for another time -rather than being opened for the first time. +If you want to simulate the installation scenario of your app on your test device, it is not enough if you just re-run the app from the Xcode on your test device. Re-running the app from the Xcode doesn't cause app data to be wiped out and all internal files that our SDK is keeping inside your app will still be there, so upon re-run, our SDK will see those files and think of your app was already installed (and that SDK was already launched in it) but just opened for another time rather than being opened for the first time. In order to run app the installation scenario, you need to do following: @@ -986,13 +855,7 @@ In order to run app the installation scenario, you need to do following: ### I'm seeing the "Unattributable SDK click ignored" message -You may notice this message while testing your app in `sandbox` envoronment. It is related to some changes Apple introduced -in `iAd.framework` version 3. With this, a user can be directed to your app from a click on iAd banner and this will cause -our SDK to send an `sdk_click` package to the adjust backend informing it about the content of the clicked URL. For some -reason, Apple decided that if the app was opened without clicking on iAd banner, they will artificially generate an iAd -banner URL click with some random values. Our SDK won't be able to distinguish if the iAd banner click was genuine or -artificially generated and will send an `sdk_click` package regardless to the adjust backend. If you have your log level -set to `verbose` level, you will see this `sdk_click` package looking something like this: +You may notice this message while testing your app in `sandbox` envoronment. It is related to some changes Apple introduced in `iAd.framework` version 3. With this, a user can be directed to your app from a click on iAd banner and this will cause our SDK to send an `sdk_click` package to the adjust backend informing it about the content of the clicked URL. For some reason, Apple decided that if the app was opened without clicking on iAd banner, they will artificially generate an iAd banner URL click with some random values. Our SDK won't be able to distinguish if the iAd banner click was genuine or artificially generated and will send an `sdk_click` package regardless to the adjust backend. If you have your log level set to `verbose` level, you will see this `sdk_click` package looking something like this: ``` [Adjust]d: Added package 1 (click) @@ -1009,24 +872,18 @@ set to `verbose` level, you will see this `sdk_click` package looking something [Adjust]v: source iad3 ``` -If for some reason this `sdk_click` would be accepted, it would mean that a user who has opened your app by clicking on -some other campaign URL or even as an organic user, will get attributed to this unexisting iAd source. This is the reason -why our backend ignores it and informs you with this message: +If for some reason this `sdk_click` would be accepted, it would mean that a user who has opened your app by clicking on some other campaign URL or even as an organic user, will get attributed to this unexisting iAd source. This is the reason why our backend ignores it and informs you with this message: ``` [Adjust]v: Response: {"message":"Unattributable SDK click ignored."} [Adjust]i: Unattributable SDK click ignored. ``` -So, this message doesn't indicate any issue with your SDK integration but it's simply informing you that our backend has -ignored this artificially created `sdk_click` which could have lead to your user being wrongly attributed/reattributed. +So, this message doesn't indicate any issue with your SDK integration but it's simply informing you that our backend has ignored this artificially created `sdk_click` which could have lead to your user being wrongly attributed/reattributed. ### I'm seeing incorrect revenue data in the adjust dashboard -The adjust SDK tracks what you tell it to track. If you are attaching revenue to your event, the number you write as an -amount is the only amount which will reach the adjust backend and be displayed in the dashboard. Our SDK does not -manipulate your amount value, nor does our backend. So, if you see wrong amount being tracked, it's because our SDK was -told to track that amount. +The adjust SDK tracks what you tell it to track. If you are attaching revenue to your event, the number you write as an amount is the only amount which will reach the adjust backend and be displayed in the dashboard. Our SDK does not manipulate your amount value, nor does our backend. So, if you see wrong amount being tracked, it's because our SDK was told to track that amount. Usually, a user's code for tracking revenue event looks something like this: @@ -1061,8 +918,7 @@ Usually, a user's code for tracking revenue event looks something like this: ``` -If you are seing any value in the dashboard other than what you expected to be tracked, **please, check your logic for -determining amount value**. +If you are seing any value in the dashboard other than what you expected to be tracked, **please, check your logic for determining amount value**. [dashboard]: http://adjust.com diff --git a/VERSION b/VERSION index 8540cb180..a162ea75a 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -4.10.3 +4.11.0 diff --git a/examples/AdjustExample-Swift/AdjustExample-Swift/Adjust/AdjustSdk.framework/Versions/A/AdjustSdk b/examples/AdjustExample-Swift/AdjustExample-Swift/Adjust/AdjustSdk.framework/Versions/A/AdjustSdk index 5f70e085c..9f6a207b1 100644 Binary files a/examples/AdjustExample-Swift/AdjustExample-Swift/Adjust/AdjustSdk.framework/Versions/A/AdjustSdk and b/examples/AdjustExample-Swift/AdjustExample-Swift/Adjust/AdjustSdk.framework/Versions/A/AdjustSdk differ diff --git a/examples/AdjustExample-Swift/AdjustExample-Swift/Adjust/AdjustSdk.framework/Versions/A/Headers/ADJAttribution.h b/examples/AdjustExample-Swift/AdjustExample-Swift/Adjust/AdjustSdk.framework/Versions/A/Headers/ADJAttribution.h index 21faee13e..9eae036ec 100644 --- a/examples/AdjustExample-Swift/AdjustExample-Swift/Adjust/AdjustSdk.framework/Versions/A/Headers/ADJAttribution.h +++ b/examples/AdjustExample-Swift/AdjustExample-Swift/Adjust/AdjustSdk.framework/Versions/A/Headers/ADJAttribution.h @@ -34,10 +34,14 @@ // tracker click_label @property (nonatomic, copy) NSString *clickLabel; +@property (nonatomic, copy) NSString *adid; + - (BOOL)isEqualToAttribution:(ADJAttribution *)attribution; -+ (ADJAttribution *)dataWithJsonDict:(NSDictionary *)jsonDict; -- (id)initWithJsonDict:(NSDictionary *)jsonDict; ++ (ADJAttribution *)dataWithJsonDict:(NSDictionary *)jsonDict + adid:(NSString *)adid; +- (id)initWithJsonDict:(NSDictionary *)jsonDict + adid:(NSString *)adid; - (NSDictionary *)dictionary; @end diff --git a/examples/AdjustExample-Swift/AdjustExample-Swift/Adjust/AdjustSdk.framework/Versions/A/Headers/ADJConfig.h b/examples/AdjustExample-Swift/AdjustExample-Swift/Adjust/AdjustSdk.framework/Versions/A/Headers/ADJConfig.h index 7f5f97155..768ce6251 100644 --- a/examples/AdjustExample-Swift/AdjustExample-Swift/Adjust/AdjustSdk.framework/Versions/A/Headers/ADJConfig.h +++ b/examples/AdjustExample-Swift/AdjustExample-Swift/Adjust/AdjustSdk.framework/Versions/A/Headers/ADJConfig.h @@ -170,7 +170,5 @@ */ @property (nonatomic, copy) NSString *userAgent; -@property (nonatomic, assign, readonly) BOOL hasResponseDelegate; - - (BOOL) isValid; @end diff --git a/examples/AdjustExample-Swift/AdjustExample-Swift/Adjust/AdjustSdk.framework/Versions/A/Headers/Adjust.h b/examples/AdjustExample-Swift/AdjustExample-Swift/Adjust/AdjustSdk.framework/Versions/A/Headers/Adjust.h index 4143e7b5a..4bf15164c 100644 --- a/examples/AdjustExample-Swift/AdjustExample-Swift/Adjust/AdjustSdk.framework/Versions/A/Headers/Adjust.h +++ b/examples/AdjustExample-Swift/AdjustExample-Swift/Adjust/AdjustSdk.framework/Versions/A/Headers/Adjust.h @@ -2,7 +2,7 @@ // Adjust.h // Adjust // -// V4.10.3 +// V4.11.0 // Created by Christian Wellenbrock on 2012-07-23. // Copyright (c) 2012-2014 adjust GmbH. All rights reserved. // @@ -171,6 +171,9 @@ extern NSString * const ADJEnvironmentProduction; */ + (void)resetSessionPartnerParameters; ++ (ADJAttribution *)attribution; ++ (NSString *)adid; + /** * Obtain singleton Adjust object */ @@ -197,5 +200,7 @@ extern NSString * const ADJEnvironmentProduction; - (void)removeSessionCallbackParameter:(NSString *)key; - (void)addSessionPartnerParameter:(NSString *)key value:(NSString *)value; - (void)addSessionCallbackParameter:(NSString *)key value:(NSString *)value; +- (ADJAttribution *)attribution; +- (NSString *)adid; @end diff --git a/examples/AdjustExample-WebView/AdjustExample-WebView/Adjust/AdjustSdk.framework/Versions/A/AdjustSdk b/examples/AdjustExample-WebView/AdjustExample-WebView/Adjust/AdjustSdk.framework/Versions/A/AdjustSdk index 5f70e085c..9f6a207b1 100644 Binary files a/examples/AdjustExample-WebView/AdjustExample-WebView/Adjust/AdjustSdk.framework/Versions/A/AdjustSdk and b/examples/AdjustExample-WebView/AdjustExample-WebView/Adjust/AdjustSdk.framework/Versions/A/AdjustSdk differ diff --git a/examples/AdjustExample-WebView/AdjustExample-WebView/Adjust/AdjustSdk.framework/Versions/A/Headers/ADJAttribution.h b/examples/AdjustExample-WebView/AdjustExample-WebView/Adjust/AdjustSdk.framework/Versions/A/Headers/ADJAttribution.h index 21faee13e..9eae036ec 100644 --- a/examples/AdjustExample-WebView/AdjustExample-WebView/Adjust/AdjustSdk.framework/Versions/A/Headers/ADJAttribution.h +++ b/examples/AdjustExample-WebView/AdjustExample-WebView/Adjust/AdjustSdk.framework/Versions/A/Headers/ADJAttribution.h @@ -34,10 +34,14 @@ // tracker click_label @property (nonatomic, copy) NSString *clickLabel; +@property (nonatomic, copy) NSString *adid; + - (BOOL)isEqualToAttribution:(ADJAttribution *)attribution; -+ (ADJAttribution *)dataWithJsonDict:(NSDictionary *)jsonDict; -- (id)initWithJsonDict:(NSDictionary *)jsonDict; ++ (ADJAttribution *)dataWithJsonDict:(NSDictionary *)jsonDict + adid:(NSString *)adid; +- (id)initWithJsonDict:(NSDictionary *)jsonDict + adid:(NSString *)adid; - (NSDictionary *)dictionary; @end diff --git a/examples/AdjustExample-WebView/AdjustExample-WebView/Adjust/AdjustSdk.framework/Versions/A/Headers/ADJConfig.h b/examples/AdjustExample-WebView/AdjustExample-WebView/Adjust/AdjustSdk.framework/Versions/A/Headers/ADJConfig.h index 7f5f97155..768ce6251 100644 --- a/examples/AdjustExample-WebView/AdjustExample-WebView/Adjust/AdjustSdk.framework/Versions/A/Headers/ADJConfig.h +++ b/examples/AdjustExample-WebView/AdjustExample-WebView/Adjust/AdjustSdk.framework/Versions/A/Headers/ADJConfig.h @@ -170,7 +170,5 @@ */ @property (nonatomic, copy) NSString *userAgent; -@property (nonatomic, assign, readonly) BOOL hasResponseDelegate; - - (BOOL) isValid; @end diff --git a/examples/AdjustExample-WebView/AdjustExample-WebView/Adjust/AdjustSdk.framework/Versions/A/Headers/Adjust.h b/examples/AdjustExample-WebView/AdjustExample-WebView/Adjust/AdjustSdk.framework/Versions/A/Headers/Adjust.h index 4143e7b5a..4bf15164c 100644 --- a/examples/AdjustExample-WebView/AdjustExample-WebView/Adjust/AdjustSdk.framework/Versions/A/Headers/Adjust.h +++ b/examples/AdjustExample-WebView/AdjustExample-WebView/Adjust/AdjustSdk.framework/Versions/A/Headers/Adjust.h @@ -2,7 +2,7 @@ // Adjust.h // Adjust // -// V4.10.3 +// V4.11.0 // Created by Christian Wellenbrock on 2012-07-23. // Copyright (c) 2012-2014 adjust GmbH. All rights reserved. // @@ -171,6 +171,9 @@ extern NSString * const ADJEnvironmentProduction; */ + (void)resetSessionPartnerParameters; ++ (ADJAttribution *)attribution; ++ (NSString *)adid; + /** * Obtain singleton Adjust object */ @@ -197,5 +200,7 @@ extern NSString * const ADJEnvironmentProduction; - (void)removeSessionCallbackParameter:(NSString *)key; - (void)addSessionPartnerParameter:(NSString *)key value:(NSString *)value; - (void)addSessionCallbackParameter:(NSString *)key value:(NSString *)value; +- (ADJAttribution *)attribution; +- (NSString *)adid; @end diff --git a/examples/AdjustExample-iOS/AdjustExample-iOS/Adjust/AdjustSdk.framework/Versions/A/AdjustSdk b/examples/AdjustExample-iOS/AdjustExample-iOS/Adjust/AdjustSdk.framework/Versions/A/AdjustSdk index 5f70e085c..9f6a207b1 100644 Binary files a/examples/AdjustExample-iOS/AdjustExample-iOS/Adjust/AdjustSdk.framework/Versions/A/AdjustSdk and b/examples/AdjustExample-iOS/AdjustExample-iOS/Adjust/AdjustSdk.framework/Versions/A/AdjustSdk differ diff --git a/examples/AdjustExample-iOS/AdjustExample-iOS/Adjust/AdjustSdk.framework/Versions/A/Headers/ADJAttribution.h b/examples/AdjustExample-iOS/AdjustExample-iOS/Adjust/AdjustSdk.framework/Versions/A/Headers/ADJAttribution.h index 21faee13e..9eae036ec 100644 --- a/examples/AdjustExample-iOS/AdjustExample-iOS/Adjust/AdjustSdk.framework/Versions/A/Headers/ADJAttribution.h +++ b/examples/AdjustExample-iOS/AdjustExample-iOS/Adjust/AdjustSdk.framework/Versions/A/Headers/ADJAttribution.h @@ -34,10 +34,14 @@ // tracker click_label @property (nonatomic, copy) NSString *clickLabel; +@property (nonatomic, copy) NSString *adid; + - (BOOL)isEqualToAttribution:(ADJAttribution *)attribution; -+ (ADJAttribution *)dataWithJsonDict:(NSDictionary *)jsonDict; -- (id)initWithJsonDict:(NSDictionary *)jsonDict; ++ (ADJAttribution *)dataWithJsonDict:(NSDictionary *)jsonDict + adid:(NSString *)adid; +- (id)initWithJsonDict:(NSDictionary *)jsonDict + adid:(NSString *)adid; - (NSDictionary *)dictionary; @end diff --git a/examples/AdjustExample-iOS/AdjustExample-iOS/Adjust/AdjustSdk.framework/Versions/A/Headers/ADJConfig.h b/examples/AdjustExample-iOS/AdjustExample-iOS/Adjust/AdjustSdk.framework/Versions/A/Headers/ADJConfig.h index 7f5f97155..768ce6251 100644 --- a/examples/AdjustExample-iOS/AdjustExample-iOS/Adjust/AdjustSdk.framework/Versions/A/Headers/ADJConfig.h +++ b/examples/AdjustExample-iOS/AdjustExample-iOS/Adjust/AdjustSdk.framework/Versions/A/Headers/ADJConfig.h @@ -170,7 +170,5 @@ */ @property (nonatomic, copy) NSString *userAgent; -@property (nonatomic, assign, readonly) BOOL hasResponseDelegate; - - (BOOL) isValid; @end diff --git a/examples/AdjustExample-iOS/AdjustExample-iOS/Adjust/AdjustSdk.framework/Versions/A/Headers/Adjust.h b/examples/AdjustExample-iOS/AdjustExample-iOS/Adjust/AdjustSdk.framework/Versions/A/Headers/Adjust.h index 4143e7b5a..4bf15164c 100644 --- a/examples/AdjustExample-iOS/AdjustExample-iOS/Adjust/AdjustSdk.framework/Versions/A/Headers/Adjust.h +++ b/examples/AdjustExample-iOS/AdjustExample-iOS/Adjust/AdjustSdk.framework/Versions/A/Headers/Adjust.h @@ -2,7 +2,7 @@ // Adjust.h // Adjust // -// V4.10.3 +// V4.11.0 // Created by Christian Wellenbrock on 2012-07-23. // Copyright (c) 2012-2014 adjust GmbH. All rights reserved. // @@ -171,6 +171,9 @@ extern NSString * const ADJEnvironmentProduction; */ + (void)resetSessionPartnerParameters; ++ (ADJAttribution *)attribution; ++ (NSString *)adid; + /** * Obtain singleton Adjust object */ @@ -197,5 +200,7 @@ extern NSString * const ADJEnvironmentProduction; - (void)removeSessionCallbackParameter:(NSString *)key; - (void)addSessionPartnerParameter:(NSString *)key value:(NSString *)value; - (void)addSessionCallbackParameter:(NSString *)key value:(NSString *)value; +- (ADJAttribution *)attribution; +- (NSString *)adid; @end diff --git a/examples/AdjustExample-iWatch/AdjustExample-iWatch/Adjust/AdjustSdk.framework/Versions/A/AdjustSdk b/examples/AdjustExample-iWatch/AdjustExample-iWatch/Adjust/AdjustSdk.framework/Versions/A/AdjustSdk index 5f70e085c..9f6a207b1 100644 Binary files a/examples/AdjustExample-iWatch/AdjustExample-iWatch/Adjust/AdjustSdk.framework/Versions/A/AdjustSdk and b/examples/AdjustExample-iWatch/AdjustExample-iWatch/Adjust/AdjustSdk.framework/Versions/A/AdjustSdk differ diff --git a/examples/AdjustExample-iWatch/AdjustExample-iWatch/Adjust/AdjustSdk.framework/Versions/A/Headers/ADJAttribution.h b/examples/AdjustExample-iWatch/AdjustExample-iWatch/Adjust/AdjustSdk.framework/Versions/A/Headers/ADJAttribution.h index 21faee13e..9eae036ec 100644 --- a/examples/AdjustExample-iWatch/AdjustExample-iWatch/Adjust/AdjustSdk.framework/Versions/A/Headers/ADJAttribution.h +++ b/examples/AdjustExample-iWatch/AdjustExample-iWatch/Adjust/AdjustSdk.framework/Versions/A/Headers/ADJAttribution.h @@ -34,10 +34,14 @@ // tracker click_label @property (nonatomic, copy) NSString *clickLabel; +@property (nonatomic, copy) NSString *adid; + - (BOOL)isEqualToAttribution:(ADJAttribution *)attribution; -+ (ADJAttribution *)dataWithJsonDict:(NSDictionary *)jsonDict; -- (id)initWithJsonDict:(NSDictionary *)jsonDict; ++ (ADJAttribution *)dataWithJsonDict:(NSDictionary *)jsonDict + adid:(NSString *)adid; +- (id)initWithJsonDict:(NSDictionary *)jsonDict + adid:(NSString *)adid; - (NSDictionary *)dictionary; @end diff --git a/examples/AdjustExample-iWatch/AdjustExample-iWatch/Adjust/AdjustSdk.framework/Versions/A/Headers/ADJConfig.h b/examples/AdjustExample-iWatch/AdjustExample-iWatch/Adjust/AdjustSdk.framework/Versions/A/Headers/ADJConfig.h index 7f5f97155..768ce6251 100644 --- a/examples/AdjustExample-iWatch/AdjustExample-iWatch/Adjust/AdjustSdk.framework/Versions/A/Headers/ADJConfig.h +++ b/examples/AdjustExample-iWatch/AdjustExample-iWatch/Adjust/AdjustSdk.framework/Versions/A/Headers/ADJConfig.h @@ -170,7 +170,5 @@ */ @property (nonatomic, copy) NSString *userAgent; -@property (nonatomic, assign, readonly) BOOL hasResponseDelegate; - - (BOOL) isValid; @end diff --git a/examples/AdjustExample-iWatch/AdjustExample-iWatch/Adjust/AdjustSdk.framework/Versions/A/Headers/Adjust.h b/examples/AdjustExample-iWatch/AdjustExample-iWatch/Adjust/AdjustSdk.framework/Versions/A/Headers/Adjust.h index 4143e7b5a..4bf15164c 100644 --- a/examples/AdjustExample-iWatch/AdjustExample-iWatch/Adjust/AdjustSdk.framework/Versions/A/Headers/Adjust.h +++ b/examples/AdjustExample-iWatch/AdjustExample-iWatch/Adjust/AdjustSdk.framework/Versions/A/Headers/Adjust.h @@ -2,7 +2,7 @@ // Adjust.h // Adjust // -// V4.10.3 +// V4.11.0 // Created by Christian Wellenbrock on 2012-07-23. // Copyright (c) 2012-2014 adjust GmbH. All rights reserved. // @@ -171,6 +171,9 @@ extern NSString * const ADJEnvironmentProduction; */ + (void)resetSessionPartnerParameters; ++ (ADJAttribution *)attribution; ++ (NSString *)adid; + /** * Obtain singleton Adjust object */ @@ -197,5 +200,7 @@ extern NSString * const ADJEnvironmentProduction; - (void)removeSessionCallbackParameter:(NSString *)key; - (void)addSessionPartnerParameter:(NSString *)key value:(NSString *)value; - (void)addSessionCallbackParameter:(NSString *)key value:(NSString *)value; +- (ADJAttribution *)attribution; +- (NSString *)adid; @end diff --git a/examples/AdjustExample-tvOS/AdjustExample-tvOS/Adjust/AdjustSdkTV.framework/AdjustSdkTV b/examples/AdjustExample-tvOS/AdjustExample-tvOS/Adjust/AdjustSdkTV.framework/AdjustSdkTV index 9f821fa1d..4496ed067 100755 Binary files a/examples/AdjustExample-tvOS/AdjustExample-tvOS/Adjust/AdjustSdkTV.framework/AdjustSdkTV and b/examples/AdjustExample-tvOS/AdjustExample-tvOS/Adjust/AdjustSdkTV.framework/AdjustSdkTV differ diff --git a/examples/AdjustExample-tvOS/AdjustExample-tvOS/Adjust/AdjustSdkTV.framework/Headers/ADJAttribution.h b/examples/AdjustExample-tvOS/AdjustExample-tvOS/Adjust/AdjustSdkTV.framework/Headers/ADJAttribution.h index 21faee13e..9eae036ec 100644 --- a/examples/AdjustExample-tvOS/AdjustExample-tvOS/Adjust/AdjustSdkTV.framework/Headers/ADJAttribution.h +++ b/examples/AdjustExample-tvOS/AdjustExample-tvOS/Adjust/AdjustSdkTV.framework/Headers/ADJAttribution.h @@ -34,10 +34,14 @@ // tracker click_label @property (nonatomic, copy) NSString *clickLabel; +@property (nonatomic, copy) NSString *adid; + - (BOOL)isEqualToAttribution:(ADJAttribution *)attribution; -+ (ADJAttribution *)dataWithJsonDict:(NSDictionary *)jsonDict; -- (id)initWithJsonDict:(NSDictionary *)jsonDict; ++ (ADJAttribution *)dataWithJsonDict:(NSDictionary *)jsonDict + adid:(NSString *)adid; +- (id)initWithJsonDict:(NSDictionary *)jsonDict + adid:(NSString *)adid; - (NSDictionary *)dictionary; @end diff --git a/examples/AdjustExample-tvOS/AdjustExample-tvOS/Adjust/AdjustSdkTV.framework/Headers/ADJConfig.h b/examples/AdjustExample-tvOS/AdjustExample-tvOS/Adjust/AdjustSdkTV.framework/Headers/ADJConfig.h index 7f5f97155..768ce6251 100644 --- a/examples/AdjustExample-tvOS/AdjustExample-tvOS/Adjust/AdjustSdkTV.framework/Headers/ADJConfig.h +++ b/examples/AdjustExample-tvOS/AdjustExample-tvOS/Adjust/AdjustSdkTV.framework/Headers/ADJConfig.h @@ -170,7 +170,5 @@ */ @property (nonatomic, copy) NSString *userAgent; -@property (nonatomic, assign, readonly) BOOL hasResponseDelegate; - - (BOOL) isValid; @end diff --git a/examples/AdjustExample-tvOS/AdjustExample-tvOS/Adjust/AdjustSdkTV.framework/Headers/Adjust.h b/examples/AdjustExample-tvOS/AdjustExample-tvOS/Adjust/AdjustSdkTV.framework/Headers/Adjust.h index 4143e7b5a..4bf15164c 100644 --- a/examples/AdjustExample-tvOS/AdjustExample-tvOS/Adjust/AdjustSdkTV.framework/Headers/Adjust.h +++ b/examples/AdjustExample-tvOS/AdjustExample-tvOS/Adjust/AdjustSdkTV.framework/Headers/Adjust.h @@ -2,7 +2,7 @@ // Adjust.h // Adjust // -// V4.10.3 +// V4.11.0 // Created by Christian Wellenbrock on 2012-07-23. // Copyright (c) 2012-2014 adjust GmbH. All rights reserved. // @@ -171,6 +171,9 @@ extern NSString * const ADJEnvironmentProduction; */ + (void)resetSessionPartnerParameters; ++ (ADJAttribution *)attribution; ++ (NSString *)adid; + /** * Obtain singleton Adjust object */ @@ -197,5 +200,7 @@ extern NSString * const ADJEnvironmentProduction; - (void)removeSessionCallbackParameter:(NSString *)key; - (void)addSessionPartnerParameter:(NSString *)key value:(NSString *)value; - (void)addSessionCallbackParameter:(NSString *)key value:(NSString *)value; +- (ADJAttribution *)attribution; +- (NSString *)adid; @end diff --git a/examples/AdjustExample-tvOS/AdjustExample-tvOS/Adjust/AdjustSdkTV.framework/Info.plist b/examples/AdjustExample-tvOS/AdjustExample-tvOS/Adjust/AdjustSdkTV.framework/Info.plist index c413ff200..14d7192a8 100644 Binary files a/examples/AdjustExample-tvOS/AdjustExample-tvOS/Adjust/AdjustSdkTV.framework/Info.plist and b/examples/AdjustExample-tvOS/AdjustExample-tvOS/Adjust/AdjustSdkTV.framework/Info.plist differ diff --git a/plugin/Criteo/ADJCriteo.h b/plugin/Criteo/ADJCriteo.h index 5ca075383..dd83603e6 100644 --- a/plugin/Criteo/ADJCriteo.h +++ b/plugin/Criteo/ADJCriteo.h @@ -28,42 +28,34 @@ @interface ADJCriteo : NSObject + (void)injectViewListingIntoEvent:(ADJEvent *)event - productIds:(NSArray *)productIds - customerId:(NSString *)customerId; + productIds:(NSArray *)productIds; + (void)injectViewProductIntoEvent:(ADJEvent *)event - productId:(NSString *)productId - customerId:(NSString *)customerId; + productId:(NSString *)productId; + (void)injectCartIntoEvent:(ADJEvent *)event - products:(NSArray *)products - customerId:(NSString *)customerId; + products:(NSArray *)products; + (void)injectTransactionConfirmedIntoEvent:(ADJEvent *)event products:(NSArray *)products transactionId:(NSString *)transactionId - customerId:(NSString *)customerId; + newCustomer:(NSString *)newCustomer; + (void)injectUserLevelIntoEvent:(ADJEvent *)event - uiLevel:(NSUInteger)uiLevel - customerId:(NSString *)customerId; + uiLevel:(NSUInteger)uiLevel; + (void)injectUserStatusIntoEvent:(ADJEvent *)event - uiStatus:(NSString *)uiStatus - customerId:(NSString *)customerId; + uiStatus:(NSString *)uiStatus; + (void)injectAchievementUnlockedIntoEvent:(ADJEvent *)event - uiAchievement:(NSString *)uiAchievement - customerId:(NSString *)customerId; + uiAchievement:(NSString *)uiAchievement; + (void)injectCustomEventIntoEvent:(ADJEvent *)event - uiData:(NSString *)uiData - customerId:(NSString *)customerId; + uiData:(NSString *)uiData; + (void)injectCustomEvent2IntoEvent:(ADJEvent *)event uiData2:(NSString *)uiData2 - uiData3:(NSUInteger)uiData3 - customerId:(NSString *)customerId; + uiData3:(NSUInteger)uiData3; + (void)injectDeeplinkIntoEvent:(ADJEvent *)event url:(NSURL *)url; @@ -75,4 +67,8 @@ + (void)injectPartnerIdIntoCriteoEvents:(NSString *)partnerId; ++ (void)injectUserSegmentIntoCriteoEvents:(NSString *)userSegment; + ++ (void)injectCustomerIdIntoCriteoEvents:(NSString *)customerId; + @end diff --git a/plugin/Criteo/ADJCriteo.m b/plugin/Criteo/ADJCriteo.m index dc5d26115..82218e894 100644 --- a/plugin/Criteo/ADJCriteo.m +++ b/plugin/Criteo/ADJCriteo.m @@ -43,6 +43,8 @@ @implementation ADJCriteo static NSString * checkInDateInternal; static NSString * checkOutDateInternal; static NSString * partnerIdInternal; +static NSString * userSegmentInternal; +static NSString * customerIdInternal; + (id) logger { return ADJAdjustFactory.logger; @@ -60,10 +62,7 @@ + (void)injectViewSearchIntoEvent:(ADJEvent *)event + (void)injectViewListingIntoEvent:(ADJEvent *)event productIds:(NSArray *)productIds - customerId:(NSString *)customerId { - [event addPartnerParameter:@"customer_id" value:customerId]; - NSString * jsonProductsIds = [ADJCriteo createCriteoVLFromProducts:productIds]; [event addPartnerParameter:@"criteo_p" value:jsonProductsIds]; @@ -72,9 +71,7 @@ + (void)injectViewListingIntoEvent:(ADJEvent *)event + (void)injectViewProductIntoEvent:(ADJEvent *)event productId:(NSString *)productId - customerId:(NSString *)customerId { - [event addPartnerParameter:@"customer_id" value:customerId]; [event addPartnerParameter:@"criteo_p" value:productId]; [ADJCriteo injectOptionalParams:event]; @@ -82,10 +79,7 @@ + (void)injectViewProductIntoEvent:(ADJEvent *)event + (void)injectCartIntoEvent:(ADJEvent *)event products:(NSArray *)products - customerId:(NSString *)customerId { - [event addPartnerParameter:@"customer_id" value:customerId]; - NSString * jsonProducts = [ADJCriteo createCriteoVBFromProducts:products]; [event addPartnerParameter:@"criteo_p" value:jsonProducts]; @@ -95,23 +89,20 @@ + (void)injectCartIntoEvent:(ADJEvent *)event + (void)injectTransactionConfirmedIntoEvent:(ADJEvent *)event products:(NSArray *)products transactionId:(NSString *)transactionId - customerId:(NSString *)customerId + newCustomer:(NSString *)newCustomer { - [event addPartnerParameter:@"customer_id" value:customerId]; [event addPartnerParameter:@"transaction_id" value:transactionId]; NSString * jsonProducts = [ADJCriteo createCriteoVBFromProducts:products]; [event addPartnerParameter:@"criteo_p" value:jsonProducts]; + [event addPartnerParameter:@"new_customer" value:newCustomer]; [ADJCriteo injectOptionalParams:event]; } + (void)injectUserLevelIntoEvent:(ADJEvent *)event uiLevel:(NSUInteger)uiLevel - customerId:(NSString *)customerId { - [event addPartnerParameter:@"customer_id" value:customerId]; - NSString * uiLevelString = [NSString stringWithFormat:@"%lu",(unsigned long)uiLevel]; [event addPartnerParameter:@"ui_level" value:uiLevelString]; @@ -120,9 +111,7 @@ + (void)injectUserLevelIntoEvent:(ADJEvent *)event + (void)injectUserStatusIntoEvent:(ADJEvent *)event uiStatus:(NSString *)uiStatus - customerId:(NSString *)customerId { - [event addPartnerParameter:@"customer_id" value:customerId]; [event addPartnerParameter:@"ui_status" value:uiStatus]; [ADJCriteo injectOptionalParams:event]; @@ -130,9 +119,7 @@ + (void)injectUserStatusIntoEvent:(ADJEvent *)event + (void)injectAchievementUnlockedIntoEvent:(ADJEvent *)event uiAchievement:(NSString *)uiAchievement - customerId:(NSString *)customerId { - [event addPartnerParameter:@"customer_id" value:customerId]; [event addPartnerParameter:@"ui_achievmnt" value:uiAchievement]; [ADJCriteo injectOptionalParams:event]; @@ -140,9 +127,7 @@ + (void)injectAchievementUnlockedIntoEvent:(ADJEvent *)event + (void)injectCustomEventIntoEvent:(ADJEvent *)event uiData:(NSString *)uiData - customerId:(NSString *)customerId { - [event addPartnerParameter:@"customer_id" value:customerId]; [event addPartnerParameter:@"ui_data" value:uiData]; [ADJCriteo injectOptionalParams:event]; @@ -151,9 +136,7 @@ + (void)injectCustomEventIntoEvent:(ADJEvent *)event + (void)injectCustomEvent2IntoEvent:(ADJEvent *)event uiData2:(NSString *)uiData2 uiData3:(NSUInteger)uiData3 - customerId:(NSString *)customerId { - [event addPartnerParameter:@"customer_id" value:customerId]; [event addPartnerParameter:@"ui_data2" value:uiData2]; NSString * uiData3String = [NSString stringWithFormat:@"%lu",(unsigned long)uiData3]; @@ -191,10 +174,22 @@ + (void)injectPartnerIdIntoCriteoEvents:(NSString *)partnerId partnerIdInternal = partnerId; } ++ (void)injectUserSegmentIntoCriteoEvents:(NSString *)userSegment +{ + userSegmentInternal = userSegment; +} + ++ (void)injectCustomerIdIntoCriteoEvents:(NSString *)customerId +{ + customerIdInternal = customerId; +} + + (void)injectOptionalParams:(ADJEvent *)event { [ADJCriteo injectHashEmail:event]; [ADJCriteo injectSearchDates:event]; [ADJCriteo injectPartnerId:event]; + [ADJCriteo injectUserSegment:event]; + [ADJCriteo injectCustomerId:event]; } + (void)injectHashEmail:(ADJEvent *)event { @@ -219,6 +214,20 @@ + (void)injectPartnerId:(ADJEvent *)event { [event addPartnerParameter:@"criteo_partner_id" value:partnerIdInternal]; } ++ (void)injectUserSegment:(ADJEvent *)event { + if (userSegmentInternal == nil) { + return; + } + [event addPartnerParameter:@"user_segment" value:userSegmentInternal]; +} + ++ (void)injectCustomerId:(ADJEvent *)event { + if (customerIdInternal == nil) { + return; + } + [event addPartnerParameter:@"customer_id" value:customerIdInternal]; +} + + (NSString*) createCriteoVBFromProducts:(NSArray*) products { if (products == nil) {