diff --git a/Adjust.podspec b/Adjust.podspec index 48ca88470..493637c38 100644 --- a/Adjust.podspec +++ b/Adjust.podspec @@ -1,11 +1,11 @@ Pod::Spec.new do |s| s.name = "Adjust" - s.version = "4.14.3" + s.version = "4.15.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.14.3" } + s.source = { :git => "https://github.com/adjust/ios_sdk.git", :tag => "v4.15.0" } s.ios.deployment_target = '6.0' s.tvos.deployment_target = '9.0' s.framework = 'SystemConfiguration' diff --git a/Adjust.xcodeproj/project.pbxproj b/Adjust.xcodeproj/project.pbxproj index 7deefe82e..69b5a3032 100644 --- a/Adjust.xcodeproj/project.pbxproj +++ b/Adjust.xcodeproj/project.pbxproj @@ -23,7 +23,6 @@ /* Begin PBXBuildFile section */ 2067002A1F18BDC700B4FDE1 /* CoreTelephony.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9601C19C1A31DD7F00A9AE21 /* CoreTelephony.framework */; settings = {ATTRIBUTES = (Weak, ); }; }; - 6FA69FD72101E00100FCD3B5 /* AdjustBridge_JS.m in Sources */ = {isa = PBXBuildFile; fileRef = 6FA69FD62101E00100FCD3B5 /* AdjustBridge_JS.m */; }; 6FCC85001F278CF300D6A0ED /* ADJReachability.m in Sources */ = {isa = PBXBuildFile; fileRef = 6FCC84F71F278CF300D6A0ED /* ADJReachability.m */; }; 6FCC85011F278CF300D6A0ED /* ADJReachability.h in Headers */ = {isa = PBXBuildFile; fileRef = 6FCC84F81F278CF300D6A0ED /* ADJReachability.h */; }; 6FCC85041F27945E00D6A0ED /* ADJReachability.h in Headers */ = {isa = PBXBuildFile; fileRef = 6FCC85021F27944600D6A0ED /* ADJReachability.h */; }; @@ -211,12 +210,10 @@ 9D0E2EAE210B575600133B4F /* AdjustBridge.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D0E2E5C210B575600133B4F /* AdjustBridge.m */; }; 9D0E2EAF210B575600133B4F /* AdjustBridgeRegister.h in Headers */ = {isa = PBXBuildFile; fileRef = 9D0E2E5D210B575600133B4F /* AdjustBridgeRegister.h */; settings = {ATTRIBUTES = (Public, ); }; }; 9D0E2EB0210B575600133B4F /* WebViewJavascriptBridgeBase.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D0E2E5F210B575600133B4F /* WebViewJavascriptBridgeBase.m */; }; - 9D0E2EB1210B575600133B4F /* AdjustBridge_JS.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D0E2E60210B575600133B4F /* AdjustBridge_JS.m */; }; 9D0E2EB2210B575600133B4F /* WKWebViewJavascriptBridge.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D0E2E61210B575600133B4F /* WKWebViewJavascriptBridge.m */; }; 9D0E2EB3210B575600133B4F /* WebViewJavascriptBridge.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D0E2E62210B575600133B4F /* WebViewJavascriptBridge.m */; }; 9D0E2EB4210B575600133B4F /* WebViewJavascriptBridge_JS.h in Headers */ = {isa = PBXBuildFile; fileRef = 9D0E2E63210B575600133B4F /* WebViewJavascriptBridge_JS.h */; settings = {ATTRIBUTES = (Public, ); }; }; 9D0E2EB5210B575600133B4F /* WebViewJavascriptBridgeBase.h in Headers */ = {isa = PBXBuildFile; fileRef = 9D0E2E64210B575600133B4F /* WebViewJavascriptBridgeBase.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 9D0E2EB6210B575600133B4F /* AdjustBridge_JS.h in Headers */ = {isa = PBXBuildFile; fileRef = 9D0E2E65210B575600133B4F /* AdjustBridge_JS.h */; settings = {ATTRIBUTES = (Public, ); }; }; 9D0E2EB7210B575600133B4F /* WebViewJavascriptBridge_JS.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D0E2E66210B575600133B4F /* WebViewJavascriptBridge_JS.m */; }; 9D0E2EB8210B575600133B4F /* WebViewJavascriptBridge.h in Headers */ = {isa = PBXBuildFile; fileRef = 9D0E2E67210B575600133B4F /* WebViewJavascriptBridge.h */; settings = {ATTRIBUTES = (Public, ); }; }; 9D0E2EB9210B575600133B4F /* WKWebViewJavascriptBridge.h in Headers */ = {isa = PBXBuildFile; fileRef = 9D0E2E68210B575600133B4F /* WKWebViewJavascriptBridge.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -519,6 +516,13 @@ remoteGlobalIDString = 9D7431E51EB9F9B700969F14; remoteInfo = AdjustExampleTests; }; + 9D9D1551212EB3D00081445E /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 9D9D154D212EB3D00081445E /* AdjustExample-FbPixel.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 9D9D152E212EB3920081445E; + remoteInfo = "AdjustExample-FbPixel"; + }; 9DE7C8FF1AE68EF1001556E5 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 9679920518BBAE2800394606 /* Project object */; @@ -553,8 +557,6 @@ /* Begin PBXFileReference section */ 6F0842182007766700568A31 /* AdjustTestLibrary.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = AdjustTestLibrary.xcodeproj; path = AdjustTestLibrary/AdjustTestLibrary.xcodeproj; sourceTree = ""; }; 6F084240200776A000568A31 /* AdjustTestApp.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = AdjustTestApp.xcodeproj; path = AdjustTestApp/AdjustTestApp.xcodeproj; sourceTree = ""; }; - 6FA69FD52101E00100FCD3B5 /* AdjustBridge_JS.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AdjustBridge_JS.h; sourceTree = ""; }; - 6FA69FD62101E00100FCD3B5 /* AdjustBridge_JS.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AdjustBridge_JS.m; sourceTree = ""; }; 6FCC84F71F278CF300D6A0ED /* ADJReachability.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ADJReachability.m; sourceTree = ""; }; 6FCC84F81F278CF300D6A0ED /* ADJReachability.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ADJReachability.h; sourceTree = ""; }; 6FCC85021F27944600D6A0ED /* ADJReachability.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ADJReachability.h; sourceTree = ""; }; @@ -791,6 +793,7 @@ 9D7431F41EB9F9B700969F14 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 9D7431F71EB9F9B700969F14 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 9D7431F91EB9F9B700969F14 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 9D9D154D212EB3D00081445E /* AdjustExample-FbPixel.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = "AdjustExample-FbPixel.xcodeproj"; path = "examples/AdjustExample-FbPixel/AdjustExample-FbPixel.xcodeproj"; sourceTree = ""; }; 9DD0E9AC1F44690B00B2A759 /* ADJUserDefaults.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ADJUserDefaults.h; sourceTree = ""; }; 9DD0E9AD1F44690B00B2A759 /* ADJUserDefaults.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ADJUserDefaults.m; sourceTree = ""; }; 9DE354D22100726300D211C9 /* AdjustSdkIm.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = AdjustSdkIm.framework; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -1152,8 +1155,6 @@ 9648C5E51CD1765E00A3B049 /* WebViewJavascriptBridge */ = { isa = PBXGroup; children = ( - 6FA69FD52101E00100FCD3B5 /* AdjustBridge_JS.h */, - 6FA69FD62101E00100FCD3B5 /* AdjustBridge_JS.m */, 9648C5E61CD1765E00A3B049 /* WebViewJavascriptBridge.h */, 9648C5E71CD1765E00A3B049 /* WebViewJavascriptBridge.m */, 9648C5E81CD1765E00A3B049 /* WebViewJavascriptBridge_JS.h */, @@ -1441,6 +1442,7 @@ 9D449DC51E6ED24000E7E80B /* AdjustExample-tvOS.xcodeproj */, 9D449DB31E6ED23400E7E80B /* AdjustExample-iWatch.xcodeproj */, 9D0167FE20FF88DE0029CFFF /* AdjustExample-iMessage.xcodeproj */, + 9D9D154D212EB3D00081445E /* AdjustExample-FbPixel.xcodeproj */, ); name = "Example Apps"; sourceTree = ""; @@ -1511,6 +1513,14 @@ name = "Supporting Files"; sourceTree = ""; }; + 9D9D154E212EB3D00081445E /* Products */ = { + isa = PBXGroup; + children = ( + 9D9D1552212EB3D00081445E /* AdjustExample-FbPixel.app */, + ); + name = Products; + sourceTree = ""; + }; 9DE354D32100726300D211C9 /* AdjustSdkIm */ = { isa = PBXGroup; children = ( @@ -1830,7 +1840,6 @@ 9D0E2E06210B570600133B4F /* AdjustSdkWebBridge.h in Headers */, 9D0E2EBA210B575600133B4F /* AdjustBridge.h in Headers */, 9D0E2EAF210B575600133B4F /* AdjustBridgeRegister.h in Headers */, - 9D0E2EB6210B575600133B4F /* AdjustBridge_JS.h in Headers */, 9D0E2EB8210B575600133B4F /* WebViewJavascriptBridge.h in Headers */, 9D0E2EB9210B575600133B4F /* WKWebViewJavascriptBridge.h in Headers */, 9D0E2EB4210B575600133B4F /* WebViewJavascriptBridge_JS.h in Headers */, @@ -2191,6 +2200,10 @@ productRefGroup = 9679920E18BBAE2800394606 /* Products */; projectDirPath = ""; projectReferences = ( + { + ProductGroup = 9D9D154E212EB3D00081445E /* Products */; + ProjectRef = 9D9D154D212EB3D00081445E /* AdjustExample-FbPixel.xcodeproj */; + }, { ProductGroup = 9D0167FF20FF88DE0029CFFF /* Products */; ProjectRef = 9D0167FE20FF88DE0029CFFF /* AdjustExample-iMessage.xcodeproj */; @@ -2317,6 +2330,13 @@ remoteRef = 9D449DCF1E6ED24400E7E80B /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; + 9D9D1552212EB3D00081445E /* AdjustExample-FbPixel.app */ = { + isa = PBXReferenceProxy; + fileType = wrapper.application; + path = "AdjustExample-FbPixel.app"; + remoteRef = 9D9D1551212EB3D00081445E /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; /* End PBXReferenceProxy section */ /* Begin PBXResourcesBuildPhase section */ @@ -2402,7 +2422,6 @@ 961515A31CD2CB9D0022D336 /* WebViewJavascriptBridge.m in Sources */, 961515A41CD2CBA20022D336 /* WebViewJavascriptBridge_JS.m in Sources */, 961515A61CD2CBAC0022D336 /* WKWebViewJavascriptBridge.m in Sources */, - 6FA69FD72101E00100FCD3B5 /* AdjustBridge_JS.m in Sources */, 961515A51CD2CBA80022D336 /* WebViewJavascriptBridgeBase.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -2512,7 +2531,6 @@ 9D0E2E6D210B575600133B4F /* ADJTimerOnce.m in Sources */, 9D0E2E77210B575600133B4F /* ADJEvent.m in Sources */, 9D0E2E8D210B575600133B4F /* ADJConfig.m in Sources */, - 9D0E2EB1210B575600133B4F /* AdjustBridge_JS.m in Sources */, 9D0E2E6E210B575600133B4F /* ADJAttributionHandler.m in Sources */, 9D0E2E87210B575600133B4F /* ADJBackoffStrategy.m in Sources */, 9D0E2EBB210B575600133B4F /* AdjustBridgeRegister.m in Sources */, diff --git a/Adjust/ADJActivityHandler.m b/Adjust/ADJActivityHandler.m index c54f58dcc..74928403b 100644 --- a/Adjust/ADJActivityHandler.m +++ b/Adjust/ADJActivityHandler.m @@ -1014,6 +1014,11 @@ - (void)launchSessionResponseTasksI:(ADJActivityHandler *)selfI withObject:sessionResponseData.attribution]; } + // if attribution didn't update and it's still null -> ask for attribution + if (selfI.attribution == nil && selfI.activityState.askingAttribution == NO) { + [selfI.attributionHandler getAttribution]; + } + selfI.internalState.sessionResponseProcessed = YES; } diff --git a/Adjust/ADJActivityPackage.m b/Adjust/ADJActivityPackage.m index 0fb097f47..6231e28ab 100644 --- a/Adjust/ADJActivityPackage.m +++ b/Adjust/ADJActivityPackage.m @@ -15,7 +15,7 @@ @implementation ADJActivityPackage - (NSString *)extendedString { NSMutableString *builder = [NSMutableString string]; - NSArray *excludedKeys = @[@"secret_id", @"app_secret"]; + NSArray *excludedKeys = @[@"secret_id", @"app_secret", @"event_callback_id"]; [builder appendFormat:@"Path: %@\n", self.path]; [builder appendFormat:@"ClientSdk: %@\n", self.clientSdk]; diff --git a/Adjust/ADJEvent.h b/Adjust/ADJEvent.h index d26247fb6..a2363c228 100644 --- a/Adjust/ADJEvent.h +++ b/Adjust/ADJEvent.h @@ -28,6 +28,11 @@ */ @property (nonatomic, copy, readonly, nonnull) NSString *transactionId; +/** + * @brief Custom user defined event ID. + */ +@property (nonatomic, copy, readonly, nonnull) NSString *callbackId; + /** * @brief Currency value. */ @@ -106,6 +111,14 @@ */ - (void)setTransactionId:(nonnull NSString *)transactionId; +/** + * @brief Set the custom user defined ID for the event which will be reported in + * success/failure callbacks. + * + * @param callbackId Custom user defined identifier for the event + */ +- (void)setCallbackId:(nonnull NSString *)callbackId; + /** * @brief Check if created adjust event object is valid. * diff --git a/Adjust/ADJEvent.m b/Adjust/ADJEvent.m index 3b585b184..99c358de1 100644 --- a/Adjust/ADJEvent.m +++ b/Adjust/ADJEvent.m @@ -93,6 +93,10 @@ - (void) setTransactionId:(NSString *)transactionId { _transactionId = transactionId; } +- (void)setCallbackId:(NSString *)callbackId { + _callbackId = callbackId; +} + - (NSDictionary *) callbackParameters { return (NSDictionary *) self.callbackMutableParameters; } diff --git a/Adjust/ADJEventFailure.h b/Adjust/ADJEventFailure.h index c3be34b17..ff272bbc1 100644 --- a/Adjust/ADJEventFailure.h +++ b/Adjust/ADJEventFailure.h @@ -30,6 +30,11 @@ */ @property (nonatomic, copy) NSString * eventToken; +/** + * @brief Event callback ID. + */ +@property (nonatomic, copy) NSString *callbackId; + /** * @brief Information whether sending of the package will be retried or not. */ diff --git a/Adjust/ADJEventFailure.m b/Adjust/ADJEventFailure.m index 6addc4e9f..bf35abf60 100644 --- a/Adjust/ADJEventFailure.m +++ b/Adjust/ADJEventFailure.m @@ -36,6 +36,7 @@ - (id)copyWithZone:(NSZone *)zone { copy.timeStamp = [self.timeStamp copyWithZone:zone]; copy.adid = [self.adid copyWithZone:zone]; copy.eventToken = [self.eventToken copyWithZone:zone]; + copy.callbackId = [self.callbackId copyWithZone:zone]; copy.willRetry = self.willRetry; copy.jsonResponse = [self.jsonResponse copyWithZone:zone]; } @@ -46,11 +47,12 @@ - (id)copyWithZone:(NSZone *)zone { #pragma mark - NSObject protocol methods - (NSString *)description { - return [NSString stringWithFormat: @"Event Failure msg:%@ time:%@ adid:%@ event:%@ retry:%@ json:%@", + return [NSString stringWithFormat: @"Event Failure msg:%@ time:%@ adid:%@ event:%@ cid:%@, retry:%@ json:%@", self.message, self.timeStamp, self.adid, self.eventToken, + self.callbackId, self.willRetry ? @"YES" : @"NO", self.jsonResponse]; } diff --git a/Adjust/ADJEventSuccess.h b/Adjust/ADJEventSuccess.h index e6d578f71..34214e21c 100644 --- a/Adjust/ADJEventSuccess.h +++ b/Adjust/ADJEventSuccess.h @@ -30,6 +30,11 @@ */ @property (nonatomic, copy) NSString *eventToken; +/** + * @brief Event callback ID. + */ +@property (nonatomic, copy) NSString *callbackId; + /** * @brief Backend response in JSON format. */ diff --git a/Adjust/ADJEventSuccess.m b/Adjust/ADJEventSuccess.m index e0c924a7e..1a40be353 100644 --- a/Adjust/ADJEventSuccess.m +++ b/Adjust/ADJEventSuccess.m @@ -36,6 +36,7 @@ - (id)copyWithZone:(NSZone *)zone { copy.timeStamp = [self.timeStamp copyWithZone:zone]; copy.adid = [self.adid copyWithZone:zone]; copy.eventToken = [self.eventToken copyWithZone:zone]; + copy.callbackId = [self.callbackId copyWithZone:zone]; copy.jsonResponse = [self.jsonResponse copyWithZone:zone]; } @@ -45,11 +46,12 @@ - (id)copyWithZone:(NSZone *)zone { #pragma mark - NSObject protocol methods - (NSString *)description { - return [NSString stringWithFormat: @"Event Success msg:%@ time:%@ adid:%@ event:%@ json:%@", + return [NSString stringWithFormat: @"Event Success msg:%@ time:%@ adid:%@ event:%@ cid:%@ json:%@", self.message, self.timeStamp, self.adid, self.eventToken, + self.callbackId, self.jsonResponse]; } diff --git a/Adjust/ADJPackageBuilder.m b/Adjust/ADJPackageBuilder.m index c34d9a076..8c2c45e35 100644 --- a/Adjust/ADJPackageBuilder.m +++ b/Adjust/ADJPackageBuilder.m @@ -75,6 +75,7 @@ - (ADJActivityPackage *)buildEventPackage:(ADJEvent *)event [ADJPackageBuilder parameters:parameters setNumber:event.revenue forKey:@"revenue"]; [ADJPackageBuilder parameters:parameters setString:event.currency forKey:@"currency"]; [ADJPackageBuilder parameters:parameters setString:event.eventToken forKey:@"event_token"]; + [ADJPackageBuilder parameters:parameters setString:event.callbackId forKey:@"event_callback_id"]; if (!isInDelay) { NSDictionary *mergedCallbackParameters = [ADJUtil mergeParameters:self.sessionParameters.callbackParameters diff --git a/Adjust/ADJResponseData.h b/Adjust/ADJResponseData.h index edf0f6f6a..57b209398 100644 --- a/Adjust/ADJResponseData.h +++ b/Adjust/ADJResponseData.h @@ -62,6 +62,8 @@ typedef NS_ENUM(int, ADJTrackingState) { @property (nonatomic, copy) NSString *eventToken; +@property (nonatomic, copy) NSString *callbackId; + - (ADJEventSuccess *)successResponseData; - (ADJEventFailure *)failureResponseData; diff --git a/Adjust/ADJResponseData.m b/Adjust/ADJResponseData.m index a929a6095..986043723 100644 --- a/Adjust/ADJResponseData.m +++ b/Adjust/ADJResponseData.m @@ -145,6 +145,7 @@ - (id)initWithActivityPackage:(ADJActivityPackage *)activityPackage { } self.eventToken = [activityPackage.parameters objectForKey:@"event_token"]; + self.callbackId = [activityPackage.parameters objectForKey:@"event_callback_id"]; return self; } @@ -156,6 +157,7 @@ - (ADJEventSuccess *)successResponseData { successResponseData.timeStamp = self.timeStamp; successResponseData.adid = self.adid; successResponseData.eventToken = self.eventToken; + successResponseData.callbackId = self.callbackId; successResponseData.jsonResponse = self.jsonResponse; return successResponseData; @@ -168,6 +170,7 @@ - (ADJEventFailure *)failureResponseData { failureResponseData.timeStamp = self.timeStamp; failureResponseData.adid = self.adid; failureResponseData.eventToken = self.eventToken; + failureResponseData.callbackId = self.callbackId; failureResponseData.willRetry = self.willRetry; failureResponseData.jsonResponse = self.jsonResponse; diff --git a/Adjust/ADJUtil.h b/Adjust/ADJUtil.h index 74abbf764..784e86f71 100644 --- a/Adjust/ADJUtil.h +++ b/Adjust/ADJUtil.h @@ -112,8 +112,6 @@ typedef void (^isInactiveInjected)(BOOL); + (NSNumber *)readReachabilityFlags; -+ (NSString *)extractAppSecret:(ADJActivityPackage *)activityPackage; - #if !TARGET_OS_TV + (NSString *)readMCC; diff --git a/Adjust/ADJUtil.m b/Adjust/ADJUtil.m index 4139abd19..00a58f80a 100644 --- a/Adjust/ADJUtil.m +++ b/Adjust/ADJUtil.m @@ -1,24 +1,23 @@ // // ADJUtil.m -// Adjust +// Adjust SDK // -// Created by Christian Wellenbrock on 2013-07-05. -// Copyright (c) 2013 adjust GmbH. All rights reserved. +// Created by Christian Wellenbrock (@wellle) on 5th July 2013. +// Copyright (c) 2013-2018 Adjust GmbH. All rights reserved. // #include #include #include - #import #import "ADJUtil.h" #import "ADJLogger.h" +#import "ADJReachability.h" #import "ADJResponseData.h" #import "ADJAdjustFactory.h" #import "UIDevice+ADJAdditions.h" #import "NSString+ADJAdditions.h" -#import "ADJReachability.h" #if !TARGET_OS_TV #import @@ -27,21 +26,20 @@ static const double kRequestTimeout = 60; // 60 seconds +static NSString *userAgent = nil; +static ADJReachability *reachability = nil; static NSRegularExpression *universalLinkRegex = nil; static NSNumberFormatter *secondsNumberFormatter = nil; static NSRegularExpression *optionalRedirectRegex = nil; static NSRegularExpression *shortUniversalLinkRegex = nil; static NSURLSessionConfiguration *urlSessionConfiguration = nil; -static ADJReachability *reachability = nil; #if !TARGET_OS_TV -static CTTelephonyNetworkInfo *networkInfo = nil; static CTCarrier *carrier = nil; +static CTTelephonyNetworkInfo *networkInfo = nil; #endif -static NSString *userAgent = nil; - -static NSString * const kClientSdk = @"ios4.14.3"; +static NSString * const kClientSdk = @"ios4.15.0"; static NSString * const kDeeplinkParam = @"deep_link="; static NSString * const kSchemeDelimiter = @"://"; static NSString * const kDefaultScheme = @"AdjustUniversalScheme"; @@ -69,12 +67,12 @@ + (void)initialize { } + (void)teardown { + reachability = nil; universalLinkRegex = nil; secondsNumberFormatter = nil; - optionalRedirectRegex = nil; + optionalRedirectRegex = nil; shortUniversalLinkRegex = nil; urlSessionConfiguration = nil; - reachability = nil; #if !TARGET_OS_TV networkInfo = nil; carrier = nil; @@ -84,46 +82,37 @@ + (void)teardown { + (void)initializeUniversalLinkRegex { NSError *error = NULL; - NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:kUniversalLinkPattern options:NSRegularExpressionCaseInsensitive error:&error]; - if ([ADJUtil isNotNull:error]) { [ADJAdjustFactory.logger error:@"Universal link regex rule error (%@)", [error description]]; return; } - universalLinkRegex = regex; } + (void)initializeShortUniversalLinkRegex { NSError *error = NULL; - NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:kShortUniversalLinkPattern options:NSRegularExpressionCaseInsensitive error:&error]; - if ([ADJUtil isNotNull:error]) { [ADJAdjustFactory.logger error:@"Short Universal link regex rule error (%@)", [error description]]; return; } - shortUniversalLinkRegex = regex; } + (void)initializeOptionalRedirectRegex { NSError *error = NULL; - NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:kOptionalRedirectPattern options:NSRegularExpressionCaseInsensitive error:&error]; - if ([ADJUtil isNotNull:error]) { [ADJAdjustFactory.logger error:@"Optional redirect regex rule error (%@)", [error description]]; return; } - optionalRedirectRegex = regex; } @@ -166,11 +155,9 @@ + (NSString *)clientSdk { + (NSDateFormatter *)getDateFormatter { NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; - if ([NSCalendar instancesRespondToSelector:@selector(calendarWithIdentifier:)]) { // http://stackoverflow.com/a/3339787 NSString *calendarIdentifier; - #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wtautological-pointer-compare" if (&NSCalendarIdentifierGregorian != NULL) { @@ -183,10 +170,8 @@ + (NSDateFormatter *)getDateFormatter { calendarIdentifier = NSGregorianCalendar; #pragma clang diagnostic pop } - dateFormatter.calendar = [NSCalendar calendarWithIdentifier:calendarIdentifier]; } - dateFormatter.locale = [NSLocale systemLocale]; [dateFormatter setDateFormat:kDateFormat]; @@ -206,18 +191,15 @@ + (void)excludeFromBackup:(NSString *)path { if (&NSURLIsExcludedFromBackupKey == nil) { u_int8_t attrValue = 1; int result = setxattr(filePath, attrName, &attrValue, sizeof(attrValue), 0, 0); - if (result != 0) { [logger debug:@"Failed to exclude '%@' from backup", url.lastPathComponent]; } } else { // iOS 5.0 and higher // First try and remove the extended attribute if it is present ssize_t result = getxattr(filePath, attrName, NULL, sizeof(u_int8_t), 0, 0); - if (result != -1) { // The attribute exists, we need to remove it int removeResult = removexattr(filePath, attrName, 0); - if (removeResult == 0) { [logger debug:@"Removed extended attribute on file '%@'", url]; } @@ -228,7 +210,6 @@ + (void)excludeFromBackup:(NSString *)path { BOOL success = [url setResourceValue:[NSNumber numberWithBool:YES] forKey:NSURLIsExcludedFromBackupKey error:&error]; - if (!success || error != nil) { [logger debug:@"Failed to exclude '%@' from backup (%@)", url.lastPathComponent, error.localizedDescription]; } @@ -243,11 +224,9 @@ + (NSString *)formatSeconds1970:(double)value { + (NSString *)formatDate:(NSDate *)value { NSDateFormatter *dateFormatter = [ADJUtil getDateFormatter]; - if (dateFormatter == nil) { return nil; } - return [dateFormatter stringFromDate:value]; } @@ -258,19 +237,14 @@ + (void)saveJsonResponse:(NSData *)jsonData responseData:(ADJResponseData *)resp if (exception != nil) { NSString *message = [NSString stringWithFormat:@"Failed to parse json response. (%@)", exception.description]; - [ADJAdjustFactory.logger error:message]; responseData.message = message; - return; } - if (error != nil) { NSString *message = [NSString stringWithFormat:@"Failed to parse json response. (%@)", error.localizedDescription]; - [ADJAdjustFactory.logger error:message]; responseData.message = message; - return; } @@ -285,14 +259,12 @@ + (NSDictionary *)buildJsonDict:(NSData *)jsonData } NSDictionary *jsonDict = nil; - @try { jsonDict = [NSJSONSerialization JSONObjectWithData:jsonData options:0 error:error]; } @catch (NSException *ex) { *exceptionPtr = ex; return nil; } - return jsonDict; } @@ -305,19 +277,15 @@ + (id)readObject:(NSString *)fileName @try { id appSupportObject = [NSKeyedUnarchiver unarchiveObjectWithFile:appSupportFilePath]; - if ([appSupportObject isKindOfClass:classToRead]) { // Successfully read object from Application Support folder, return it. - if ([appSupportObject isKindOfClass:[NSArray class]]) { [[ADJAdjustFactory logger] debug:@"Package handler read %d packages", [appSupportObject count]]; } else { [[ADJAdjustFactory logger] debug:@"Read %@: %@", objectName, appSupportObject]; } - // Just in case check if old file exists in Documents folder and if yes, remove it. [ADJUtil deleteFileInPath:documentsFilePath]; - return appSupportObject; } else if (appSupportObject == nil) { // [[ADJAdjustFactory logger] verbose:@"%@ file not found", appSupportFilePath]; @@ -333,23 +301,18 @@ + (id)readObject:(NSString *)fileName // If in here, for some reason, reading of file from Application Support folder failed. // Let's check the Documents folder. - @try { id documentsObject = [NSKeyedUnarchiver unarchiveObjectWithFile:documentsFilePath]; - if (documentsObject != nil) { // Successfully read object from Documents folder. - if ([documentsObject isKindOfClass:[NSArray class]]) { [[ADJAdjustFactory logger] debug:@"Package handler read %d packages", [documentsObject count]]; } else { [[ADJAdjustFactory logger] debug:@"Read %@: %@", objectName, documentsObject]; } - // Do the file migration. [[ADJAdjustFactory logger] verbose:@"Migrating %@ file from Documents to \"Application Support/Adjust\" folder", fileName]; [ADJUtil migrateFileFromPath:documentsFilePath toPath:appSupportFilePath]; - return documentsObject; } else if (documentsObject == nil) { // [[ADJAdjustFactory logger] verbose:@"%@ file not found", documentsFilePath]; @@ -362,7 +325,6 @@ + (id)readObject:(NSString *)fileName // [[ADJAdjustFactory logger] error:@"Failed to read %@ file (%@)", documentsFilePath, ex]; [[ADJAdjustFactory logger] error:@"Failed to read %@ file from Documents folder (%@)", fileName, ex]; } - return nil; } @@ -370,12 +332,9 @@ + (void)writeObject:(id)object fileName:(NSString *)fileName objectName:(NSString *)objectName { NSString *filePath = [ADJUtil getFilePathInAppSupportDir:fileName]; - BOOL result = (filePath != nil) && [NSKeyedArchiver archiveRootObject:object toFile:filePath]; - if (result == YES) { [ADJUtil excludeFromBackup:filePath]; - if ([object isKindOfClass:[NSArray class]]) { [[ADJAdjustFactory logger] debug:@"Package handler wrote %d packages", [object count]]; } else { @@ -388,72 +347,54 @@ + (void)writeObject:(id)object + (BOOL)migrateFileFromPath:(NSString *)oldPath toPath:(NSString *)newPath { NSError *errorCopy; - [[NSFileManager defaultManager] copyItemAtPath:oldPath toPath:newPath error:&errorCopy]; - if (errorCopy != nil) { [[ADJAdjustFactory logger] error:@"Error while copying from %@ to %@", oldPath, newPath]; [[ADJAdjustFactory logger] error:[errorCopy description]]; - return NO; } - // Migration successful. return YES; } + (NSString *)getFilePathInDocumentsDir:(NSString *)fileName { // Documents directory exists by default inside app bundle, no need to check for it's presence. - NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString *documentsDir = [paths objectAtIndex:0]; NSString *filePath = [documentsDir stringByAppendingPathComponent:fileName]; - return filePath; } + (NSString *)getFilePathInAppSupportDir:(NSString *)fileName { // Application Support directory doesn't exist by default inside app bundle. // All Adjust files are going to be stored in Adjust sub-directory inside Application Support directory. - NSArray *paths = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES); NSString *appSupportDir = [paths firstObject]; NSString *adjustDirName = @"Adjust"; - if (![ADJUtil checkForDirectoryPresenceInPath:appSupportDir forFolder:[appSupportDir lastPathComponent]]) { return nil; } - NSString *adjustDir = [appSupportDir stringByAppendingPathComponent:[NSString stringWithFormat:@"/%@", adjustDirName]]; - if (![ADJUtil checkForDirectoryPresenceInPath:adjustDir forFolder:adjustDirName]) { return nil; } - NSString *filePath = [adjustDir stringByAppendingPathComponent:fileName]; - return filePath; } + (BOOL)checkForDirectoryPresenceInPath:(NSString *)path forFolder:(NSString *)folderName { // Check for presence of directory first. // If it doesn't exist, make one. - if (![[NSFileManager defaultManager] fileExistsAtPath:path]) { [[ADJAdjustFactory logger] debug:@"%@ directory not present and will be created", folderName]; - NSError *error; - [[NSFileManager defaultManager] createDirectoryAtPath:path withIntermediateDirectories:NO attributes:nil error:&error]; - if (error != nil) { [[ADJAdjustFactory logger] error:@"Error while creating % directory", path]; [[ADJAdjustFactory logger] error:[error description]]; - return NO; } } - return YES; } @@ -464,13 +405,11 @@ + (NSString *)queryString:(NSDictionary *)parameters { + (NSString *)queryString:(NSDictionary *)parameters queueSize:(NSUInteger)queueSize { NSMutableArray *pairs = [NSMutableArray array]; - for (NSString *key in parameters) { NSString *value = [parameters objectForKey:key]; NSString *escapedValue = [value adjUrlEncode]; NSString *escapedKey = [key adjUrlEncode]; NSString *pair = [NSString stringWithFormat:@"%@=%@", escapedKey, escapedValue]; - [pairs addObject:pair]; } @@ -478,7 +417,6 @@ + (NSString *)queryString:(NSDictionary *)parameters NSString *dateString = [ADJUtil formatSeconds1970:now]; NSString *escapedDate = [dateString adjUrlEncode]; NSString *sentAtPair = [NSString stringWithFormat:@"%@=%@", @"sent_at", escapedDate]; - [pairs addObject:sentAtPair]; if (queueSize > 0) { @@ -486,12 +424,10 @@ + (NSString *)queryString:(NSDictionary *)parameters NSString *queueSizeString = [NSString stringWithFormat:@"%lu", queueSizeNative]; NSString *escapedQueueSize = [queueSizeString adjUrlEncode]; NSString *queueSizePair = [NSString stringWithFormat:@"%@=%@", @"queue_size", escapedQueueSize]; - [pairs addObject:queueSizePair]; } NSString *queryString = [pairs componentsJoinedByString:@"&"]; - return queryString; } @@ -507,7 +443,6 @@ + (NSString *)formatErrorMessage:(NSString *)prefixErrorMessage systemErrorMessage:(NSString *)systemErrorMessage suffixErrorMessage:(NSString *)suffixErrorMessage { NSString *errorMessage = [NSString stringWithFormat:@"%@ (%@)", prefixErrorMessage, systemErrorMessage]; - if (suffixErrorMessage == nil) { return errorMessage; } else { @@ -520,12 +455,18 @@ + (void)sendGetRequest:(NSURL *)baseUrl prefixErrorMessage:(NSString *)prefixErrorMessage activityPackage:(ADJActivityPackage *)activityPackage responseDataHandler:(void (^)(ADJResponseData *responseData))responseDataHandler { - - NSString *appSecret = [ADJUtil extractAppSecret:activityPackage]; - NSString *secretId = [ADJUtil extractSecretId:activityPackage]; - - NSMutableURLRequest *request = [ADJUtil requestForGetPackage:activityPackage baseUrl:baseUrl basePath:basePath]; - + NSMutableDictionary *parametersCopy = [[NSMutableDictionary alloc] initWithCapacity:[activityPackage.parameters count]]; + [parametersCopy addEntriesFromDictionary:activityPackage.parameters]; + + NSString *appSecret = [ADJUtil extractAppSecret:parametersCopy]; + NSString *secretId = [ADJUtil extractSecretId:parametersCopy]; + [ADJUtil extractEventCallbackId:parametersCopy]; + + NSMutableURLRequest *request = [ADJUtil requestForGetPackage:activityPackage.path + clientSdk:activityPackage.clientSdk + parameters:parametersCopy + baseUrl:baseUrl + basePath:basePath]; [ADJUtil sendRequest:request prefixErrorMessage:prefixErrorMessage activityPackage:activityPackage @@ -555,12 +496,17 @@ + (void)sendPostRequest:(NSURL *)baseUrl suffixErrorMessage:(NSString *)suffixErrorMessage activityPackage:(ADJActivityPackage *)activityPackage responseDataHandler:(void (^)(ADJResponseData *responseData))responseDataHandler { + NSMutableDictionary *parametersCopy = [[NSMutableDictionary alloc] initWithCapacity:[activityPackage.parameters count]]; + [parametersCopy addEntriesFromDictionary:activityPackage.parameters]; - NSString *appSecret = [ADJUtil extractAppSecret:activityPackage]; - NSString *secretId = [ADJUtil extractSecretId:activityPackage]; - - NSMutableURLRequest *request = [ADJUtil requestForPostPackage:activityPackage baseUrl:baseUrl queueSize:queueSize]; + NSString *appSecret = [ADJUtil extractAppSecret:parametersCopy]; + NSString *secretId = [ADJUtil extractSecretId:parametersCopy]; + [ADJUtil extractEventCallbackId:parametersCopy]; + NSMutableURLRequest *request = [ADJUtil requestForPostPackage:activityPackage.path + clientSdk:activityPackage.clientSdk + parameters:parametersCopy + baseUrl:baseUrl queueSize:queueSize]; [ADJUtil sendRequest:request prefixErrorMessage:prefixErrorMessage suffixErrorMessage:suffixErrorMessage @@ -577,15 +523,12 @@ + (void)sendRequest:(NSMutableURLRequest *)request appSecret:(NSString *)appSecret activityPackage:(ADJActivityPackage *)activityPackage responseDataHandler:(void (^)(ADJResponseData *responseData))responseDataHandler { - NSString *authHeader = [ADJUtil buildAuthorizationHeader:appSecret secretId:secretId activityPackage:activityPackage]; - if (authHeader != nil) { [request setValue:authHeader forHTTPHeaderField:@"Authorization"]; } - if (userAgent != nil) { [request setValue:userAgent forHTTPHeaderField:@"User-Agent"]; } @@ -606,66 +549,68 @@ + (void)sendRequest:(NSMutableURLRequest *)request } } -+ (NSString *)extractAppSecret:(ADJActivityPackage *)activityPackage { - NSString *appSecret = [activityPackage.parameters objectForKey:@"app_secret"]; - ++ (NSString *)extractAppSecret:(NSMutableDictionary *)parameters { + NSString *appSecret = [parameters objectForKey:@"app_secret"]; if (appSecret == nil) { return nil; } - - [activityPackage.parameters removeObjectForKey:@"app_secret"]; - + [parameters removeObjectForKey:@"app_secret"]; return appSecret; } -+ (NSString *)extractSecretId:(ADJActivityPackage *)activityPackage { - NSString *appSecret = [activityPackage.parameters objectForKey:@"secret_id"]; - ++ (NSString *)extractSecretId:(NSMutableDictionary *)parameters { + NSString *appSecret = [parameters objectForKey:@"secret_id"]; if (appSecret == nil) { return nil; } - - [activityPackage.parameters removeObjectForKey:@"secret_id"]; - + [parameters removeObjectForKey:@"secret_id"]; return appSecret; } -+ (NSMutableURLRequest *)requestForGetPackage:(ADJActivityPackage *)activityPackage ++ (void)extractEventCallbackId:(NSMutableDictionary *)parameters { + NSString *eventCallbackId = [parameters objectForKey:@"event_callback_id"]; + if (eventCallbackId == nil) { + return; + } + [parameters removeObjectForKey:@"event_callback_id"]; +} + ++ (NSMutableURLRequest *)requestForGetPackage:(NSString *)path + clientSdk:(NSString *)clientSdk + parameters:(NSDictionary *)parameters baseUrl:(NSURL *)baseUrl - basePath:(NSString *)basePath -{ - NSString *parameters = [ADJUtil queryString:activityPackage.parameters]; + basePath:(NSString *)basePath { + NSString *queryStringParameters = [ADJUtil queryString:parameters]; NSString *relativePath; if (basePath != nil) { - relativePath = [NSString stringWithFormat:@"%@%@?%@", basePath, activityPackage.path, parameters]; + relativePath = [NSString stringWithFormat:@"%@%@?%@", basePath, path, queryStringParameters]; } else { - relativePath = [NSString stringWithFormat:@"%@?%@", activityPackage.path, parameters]; + relativePath = [NSString stringWithFormat:@"%@?%@", path, queryStringParameters]; } - NSURL *url = [NSURL URLWithString:relativePath relativeToURL:baseUrl]; + NSURL *url = [NSURL URLWithString:relativePath relativeToURL:baseUrl]; NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; request.timeoutInterval = kRequestTimeout; request.HTTPMethod = @"GET"; - - [request setValue:activityPackage.clientSdk forHTTPHeaderField:@"Client-Sdk"]; - + [request setValue:clientSdk forHTTPHeaderField:@"Client-Sdk"]; return request; } -+ (NSMutableURLRequest *)requestForPostPackage:(ADJActivityPackage *)activityPackage ++ (NSMutableURLRequest *)requestForPostPackage:(NSString *)path + clientSdk:(NSString *)clientSdk + parameters:(NSDictionary *)parameters baseUrl:(NSURL *)baseUrl queueSize:(NSUInteger)queueSize { - NSURL *url = [baseUrl URLByAppendingPathComponent:activityPackage.path]; + NSURL *url = [baseUrl URLByAppendingPathComponent:path]; NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; request.timeoutInterval = kRequestTimeout; request.HTTPMethod = @"POST"; [request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"]; - [request setValue:activityPackage.clientSdk forHTTPHeaderField:@"Client-Sdk"]; + [request setValue:clientSdk forHTTPHeaderField:@"Client-Sdk"]; - NSString *bodyString = [ADJUtil queryString:activityPackage.parameters queueSize:queueSize]; + NSString *bodyString = [ADJUtil queryString:parameters queueSize:queueSize]; NSData *body = [NSData dataWithBytes:bodyString.UTF8String length:bodyString.length]; [request setHTTPBody:body]; - return request; } @@ -678,31 +623,25 @@ + (NSString *)buildAuthorizationHeader:(NSString *)appSecret NSMutableDictionary *parameters = activityPackage.parameters; NSString *activityKindS = [ADJActivityKindUtil activityKindToString:activityPackage.activityKind]; - - NSDictionary *signatureParameters = [ADJUtil buildSignatureParameters:parameters appSecret:appSecret activityKindS:activityKindS]; - NSMutableString *fields = [[NSMutableString alloc] initWithCapacity:5]; NSMutableString *clearSignature = [[NSMutableString alloc] initWithCapacity:5]; // signature part of header for (NSDictionary *key in signatureParameters) { [fields appendFormat:@"%@ ", key]; - NSString *value = [signatureParameters objectForKey:key]; [clearSignature appendString:value]; } - NSString * secretIdHeader = [NSString stringWithFormat:@"secret_id=\"%@\"", secretId]; - + NSString *secretIdHeader = [NSString stringWithFormat:@"secret_id=\"%@\"", secretId]; // algorithm part of header - NSString * algorithm = @"sha256"; - NSString * signature = [clearSignature adjSha256]; - NSString * signatureHeader = [NSString stringWithFormat:@"signature=\"%@\"", signature]; - - NSString * algorithmHeader = [NSString stringWithFormat:@"algorithm=\"%@\"", algorithm]; + NSString *algorithm = @"sha256"; + NSString *signature = [clearSignature adjSha256]; + NSString *signatureHeader = [NSString stringWithFormat:@"signature=\"%@\"", signature]; + NSString *algorithmHeader = [NSString stringWithFormat:@"algorithm=\"%@\"", algorithm]; // fields part of header // Remove last empty space. if (fields.length > 0) { @@ -710,13 +649,13 @@ + (NSString *)buildAuthorizationHeader:(NSString *)appSecret } NSString *fieldsHeader = [NSString stringWithFormat:@"headers=\"%@\"", fields]; - // putting it all together - NSString *authorizationHeader = [NSString stringWithFormat:@"Signature %@,%@,%@,%@", secretIdHeader, signatureHeader, algorithmHeader, fieldsHeader]; - + NSString *authorizationHeader = [NSString stringWithFormat:@"Signature %@,%@,%@,%@", + secretIdHeader, + signatureHeader, + algorithmHeader, + fieldsHeader]; [ADJAdjustFactory.logger debug:@"authorizationHeader %@", authorizationHeader]; - - return authorizationHeader; } @@ -725,20 +664,16 @@ + (NSDictionary *)buildSignatureParameters:(NSMutableDictionary *)parameters activityKindS:(NSString *)activityKindS { NSString *activityKindName = @"activity_kind"; NSString *activityKindValue = activityKindS; - NSString *createdAtName = @"created_at"; NSString *createdAtValue = [parameters objectForKey:createdAtName]; - NSString *deviceIdentifierName = [ADJUtil getValidIdentifier:parameters]; NSString *deviceIdentifierValue = [parameters objectForKey:deviceIdentifierName]; - NSMutableDictionary *signatureParameters = [[NSMutableDictionary alloc] initWithCapacity:4]; [ADJUtil checkAndAddEntry:signatureParameters key:@"app_secret" value:appSecret]; [ADJUtil checkAndAddEntry:signatureParameters key:createdAtName value:createdAtValue]; [ADJUtil checkAndAddEntry:signatureParameters key:activityKindName value:activityKindValue]; [ADJUtil checkAndAddEntry:signatureParameters key:deviceIdentifierName value:deviceIdentifierValue]; - return signatureParameters; } @@ -764,15 +699,12 @@ + (NSString *)getValidIdentifier:(NSMutableDictionary *)parameters { if ([parameters objectForKey:idfaName] != nil) { return idfaName; } - if ([parameters objectForKey:persistentUUIDName] != nil) { return persistentUUIDName; } - if ([parameters objectForKey:uuidName] != nil) { return uuidName; } - return nil; } @@ -782,7 +714,6 @@ + (void)sendNSURLSessionRequest:(NSMutableURLRequest *)request activityPackage:(ADJActivityPackage *)activityPackage responseDataHandler:(void (^)(ADJResponseData *responseData))responseDataHandler { NSURLSession *session = [NSURLSession sessionWithConfiguration:[ADJUtil getUrlSessionConfiguration]]; - NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler: ^(NSData *data, NSURLResponse *response, NSError *error) { @@ -792,10 +723,8 @@ + (void)sendNSURLSessionRequest:(NSMutableURLRequest *)request prefixErrorMessage:prefixErrorMessage suffixErrorMessage:suffixErrorMessage activityPackage:activityPackage]; - responseDataHandler(responseData); }]; - [task resume]; [session finishTasksAndInvalidate]; } @@ -807,21 +736,18 @@ + (void)sendNSURLConnectionRequest:(NSMutableURLRequest *)request responseDataHandler:(void (^)(ADJResponseData *responseData))responseDataHandler { NSError *responseError = nil; NSHTTPURLResponse *urlResponse = nil; - #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wdeprecated-declarations" NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&urlResponse error:&responseError]; #pragma clang diagnostic pop - ADJResponseData *responseData = [ADJUtil completionHandler:data response:(NSHTTPURLResponse *)urlResponse error:responseError prefixErrorMessage:prefixErrorMessage suffixErrorMessage:suffixErrorMessage activityPackage:activityPackage]; - responseDataHandler(responseData); } @@ -832,51 +758,41 @@ + (ADJResponseData *)completionHandler:(NSData *)data suffixErrorMessage:(NSString *)suffixErrorMessage activityPackage:(ADJActivityPackage *)activityPackage { ADJResponseData *responseData = [ADJResponseData buildResponseData:activityPackage]; - // Connection error if (responseError != nil) { NSString *errorMessage = [ADJUtil formatErrorMessage:prefixErrorMessage systemErrorMessage:responseError.localizedDescription suffixErrorMessage:suffixErrorMessage]; - [ADJAdjustFactory.logger error:errorMessage]; responseData.message = errorMessage; - return responseData; } - if ([ADJUtil isNull:data]) { NSString *errorMessage = [ADJUtil formatErrorMessage:prefixErrorMessage systemErrorMessage:@"empty error" suffixErrorMessage:suffixErrorMessage]; - [ADJAdjustFactory.logger error:errorMessage]; responseData.message = errorMessage; - return responseData; } NSString *responseString = [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] adjTrim]; NSInteger statusCode = urlResponse.statusCode; - [ADJAdjustFactory.logger verbose:@"Response: %@", responseString]; if (statusCode == 429) { [ADJAdjustFactory.logger error:@"Too frequent requests to the endpoint (429)"]; return responseData; } - [ADJUtil saveJsonResponse:data responseData:responseData]; - if ([ADJUtil isNull:responseData.jsonResponse]) { return responseData; } NSString *messageResponse = [responseData.jsonResponse objectForKey:@"message"]; - - responseData.message = messageResponse; - responseData.timeStamp = [responseData.jsonResponse objectForKey:@"timestamp"]; - responseData.adid = [responseData.jsonResponse objectForKey:@"adid"]; + responseData.message = messageResponse; + responseData.timeStamp = [responseData.jsonResponse objectForKey:@"timestamp"]; + responseData.adid = [responseData.jsonResponse objectForKey:@"adid"]; NSString *trackingState = [responseData.jsonResponse objectForKey:@"tracking_state"]; if (trackingState != nil) { @@ -884,28 +800,23 @@ + (ADJResponseData *)completionHandler:(NSData *)data responseData.trackingState = ADJTrackingStateOptedOut; } } - if (messageResponse == nil) { messageResponse = @"No message found"; } - if (statusCode == 200) { [ADJAdjustFactory.logger info:@"%@", messageResponse]; responseData.success = YES; } else { [ADJAdjustFactory.logger error:@"%@", messageResponse]; } - return responseData; } // Convert all values to strings, if value is dictionary -> recursive call + (NSDictionary *)convertDictionaryValues:(NSDictionary *)dictionary { NSMutableDictionary *convertedDictionary = [[NSMutableDictionary alloc] initWithCapacity:dictionary.count]; - for (NSString *key in dictionary) { id value = [dictionary objectForKey:key]; - if ([value isKindOfClass:[NSDictionary class]]) { // Dictionary value, recursive call NSDictionary *dictionaryValue = [ADJUtil convertDictionaryValues:(NSDictionary *)value]; @@ -922,7 +833,6 @@ + (NSDictionary *)convertDictionaryValues:(NSDictionary *)dictionary { [convertedDictionary setObject:stringValue forKey:key]; } } - return convertedDictionary; } @@ -933,7 +843,6 @@ + (NSString *)idfa { + (NSString *)getUpdateTime { NSDate *updateTime = nil; id logger = ADJAdjustFactory.logger; - @try { __autoreleasing NSError *error; NSString *infoPlistPath = [[NSBundle mainBundle] pathForResource:@"Info" ofType:@"plist"]; @@ -941,23 +850,19 @@ + (NSString *)getUpdateTime { } @catch (NSException *exception) { [logger error:@"Error while trying to check update date. Exception: %@", exception]; } - return [ADJUtil formatDate:updateTime]; } + (NSString *)getInstallTime { id logger = ADJAdjustFactory.logger; - NSDate *installTime = nil; NSString *pathToCheck = nil; NSSearchPathDirectory folderToCheck = NSDocumentDirectory; #if TARGET_OS_TV folderToCheck = NSCachesDirectory; #endif - @try { NSArray *paths = NSSearchPathForDirectoriesInDomains(folderToCheck, NSUserDomainMask, YES); - if (paths.count > 0) { pathToCheck = [paths objectAtIndex:0]; } else { @@ -965,12 +870,10 @@ + (NSString *)getInstallTime { // Check app's bundle creation date instead. pathToCheck = [[NSBundle mainBundle] bundlePath]; } - installTime = [[NSFileManager defaultManager] attributesOfItemAtPath:pathToCheck error:nil][NSFileCreationDate]; } @catch (NSException *exception) { [logger error:@"Error while trying to check install date. Exception: %@", exception]; } - return [ADJUtil formatDate:installTime]; } @@ -981,47 +884,38 @@ + (NSURL *)convertUniversalLink:(NSURL *)url scheme:(NSString *)scheme { [logger error:@"Received universal link is nil"]; return nil; } - if ([ADJUtil isNull:scheme] || [scheme length] == 0) { [logger warn:@"Non-empty scheme required, using the scheme \"AdjustUniversalScheme\""]; scheme = kDefaultScheme; } - NSString *urlString = [url absoluteString]; - if ([ADJUtil isNull:urlString]) { [logger error:@"Parsed universal link is nil"]; return nil; } - if (universalLinkRegex == nil) { [logger error:@"Universal link regex not correctly configured"]; return nil; } - if (shortUniversalLinkRegex == nil) { [logger error:@"Short Universal link regex not correctly configured"]; return nil; } NSArray *matches = [universalLinkRegex matchesInString:urlString options:0 range:NSMakeRange(0, [urlString length])]; - if ([matches count] == 0) { matches = [shortUniversalLinkRegex matchesInString:urlString options:0 range:NSMakeRange(0, [urlString length])]; - if ([matches count] == 0) { [logger error:@"Url doesn't match as universal link or short version"]; return nil; } } - if ([matches count] > 1) { [logger error:@"Url match as universal link multiple times"]; return nil; } NSTextCheckingResult *match = matches[0]; - if ([match numberOfRanges] != 2) { [logger error:@"Wrong number of ranges matched"]; return nil; @@ -1030,16 +924,12 @@ + (NSURL *)convertUniversalLink:(NSURL *)url scheme:(NSString *)scheme { NSString *tailSubString = [urlString substringWithRange:[match rangeAtIndex:1]]; NSString *finalTailSubString = [ADJUtil removeOptionalRedirect:tailSubString]; NSString *extractedUrlString = [NSString stringWithFormat:@"%@://%@", scheme, finalTailSubString]; - [logger info:@"Converted deeplink from universal link %@", extractedUrlString]; - NSURL *extractedUrl = [NSURL URLWithString:extractedUrlString]; - if ([ADJUtil isNull:extractedUrl]) { [logger error:@"Unable to parse converted deeplink from universal link %@", extractedUrlString]; return nil; } - return extractedUrl; } @@ -1050,16 +940,13 @@ + (NSString *)removeOptionalRedirect:(NSString *)tailSubString { [ADJAdjustFactory.logger error:@"Remove Optional Redirect regex not correctly configured"]; return tailSubString; } - NSArray *optionalRedirectmatches = [optionalRedirectRegex matchesInString:tailSubString options:0 range:NSMakeRange(0, [tailSubString length])]; - if ([optionalRedirectmatches count] == 0) { [logger debug:@"Universal link does not contain option adjust_redirect parameter"]; return tailSubString; } - if ([optionalRedirectmatches count] > 1) { [logger error:@"Universal link contains multiple option adjust_redirect parameters"]; return tailSubString; @@ -1067,38 +954,30 @@ + (NSString *)removeOptionalRedirect:(NSString *)tailSubString { NSTextCheckingResult *redirectMatch = optionalRedirectmatches[0]; NSRange redirectRange = [redirectMatch rangeAtIndex:0]; - NSString *beforeRedirect = [tailSubString substringToIndex:redirectRange.location]; NSString *afterRedirect = [tailSubString substringFromIndex:(redirectRange.location + redirectRange.length)]; - if (beforeRedirect.length > 0 && afterRedirect.length > 0) { NSString *lastCharacterBeforeRedirect = [beforeRedirect substringFromIndex:beforeRedirect.length - 1]; NSString *firstCharacterAfterRedirect = [afterRedirect substringToIndex:1]; - if ([@"&" isEqualToString:lastCharacterBeforeRedirect] && [@"&" isEqualToString:firstCharacterAfterRedirect]) { beforeRedirect = [beforeRedirect substringToIndex:beforeRedirect.length - 1]; } - if ([@"&" isEqualToString:lastCharacterBeforeRedirect] && [@"#" isEqualToString:firstCharacterAfterRedirect]) { beforeRedirect = [beforeRedirect substringToIndex:beforeRedirect.length - 1]; } - if ([@"?" isEqualToString:lastCharacterBeforeRedirect] && [@"#" isEqualToString:firstCharacterAfterRedirect]) { beforeRedirect = [beforeRedirect substringToIndex:beforeRedirect.length - 1]; } - if ([@"?" isEqualToString:lastCharacterBeforeRedirect] && [@"&" isEqualToString:firstCharacterAfterRedirect]) { afterRedirect = [afterRedirect substringFromIndex:1]; } - } NSString *removedRedirect = [NSString stringWithFormat:@"%@%@", beforeRedirect, afterRedirect]; - return removedRedirect; } @@ -1107,26 +986,21 @@ + (NSString *)secondsNumberFormat:(double)seconds { if (seconds < 0) { seconds = seconds * -1; } - if (secondsNumberFormatter == nil) { return nil; } - return [secondsNumberFormatter stringFromNumber:[NSNumber numberWithDouble:seconds]]; } + (double)randomInRange:(double)minRange maxRange:(double)maxRange { static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ srand48(arc4random()); }); - double random = drand48(); double range = maxRange - minRange; double scaled = random * range; double shifted = scaled + minRange; - return shifted; } @@ -1138,19 +1012,14 @@ + (NSTimeInterval)waitingTime:(NSInteger)retries // Start with base 0 NSInteger base = retries - backoffStrategy.minRetries; - // Get the exponential Time from the base: 1, 2, 4, 8, 16, ... * times the multiplier NSTimeInterval exponentialTime = pow(2.0, base) * backoffStrategy.secondMultiplier; - // Limit the maximum allowed time to wait NSTimeInterval ceilingTime = MIN(exponentialTime, backoffStrategy.maxWait); - // Add 1 to allow maximum value double randomRange = [ADJUtil randomInRange:backoffStrategy.minRange maxRange:backoffStrategy.maxRange]; - // Apply jitter factor NSTimeInterval waitingTime = ceilingTime * randomRange; - return waitingTime; } @@ -1194,12 +1063,10 @@ + (void)launchInMainThreadWithInactive:(isInactiveInjected)isInactiveblock { __block BOOL isInactive = [ADJUtil isInactive]; isInactiveblock(isInactive); }; - if ([ADJUtil isMainThread]) { block(); return; } - if (ADJAdjustFactory.testing) { [ADJAdjustFactory.logger debug:@"Launching in the background for testing"]; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), block); @@ -1208,7 +1075,6 @@ + (void)launchInMainThreadWithInactive:(isInactiveInjected)isInactiveblock { } } - + (BOOL)isValidParameter:(NSString *)attribute attributeType:(NSString *)attributeType parameterName:(NSString *)parameterName { @@ -1216,12 +1082,10 @@ + (BOOL)isValidParameter:(NSString *)attribute [ADJAdjustFactory.logger error:@"%@ parameter %@ is missing", parameterName, attributeType]; return NO; } - if ([attribute isEqualToString:@""]) { [ADJAdjustFactory.logger error:@"%@ parameter %@ is empty", parameterName, attributeType]; return NO; } - return YES; } @@ -1231,24 +1095,19 @@ + (NSDictionary *)mergeParameters:(NSDictionary *)target if (target == nil) { return source; } - if (source == nil) { return target; } NSMutableDictionary *mergedParameters = [NSMutableDictionary dictionaryWithDictionary:target]; - [source enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSString *obj, BOOL *stop) { NSString *oldValue = [mergedParameters objectForKey:key]; - if (oldValue != nil) { [ADJAdjustFactory.logger warn:@"Key %@ with value %@ from %@ parameter was replaced by value %@", key, oldValue, parameterName, obj]; } - [mergedParameters setObject:obj forKey:key]; }]; - return (NSDictionary *)mergedParameters; } @@ -1259,14 +1118,11 @@ + (void)launchInQueue:(dispatch_queue_t)queue return; } __weak __typeof__(selfInject) weakSelf = selfInject; - dispatch_async(queue, ^{ __typeof__(selfInject) strongSelf = weakSelf; - if (strongSelf == nil) { return; } - block(strongSelf); }); } @@ -1274,31 +1130,25 @@ + (void)launchInQueue:(dispatch_queue_t)queue + (BOOL)deleteFileWithName:(NSString *)fileName { NSString *documentsFilePath = [ADJUtil getFilePathInDocumentsDir:fileName]; NSString *appSupportFilePath = [ADJUtil getFilePathInAppSupportDir:fileName]; - BOOL deletedDocumentsFilePath = [ADJUtil deleteFileInPath:documentsFilePath]; BOOL deletedAppSupportFilePath = [ADJUtil deleteFileInPath:appSupportFilePath]; - return deletedDocumentsFilePath || deletedAppSupportFilePath; } + (BOOL)deleteFileInPath:(NSString *)filePath { NSError *error; - if (![[NSFileManager defaultManager] fileExistsAtPath:filePath]) { // [[ADJAdjustFactory logger] verbose:@"File does not exist at path %@", filePath]; return YES; } BOOL deleted = [[NSFileManager defaultManager] removeItemAtPath:filePath error:&error]; - if (!deleted) { [[ADJAdjustFactory logger] verbose:@"Unable to delete file at path %@", filePath]; } - if (error) { [[ADJAdjustFactory logger] error:@"Error while deleting file at path %@", filePath]; } - return deleted; } @@ -1312,7 +1162,6 @@ + (void)launchDeepLinkMain:(NSURL *)deepLinkUrl { #pragma clang diagnostic ignored "-Wundeclared-selector" SEL openUrlSelector = @selector(openURL:options:completionHandler:); #pragma clang diagnostic pop - if ([sharedUIApplication respondsToSelector:openUrlSelector]) { /* [sharedUIApplication openURL:deepLinkUrl options:@{} completionHandler:^(BOOL success) { @@ -1321,20 +1170,16 @@ + (void)launchDeepLinkMain:(NSURL *)deepLinkUrl { } }]; */ - NSMethodSignature *methSig = [sharedUIApplication methodSignatureForSelector:openUrlSelector]; NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:methSig]; - [invocation setSelector: openUrlSelector]; [invocation setTarget: sharedUIApplication]; - NSDictionary *emptyDictionary = @{}; void (^completion)(BOOL) = ^(BOOL success) { if (!success) { [ADJAdjustFactory.logger error:@"Unable to open deep link (%@)", deepLinkUrl]; } }; - [invocation setArgument:&deepLinkUrl atIndex: 2]; [invocation setArgument:&emptyDictionary atIndex: 3]; [invocation setArgument:&completion atIndex: 4]; @@ -1344,7 +1189,6 @@ + (void)launchDeepLinkMain:(NSURL *)deepLinkUrl { #pragma clang diagnostic ignored "-Wdeprecated-declarations" BOOL success = [sharedUIApplication openURL:deepLinkUrl]; #pragma clang diagnostic pop - if (!success) { [ADJAdjustFactory.logger error:@"Unable to open deep link (%@)", deepLinkUrl]; } @@ -1364,7 +1208,6 @@ + (NSString *)convertDeviceToken:(NSData *)deviceToken { } deviceTokenString = [deviceTokenString stringByReplacingOccurrencesOfString:@" " withString:@""]; - return deviceTokenString; } @@ -1374,7 +1217,6 @@ + (BOOL)checkAttributionDetails:(NSDictionary *)attributionDetails { } NSDictionary *details = [attributionDetails objectForKey:@"Version3.1"]; - if ([ADJUtil isNull:details]) { return YES; } @@ -1388,7 +1230,6 @@ + (BOOL)checkAttributionDetails:(NSDictionary *)attributionDetails { [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"] && @@ -1396,7 +1237,6 @@ + (BOOL)checkAttributionDetails:(NSDictionary *)attributionDetails { [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"]) { @@ -1411,11 +1251,9 @@ + (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]]; } @@ -1423,7 +1261,6 @@ + (NSNumber *)readReachabilityFlags { if (reachability == nil) { return nil; } - return [reachability currentReachabilityFlags]; } @@ -1432,7 +1269,6 @@ + (NSString *)readMCC { if (carrier == nil) { return nil; } - return [carrier mobileCountryCode]; } @@ -1440,7 +1276,6 @@ + (NSString *)readMNC { if (carrier == nil) { return nil; } - return [carrier mobileNetworkCode]; } @@ -1448,18 +1283,14 @@ + (NSString *)readCurrentRadioAccessTechnology { if (networkInfo == nil) { return nil; } - SEL radioTechSelector = NSSelectorFromString(@"currentRadioAccessTechnology"); - if (![networkInfo respondsToSelector:radioTechSelector]) { return nil; } - #pragma clang diagnostic push #pragma clang diagnostic ignored "-Warc-performSelector-leaks" id radioTech = [networkInfo performSelector:radioTechSelector]; #pragma clang diagnostic pop - return radioTech; } #endif diff --git a/Adjust/Adjust.h b/Adjust/Adjust.h index 5a453bc75..b7b20046d 100644 --- a/Adjust/Adjust.h +++ b/Adjust/Adjust.h @@ -2,7 +2,7 @@ // Adjust.h // Adjust // -// V4.14.3 +// V4.15.0 // Created by Christian Wellenbrock (wellle) on 23rd July 2013. // Copyright © 2012-2017 Adjust GmbH. All rights reserved. // diff --git a/AdjustBridge/AdjustBridge.h b/AdjustBridge/AdjustBridge.h index 6e52a84bc..39447b448 100644 --- a/AdjustBridge/AdjustBridge.h +++ b/AdjustBridge/AdjustBridge.h @@ -9,16 +9,16 @@ #import #import #import - #import "AdjustBridgeRegister.h" @interface AdjustBridge : NSObject -@property (nonatomic, strong, readonly) id bridgeRegister; +@property (nonatomic, strong, readonly) AdjustBridgeRegister *bridgeRegister; - (void)loadUIWebViewBridge:(WVJB_WEBVIEW_TYPE *)webView; - (void)loadWKWebViewBridge:(WKWebView *)wkWebView; - (void)loadUIWebViewBridge:(WVJB_WEBVIEW_TYPE *)webView webViewDelegate:(WVJB_WEBVIEW_DELEGATE_TYPE *)webViewDelegate; - (void)loadWKWebViewBridge:(WKWebView *)wkWebView wkWebViewDelegate:(id)wkWebViewDelegate; +- (void)augmentHybridWebView; @end diff --git a/AdjustBridge/AdjustBridge.m b/AdjustBridge/AdjustBridge.m index c5ebe3333..b541d257a 100644 --- a/AdjustBridge/AdjustBridge.m +++ b/AdjustBridge/AdjustBridge.m @@ -19,13 +19,14 @@ @interface AdjustBridge() @property BOOL openDeferredDeeplink; -@property WVJBResponseCallback deeplinkCallback; -@property WVJBResponseCallback attributionCallback; -@property WVJBResponseCallback eventSuccessCallback; -@property WVJBResponseCallback eventFailureCallback; -@property WVJBResponseCallback sessionSuccessCallback; -@property WVJBResponseCallback sessionFailureCallback; -@property WVJBResponseCallback deferredDeeplinkCallback; +@property (nonatomic, copy) NSString *fbPixelDefaultEventToken; +@property (nonatomic, strong) NSMutableDictionary* fbPixelMapping; +@property (nonatomic, copy) NSString *attributionCallbackName; +@property (nonatomic, copy) NSString *eventSuccessCallbackName; +@property (nonatomic, copy) NSString *eventFailureCallbackName; +@property (nonatomic, copy) NSString *sessionSuccessCallbackName; +@property (nonatomic, copy) NSString *sessionFailureCallbackName; +@property (nonatomic, copy) NSString *deferredDeeplinkCallbackName; @end @@ -40,90 +41,101 @@ - (id)init { } _bridgeRegister = nil; - self.openDeferredDeeplink = YES; - self.attributionCallback = nil; - self.eventSuccessCallback = nil; - self.eventFailureCallback = nil; - self.sessionSuccessCallback = nil; - self.sessionFailureCallback = nil; - return self; } #pragma mark - AdjustDelegate methods - (void)adjustAttributionChanged:(ADJAttribution *)attribution { - if (self.attributionCallback == nil) { + if (self.attributionCallbackName == nil) { return; } - self.attributionCallback([attribution dictionary]); + [self.bridgeRegister callHandler:self.attributionCallbackName data:[attribution dictionary]]; } - (void)adjustEventTrackingSucceeded:(ADJEventSuccess *)eventSuccessResponseData { - if (self.eventSuccessCallback == nil) { + if (self.eventSuccessCallbackName == nil) { return; } - NSMutableDictionary *dictionary = [NSMutableDictionary dictionary]; - [dictionary setValue:eventSuccessResponseData.message forKey:@"message"]; - [dictionary setValue:eventSuccessResponseData.timeStamp forKey:@"timestamp"]; - [dictionary setValue:eventSuccessResponseData.adid forKey:@"adid"]; - [dictionary setValue:eventSuccessResponseData.eventToken forKey:@"eventToken"]; - [dictionary setValue:eventSuccessResponseData.jsonResponse forKey:@"jsonResponse"]; - self.eventSuccessCallback(dictionary); + NSMutableDictionary *eventSuccessResponseDataDictionary = [NSMutableDictionary dictionary]; + [eventSuccessResponseDataDictionary setValue:eventSuccessResponseData.message forKey:@"message"]; + [eventSuccessResponseDataDictionary setValue:eventSuccessResponseData.timeStamp forKey:@"timestamp"]; + [eventSuccessResponseDataDictionary setValue:eventSuccessResponseData.adid forKey:@"adid"]; + [eventSuccessResponseDataDictionary setValue:eventSuccessResponseData.eventToken forKey:@"eventToken"]; + [eventSuccessResponseDataDictionary setValue:eventSuccessResponseData.callbackId forKey:@"callbackId"]; + [eventSuccessResponseDataDictionary setValue:eventSuccessResponseData.jsonResponse forKey:@"jsonResponse"]; + + [self.bridgeRegister callHandler:self.eventSuccessCallbackName data:eventSuccessResponseDataDictionary]; } - (void)adjustEventTrackingFailed:(ADJEventFailure *)eventFailureResponseData { - if (self.eventFailureCallback == nil) { + if (self.eventFailureCallbackName == nil) { return; } - NSMutableDictionary *dictionary = [NSMutableDictionary dictionary]; - [dictionary setValue:eventFailureResponseData.message forKey:@"message"]; - [dictionary setValue:eventFailureResponseData.timeStamp forKey:@"timestamp"]; - [dictionary setValue:eventFailureResponseData.adid forKey:@"adid"]; - [dictionary setValue:eventFailureResponseData.eventToken forKey:@"eventToken"]; - [dictionary setValue:[NSNumber numberWithBool:eventFailureResponseData.willRetry] forKey:@"willRetry"]; - [dictionary setValue:eventFailureResponseData.jsonResponse forKey:@"jsonResponse"]; - self.eventFailureCallback(dictionary); + NSMutableDictionary *eventFailureResponseDataDictionary = [NSMutableDictionary dictionary]; + [eventFailureResponseDataDictionary setValue:eventFailureResponseData.message forKey:@"message"]; + [eventFailureResponseDataDictionary setValue:eventFailureResponseData.timeStamp forKey:@"timestamp"]; + [eventFailureResponseDataDictionary setValue:eventFailureResponseData.adid forKey:@"adid"]; + [eventFailureResponseDataDictionary setValue:eventFailureResponseData.eventToken forKey:@"eventToken"]; + [eventFailureResponseDataDictionary setValue:eventFailureResponseData.callbackId forKey:@"callbackId"]; + + [eventFailureResponseDataDictionary setValue:[NSNumber numberWithBool:eventFailureResponseData.willRetry] forKey:@"willRetry"]; + [eventFailureResponseDataDictionary setValue:eventFailureResponseData.jsonResponse forKey:@"jsonResponse"]; + + [self.bridgeRegister callHandler:self.eventFailureCallbackName data:eventFailureResponseDataDictionary]; } - (void)adjustSessionTrackingSucceeded:(ADJSessionSuccess *)sessionSuccessResponseData { - if (self.sessionSuccessCallback == nil) { + if (self.sessionSuccessCallbackName == nil) { return; } - NSMutableDictionary *dictionary = [NSMutableDictionary dictionary]; - [dictionary setValue:sessionSuccessResponseData.message forKey:@"message"]; - [dictionary setValue:sessionSuccessResponseData.timeStamp forKey:@"timestamp"]; - [dictionary setValue:sessionSuccessResponseData.adid forKey:@"adid"]; - [dictionary setValue:sessionSuccessResponseData.jsonResponse forKey:@"jsonResponse"]; - self.sessionSuccessCallback(dictionary); + NSMutableDictionary *sessionSuccessResponseDataDictionary = [NSMutableDictionary dictionary]; + [sessionSuccessResponseDataDictionary setValue:sessionSuccessResponseData.message forKey:@"message"]; + [sessionSuccessResponseDataDictionary setValue:sessionSuccessResponseData.timeStamp forKey:@"timestamp"]; + [sessionSuccessResponseDataDictionary setValue:sessionSuccessResponseData.adid forKey:@"adid"]; + [sessionSuccessResponseDataDictionary setValue:sessionSuccessResponseData.jsonResponse forKey:@"jsonResponse"]; + + [self.bridgeRegister callHandler:self.sessionSuccessCallbackName data:sessionSuccessResponseDataDictionary]; } - (void)adjustSessionTrackingFailed:(ADJSessionFailure *)sessionFailureResponseData { - if (self.sessionFailureCallback == nil) { + if (self.sessionFailureCallbackName == nil) { return; } - NSMutableDictionary *dictionary = [NSMutableDictionary dictionary]; - [dictionary setValue:sessionFailureResponseData.message forKey:@"message"]; - [dictionary setValue:sessionFailureResponseData.timeStamp forKey:@"timestamp"]; - [dictionary setValue:sessionFailureResponseData.adid forKey:@"adid"]; - [dictionary setValue:[NSNumber numberWithBool:sessionFailureResponseData.willRetry] forKey:@"willRetry"]; - [dictionary setValue:sessionFailureResponseData.jsonResponse forKey:@"jsonResponse"]; - self.sessionFailureCallback(dictionary); + NSMutableDictionary *sessionFailureResponseDataDictionary = [NSMutableDictionary dictionary]; + [sessionFailureResponseDataDictionary setValue:sessionFailureResponseData.message forKey:@"message"]; + [sessionFailureResponseDataDictionary setValue:sessionFailureResponseData.timeStamp forKey:@"timestamp"]; + [sessionFailureResponseDataDictionary setValue:sessionFailureResponseData.adid forKey:@"adid"]; + [sessionFailureResponseDataDictionary setValue:[NSNumber numberWithBool:sessionFailureResponseData.willRetry] forKey:@"willRetry"]; + [sessionFailureResponseDataDictionary setValue:sessionFailureResponseData.jsonResponse forKey:@"jsonResponse"]; + + [self.bridgeRegister callHandler:self.sessionFailureCallbackName data:sessionFailureResponseDataDictionary]; } - (BOOL)adjustDeeplinkResponse:(NSURL *)deeplink { - if (self.deferredDeeplinkCallback) { - self.deferredDeeplinkCallback([deeplink absoluteString]); + if (self.deferredDeeplinkCallbackName) { + [self.bridgeRegister callHandler:self.deferredDeeplinkCallbackName data:[deeplink absoluteString]]; } return self.openDeferredDeeplink; } #pragma mark - Public methods +- (void)augmentHybridWebView { + NSString *fbAppId = [self getFbAppId]; + + if (fbAppId == nil) { + [[ADJAdjustFactory logger] error:@"FacebookAppID is not correctly configured in the pList"]; + return; + } + [_bridgeRegister augmentHybridWebView:fbAppId]; + [self registerAugmentedView]; +} + - (void)loadUIWebViewBridge:(WVJB_WEBVIEW_TYPE *)webView { [self loadUIWebViewBridge:webView webViewDelegate:nil]; } @@ -138,11 +150,12 @@ - (void)loadUIWebViewBridge:(WVJB_WEBVIEW_TYPE *)webView // WebViewBridge already loaded. return; } - +/* AdjustUIBridgeRegister *uiBridgeRegister = [AdjustUIBridgeRegister bridgeRegisterWithUIWebView:webView]; [uiBridgeRegister setWebViewDelegate:webViewDelegate]; _bridgeRegister = uiBridgeRegister; - [self loadWebViewBridge]; + */ + [self loadWebViewBridge:webView webViewDelegate:webViewDelegate]; } - (void)loadWKWebViewBridge:(WKWebView *)wkWebView @@ -151,34 +164,17 @@ - (void)loadWKWebViewBridge:(WKWebView *)wkWebView // WebViewBridge already loaded. return; } - +/* AdjustWKBridgeRegister *wkBridgeRegister = [AdjustWKBridgeRegister bridgeRegisterWithWKWebView:wkWebView]; [wkBridgeRegister setWebViewDelegate:wkWebViewDelegate]; _bridgeRegister = wkBridgeRegister; - [self loadWebViewBridge]; +*/ + [self loadWebViewBridge:wkWebView webViewDelegate:wkWebViewDelegate]; } -- (void)loadWebViewBridge { - // Register setCallback method to save callbacks before appDidLaunch - [self.bridgeRegister registerHandler:@"adjust_setCallback" handler:^(id data, WVJBResponseCallback responseCallback) { - if (responseCallback == nil) { - return; - } - - if ([data isEqualToString:@"attributionCallback"]) { - self.attributionCallback = responseCallback; - } else if ([data isEqualToString:@"eventSuccessCallback"]) { - self.eventSuccessCallback = responseCallback; - } else if ([data isEqualToString:@"eventFailureCallback"]) { - self.eventFailureCallback = responseCallback; - } else if ([data isEqualToString:@"sessionSuccessCallback"]) { - self.sessionSuccessCallback = responseCallback; - } else if ([data isEqualToString:@"sessionFailureCallback"]) { - self.sessionFailureCallback = responseCallback; - } else if ([data isEqualToString:@"deferredDeeplinkCallback"]) { - self.deferredDeeplinkCallback = responseCallback; - } - }]; +- (void)loadWebViewBridge:(id)webView webViewDelegate:(id)webViewDelegate { + _bridgeRegister = [[AdjustBridgeRegister alloc] initWithWebView:webView]; + [self.bridgeRegister setWebViewDelegate:webViewDelegate]; [self.bridgeRegister registerHandler:@"adjust_appDidLaunch" handler:^(id data, WVJBResponseCallback responseCallback) { NSString *appToken = [data objectForKey:@"appToken"]; @@ -198,6 +194,14 @@ - (void)loadWebViewBridge { NSNumber *info3 = [data objectForKey:@"info3"]; NSNumber *info4 = [data objectForKey:@"info4"]; NSNumber *openDeferredDeeplink = [data objectForKey:@"openDeferredDeeplink"]; + NSString *fbPixelDefaultEventToken = [data objectForKey:@"fbPixelDefaultEventToken"]; + id fbPixelMapping = [data objectForKey:@"fbPixelMapping"]; + NSString * attributionCallback = [data objectForKey:@"attributionCallback"]; + NSString * eventSuccessCallback = [data objectForKey:@"eventSuccessCallback"]; + NSString * eventFailureCallback = [data objectForKey:@"eventFailureCallback"]; + NSString * sessionSuccessCallback = [data objectForKey:@"sessionSuccessCallback"]; + NSString * sessionFailureCallback = [data objectForKey:@"sessionFailureCallback"]; + NSString * deferredDeeplinkCallback = [data objectForKey:@"deferredDeeplinkCallback"]; ADJConfig *adjustConfig; if ([self isFieldValid:allowSuppressLogLevel]) { @@ -250,14 +254,45 @@ - (void)loadWebViewBridge { if ([self isFieldValid:openDeferredDeeplink]) { self.openDeferredDeeplink = [openDeferredDeeplink boolValue]; } + if ([self isFieldValid:fbPixelDefaultEventToken]) { + self.fbPixelDefaultEventToken = fbPixelDefaultEventToken; + } + if ([fbPixelMapping count] > 0) { + self.fbPixelMapping = [[NSMutableDictionary alloc] initWithCapacity:[fbPixelMapping count] / 2]; + } + for (int i = 0; i < [fbPixelMapping count]; i += 2) { + NSString *key = [[fbPixelMapping objectAtIndex:i] description]; + NSString *value = [[fbPixelMapping objectAtIndex:(i + 1)] description]; + [self.fbPixelMapping setObject:value forKey:key]; + } + if ([self isFieldValid:attributionCallback]) { + self.attributionCallbackName = attributionCallback; + } + if ([self isFieldValid:eventSuccessCallback]) { + self.eventSuccessCallbackName = eventSuccessCallback; + } + if ([self isFieldValid:eventFailureCallback]) { + self.eventFailureCallbackName = eventFailureCallback; + } + if ([self isFieldValid:sessionSuccessCallback]) { + self.sessionSuccessCallbackName = sessionSuccessCallback; + } + if ([self isFieldValid:sessionFailureCallback]) { + self.sessionFailureCallbackName = sessionFailureCallback; + } + if ([self isFieldValid:deferredDeeplinkCallback]) { + self.deferredDeeplinkCallbackName = deferredDeeplinkCallback; + } + // Set self as delegate if any callback is configured. // Change to swifle the methods in the future. - if (self.attributionCallback != nil - || self.eventSuccessCallback != nil - || self.eventFailureCallback != nil - || self.sessionSuccessCallback != nil - || self.sessionFailureCallback != nil - || self.deferredDeeplinkCallback != nil) { + if (self.attributionCallbackName != nil + || self.eventSuccessCallbackName != nil + || self.eventFailureCallbackName != nil + || self.sessionSuccessCallbackName != nil + || self.sessionFailureCallbackName != nil + || self.deferredDeeplinkCallbackName != nil) + { [adjustConfig setDelegate:self]; } @@ -272,6 +307,7 @@ - (void)loadWebViewBridge { NSString *transactionId = [data objectForKey:@"transactionId"]; id callbackParameters = [data objectForKey:@"callbackParameters"]; id partnerParameters = [data objectForKey:@"partnerParameters"]; + NSString *callbackId = [data objectForKey:@"callbackId"]; ADJEvent *adjustEvent = [ADJEvent eventWithEventToken:eventToken]; // No need to continue if adjust event is not valid @@ -296,6 +332,9 @@ - (void)loadWebViewBridge { NSString *value = [[partnerParameters objectAtIndex:(i + 1)] description]; [adjustEvent addPartnerParameter:key value:value]; } + if ([self isFieldValid:callbackId]) { + [adjustEvent setCallbackId:callbackId]; + } [Adjust trackEvent:adjustEvent]; }]; @@ -416,6 +455,48 @@ - (void)loadWebViewBridge { }]; } +- (void)registerAugmentedView { + [self.bridgeRegister registerHandler:@"adjust_fbPixelEvent" handler:^(id data, WVJBResponseCallback responseCallback) { + NSString *pixelID = [data objectForKey:@"pixelID"]; + if (pixelID == nil) { + [[ADJAdjustFactory logger] error:@"Can't bridge an event without a referral Pixel ID. Check your webview Pixel configuration"]; + return; + } + NSString *evtName = [data objectForKey:@"evtName"]; + NSString *eventToken = [self getEventTokenFromFbPixelEventName:evtName]; + if (eventToken == nil) { + [[ADJAdjustFactory logger] debug:@"No mapping found for the fb pixel event %@, trying to fall back to the default event token", evtName]; + eventToken = self.fbPixelDefaultEventToken; + } + if (eventToken == nil) { + [[ADJAdjustFactory logger] debug:@"There is not a default event token configured or a mapping found for event named: '%@'. It won't be tracked as an adjust event", evtName]; + return; + } + + ADJEvent *fbPixelEvent = [ADJEvent eventWithEventToken:eventToken]; + if (![fbPixelEvent isValid]) { + return; + } + + id customData = [data objectForKey:@"customData"]; + + [fbPixelEvent addPartnerParameter:@"_fb_pixel_referral_id" value:pixelID]; + // [fbPixelEvent addPartnerParameter:@"_eventName" value:evtName]; + if ([customData isKindOfClass:[NSString class]]) { + NSError *jsonParseError = nil; + NSDictionary *params = [NSJSONSerialization JSONObjectWithData:[customData dataUsingEncoding:NSUTF8StringEncoding] + options:NSJSONReadingMutableContainers + error:&jsonParseError]; + [params enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) { + NSString *keyS = [key description]; + NSString *valueS = [obj description]; + [fbPixelEvent addPartnerParameter:keyS value:valueS]; + }]; + } + [Adjust trackEvent:fbPixelEvent]; + }]; +} + #pragma mark - Private & helper methods - (BOOL)isFieldValid:(NSObject *)field { @@ -428,4 +509,24 @@ - (BOOL)isFieldValid:(NSObject *)field { return YES; } +- (NSString *)getFbAppId { + NSString *facebookLoggingOverrideAppID = [self getValueFromBundleByKey:@"FacebookLoggingOverrideAppID"]; + + if (facebookLoggingOverrideAppID != nil) { + return facebookLoggingOverrideAppID; + } + return [self getValueFromBundleByKey:@"FacebookAppID"]; +} + +- (NSString *)getValueFromBundleByKey:(NSString *)key { + return [[[NSBundle mainBundle] objectForInfoDictionaryKey:key] copy]; +} + +- (NSString *)getEventTokenFromFbPixelEventName:(NSString *)fbPixelEventName { + if (self.fbPixelMapping == nil) { + return nil; + } + return [self.fbPixelMapping objectForKey:fbPixelEventName]; +} + @end diff --git a/AdjustBridge/AdjustBridgeRegister.h b/AdjustBridge/AdjustBridgeRegister.h index 032ad003b..d35042223 100644 --- a/AdjustBridge/AdjustBridgeRegister.h +++ b/AdjustBridge/AdjustBridgeRegister.h @@ -9,10 +9,24 @@ #import #import "WebViewJavascriptBridge.h" +@interface AdjustBridgeRegister : NSObject + +- (id)initWithWebView:(id)webView; +- (void)setWebViewDelegate:(id)webViewDelegate; + +- (void)callHandler:(NSString *)handlerName data:(id)data; +- (void)registerHandler:(NSString *)handlerName handler:(WVJBHandler)handler; +- (void)augmentHybridWebView:(NSString *)fbAppId; ++ (NSString *)AdjustBridge_js; + +@end +/* @protocol AdjustBridgeRegister - (void)callHandler:(NSString *)handlerName data:(id)data; - (void)registerHandler:(NSString *)handlerName handler:(WVJBHandler)handler; +- (void)augmentHybridWebView; ++ (NSString *)AdjustBridge_js; @end @@ -29,3 +43,4 @@ - (void)setWebViewDelegate:(id)webViewDelegate; @end +*/ diff --git a/AdjustBridge/AdjustBridgeRegister.m b/AdjustBridge/AdjustBridgeRegister.m index a5f125300..212865914 100644 --- a/AdjustBridge/AdjustBridgeRegister.m +++ b/AdjustBridge/AdjustBridgeRegister.m @@ -9,87 +9,381 @@ #import "AdjustBridgeRegister.h" static NSString * const kHandlerPrefix = @"adjust_"; +static NSString * fbAppIdStatic = nil; -@interface AdjustUIBridgeRegister() +@interface AdjustBridgeRegister() -@property (nonatomic, strong) WebViewJavascriptBridge *uiBridge; +@property (nonatomic, strong) WebViewJavascriptBridge *wvjb; @end -@implementation AdjustUIBridgeRegister +@implementation AdjustBridgeRegister -+ (id)bridgeRegisterWithUIWebView:(WVJB_WEBVIEW_TYPE *)uiWebView { - return [[AdjustUIBridgeRegister alloc] initWithUIWebView:uiWebView]; -} - -- (id)initWithUIWebView:(WVJB_WEBVIEW_TYPE *)uiWebView { +- (id)initWithWebView:(id)webView { self = [super init]; if (self == nil) { return nil; } - self.uiBridge = [WebViewJavascriptBridge bridgeForWebView:uiWebView]; + self.wvjb = [WebViewJavascriptBridge bridgeForWebView:webView]; return self; } -- (void)setWebViewDelegate:(WVJB_WEBVIEW_DELEGATE_TYPE *)webViewDelegate { - [self.uiBridge setWebViewDelegate:webViewDelegate]; +- (void)setWebViewDelegate:(id)webViewDelegate { + [self.wvjb setWebViewDelegate:webViewDelegate]; +} + +- (void)callHandler:(NSString *)handlerName data:(id)data { + [self.wvjb callHandler:handlerName data:data]; } - (void)registerHandler:(NSString *)handlerName handler:(WVJBHandler)handler { - if ([handlerName hasPrefix:kHandlerPrefix] == NO) { - return; - } - [self.uiBridge registerHandler:handlerName handler:handler]; + [self.wvjb registerHandler:handlerName handler:handler]; } -- (void)callHandler:(NSString *)handlerName data:(id)data { - if ([handlerName hasPrefix:kHandlerPrefix] == NO) { - return; +- (void)augmentHybridWebView:(NSString *)fbAppId { + fbAppIdStatic = fbAppId; +} + ++ (NSString *)AdjustBridge_js { + if (fbAppIdStatic != nil) { + return [NSString stringWithFormat:@"%@%@", + [AdjustBridgeRegister adjust_js], + [AdjustBridgeRegister augmented_js]]; + } else { + return [AdjustBridgeRegister adjust_js]; } - [self.uiBridge callHandler:handlerName data:data]; } -@end +#define __adj_js_func__(x) #x +// BEGIN preprocessorJSCode -@interface AdjustWKBridgeRegister() ++ (NSString *)augmented_js { + return [NSString stringWithFormat: + @__adj_js_func__(;(function() { + window['fbmq_%@'] = { + 'getProtocol' : function() { + return 'fbmq-0.1'; -@property (nonatomic, strong) WebViewJavascriptBridge *wkBridge; + }, + 'sendEvent': function(pixelID, evtName, customData) { + Adjust.fbPixelEvent(pixelID, evtName, customData); + } + }; + })();) // END preprocessorJSCode + , fbAppIdStatic]; +} -@end ++ (NSString *)adjust_js { + static NSString * preprocessorJSCode = @__adj_js_func__(;(function() { + if (window.Adjust) { + return; + } -@implementation AdjustWKBridgeRegister + // copied from adjust.js + window.Adjust = { + appDidLaunch: function (adjustConfig) { + if (WebViewJavascriptBridge) { + if (adjustConfig) { + adjustConfig.registerCallbackHandlers(); + WebViewJavascriptBridge.callHandler('adjust_appDidLaunch', adjustConfig, null); + } + } + }, + trackEvent: function (adjustEvent) { + if (WebViewJavascriptBridge) { + WebViewJavascriptBridge.callHandler('adjust_trackEvent', adjustEvent, null); + } + }, + trackSubsessionStart: function() { + if (WebViewJavascriptBridge) { + WebViewJavascriptBridge.callHandler('adjust_trackSubsessionStart', null, null); + } + }, + trackSubsessionEnd: function() { + if (WebViewJavascriptBridge) { + WebViewJavascriptBridge.callHandler('adjust_trackSubsessionEnd', null, null); + } + }, + setEnabled: function (enabled) { + if (WebViewJavascriptBridge) { + WebViewJavascriptBridge.callHandler('adjust_setEnabled', enabled, null); + } + }, + isEnabled: function (callback) { + if (WebViewJavascriptBridge) { + WebViewJavascriptBridge.callHandler('adjust_isEnabled', null, + function(response) { + callback(new Boolean(response)); + } + ); + } + }, + appWillOpenUrl: function (url) { + if (WebViewJavascriptBridge) { + WebViewJavascriptBridge.callHandler('adjust_appWillOpenUrl', url, null); + } + }, + setDeviceToken: function (deviceToken) { + if (WebViewJavascriptBridge) { + WebViewJavascriptBridge.callHandler('adjust_setDeviceToken', deviceToken, null); + } + }, + setOfflineMode: function(isOffline) { + if (WebViewJavascriptBridge) { + WebViewJavascriptBridge.callHandler('adjust_setOfflineMode', isOffline, null); + } + }, + getIdfa: function (callback) { + if (WebViewJavascriptBridge) { + WebViewJavascriptBridge.callHandler('adjust_idfa', null, callback); + } + }, + getAdid: function (callback) { + if (WebViewJavascriptBridge) { + WebViewJavascriptBridge.callHandler('adjust_adid', null, callback); + } + }, + getAttribution: function (callback) { + if (WebViewJavascriptBridge) { + WebViewJavascriptBridge.callHandler('adjust_attribution', null, callback); + } + }, + sendFirstPackages: function () { + if (WebViewJavascriptBridge) { + WebViewJavascriptBridge.callHandler('adjust_sendFirstPackages', null, null); + } + }, + addSessionCallbackParameter: function (key, value) { + if (WebViewJavascriptBridge != null) { + WebViewJavascriptBridge.callHandler('adjust_addSessionCallbackParameter', {key: key, value: value}, null); + } + }, + addSessionPartnerParameter: function (key, value) { + if (WebViewJavascriptBridge != null) { + WebViewJavascriptBridge.callHandler('adjust_addSessionPartnerParameter', {key: key, value: value}, null); + } + }, + removeSessionCallbackParameter: function (key) { + if (WebViewJavascriptBridge != null) { + WebViewJavascriptBridge.callHandler('adjust_removeSessionCallbackParameter', key, null); + } + }, + removeSessionPartnerParameter: function (key) { + if (WebViewJavascriptBridge != null) { + WebViewJavascriptBridge.callHandler('adjust_removeSessionPartnerParameter', key, null); + } + }, + resetSessionCallbackParameters: function () { + if (WebViewJavascriptBridge != null) { + WebViewJavascriptBridge.callHandler('adjust_resetSessionCallbackParameters', null, null); + } + }, + resetSessionPartnerParameters: function () { + if (WebViewJavascriptBridge != null) { + WebViewJavascriptBridge.callHandler('adjust_resetSessionPartnerParameters', null, null); + } + }, + gdprForgetMe: function () { + if (WebViewJavascriptBridge != null) { + WebViewJavascriptBridge.callHandler('adjust_gdprForgetMe', null, null); + } + }, + fbPixelEvent: function (pixelID, evtName, customData) { + if (WebViewJavascriptBridge != null) { + WebViewJavascriptBridge.callHandler('adjust_fbPixelEvent', + { pixelID: pixelID, + evtName:evtName, + customData: customData + }, + null); + } + } + }; -+ (id)bridgeRegisterWithWKWebView:(WKWebView *)wkWebView { - return [[AdjustWKBridgeRegister alloc] initWithWKWebView:wkWebView]; -} + // copied from adjust_event.js + window.AdjustEvent = function (eventToken) { + this.eventToken = eventToken; -- (id)initWithWKWebView:(WKWebView *)wkWebView { - self = [super init]; - if (self == nil) { - return nil; - } + this.revenue = null; + this.currency = null; + this.transactionId = null; - self.wkBridge = [WebViewJavascriptBridge bridgeForWebView:wkWebView]; - return self; -} + this.callbackParameters = []; + this.partnerParameters = []; -- (void)setWebViewDelegate:(id)webViewDelegate { - [self.wkBridge setWebViewDelegate:webViewDelegate]; -} + this.callbackId = null; + }; -- (void)registerHandler:(NSString *)handlerName handler:(WVJBHandler)handler { - if ([handlerName hasPrefix:kHandlerPrefix] == NO) { - return; - } - [self.wkBridge registerHandler:handlerName handler:handler]; -} + AdjustEvent.prototype.addCallbackParameter = function(key, value) { + this.callbackParameters.push(key); + this.callbackParameters.push(value); + }; -- (void)callHandler:(NSString *)handlerName data:(id)data { - if ([handlerName hasPrefix:kHandlerPrefix] == NO) { - return; - } - [self.wkBridge callHandler:handlerName data:data]; + AdjustEvent.prototype.addPartnerParameter = function(key, value) { + this.partnerParameters.push(key); + this.partnerParameters.push(value); + }; + + AdjustEvent.prototype.setRevenue = function(revenue, currency) { + this.revenue = revenue; + this.currency = currency; + }; + + AdjustEvent.prototype.setTransactionId = function(transactionId) { + this.transactionId = transactionId; + }; + + AdjustEvent.prototype.setCallbackId = function(callbackId) { + this.callbackId = callbackId; + }; + + // copied from adjust_config.js + window.AdjustConfig = function (appToken, environment, legacy) { + + if (arguments.length === 2) { + // New format does not require bridge as first parameter. + this.appToken = appToken; + this.environment = environment; + } else if (arguments.length === 3) { + // New format with allowSuppressLogLevel. + if (typeof(legacy) == typeof(true)) { + this.appToken = appToken; + this.environment = environment; + this.allowSuppressLogLevel = legacy; + } else { + // Old format with first argument being the bridge instance. + this.bridge = appToken; + this.appToken = environment; + this.environment = legacy; + } + } + + this.sdkPrefix = 'web-bridge4.15.0'; + this.defaultTracker = null; + this.logLevel = null; + this.eventBufferingEnabled = null; + this.sendInBackground = null; + this.delayStart = null; + this.userAgent = null; + this.isDeviceKnown = null; + this.secretId = null; + this.info1 = null; + this.info2 = null; + this.info3 = null; + this.info4 = null; + this.openDeferredDeeplink = null; + this.fbPixelDefaultEventToken = null; + this.fbPixelMapping = []; + this.attributionCallback = null; + this.eventSuccessCallback = null; + this.eventFailureCallback = null; + this.sessionSuccessCallback = null; + this.sessionFailureCallback = null; + this.deferredDeeplinkCallback = null; + }; + AdjustConfig.EnvironmentSandbox = 'sandbox'; + AdjustConfig.EnvironmentProduction = 'production'; + + AdjustConfig.LogLevelVerbose = 'VERBOSE'; + AdjustConfig.LogLevelDebug = 'DEBUG'; + AdjustConfig.LogLevelInfo = 'INFO'; + AdjustConfig.LogLevelWarn = 'WARN'; + AdjustConfig.LogLevelError = 'ERROR'; + AdjustConfig.LogLevelAssert = 'ASSERT'; + AdjustConfig.LogLevelSuppress = 'SUPPRESS'; + + AdjustConfig.prototype.registerCallbackHandlers = function() { + var registerCallbackHandler = function (callbackName) { + var callback = this[callbackName]; + if (!callback) { + return; + } + var regiteredCallbackName = 'adjustJS_' + callbackName; + WebViewJavascriptBridge.registerHandler(regiteredCallbackName, callback); + this[callbackName] = regiteredCallbackName; + }; + registerCallbackHandler.call(this, 'attributionCallback'); + registerCallbackHandler.call(this, 'eventSuccessCallback'); + registerCallbackHandler.call(this, 'eventFailureCallback'); + registerCallbackHandler.call(this, 'sessionSuccessCallback'); + registerCallbackHandler.call(this, 'sessionFailureCallback'); + registerCallbackHandler.call(this, 'deferredDeeplinkCallback'); + }; + + AdjustConfig.prototype.setSdkPrefix = function(sdkPrefix) { + this.sdkPrefix = sdkPrefix; + }; + AdjustConfig.prototype.setDefaultTracker = function(defaultTracker) { + this.defaultTracker = defaultTracker; + }; + AdjustConfig.prototype.setLogLevel = function(logLevel) { + this.logLevel = logLevel; + }; + AdjustConfig.prototype.setEventBufferingEnabled = function(isEnabled) { + this.eventBufferingEnabled = isEnabled; + }; + AdjustConfig.prototype.setSendInBackground = function(isEnabled) { + this.sendInBackground = isEnabled; + }; + AdjustConfig.prototype.setDelayStart = function(delayStartInSeconds) { + this.delayStart = delayStartInSeconds; + }; + AdjustConfig.prototype.setUserAgent = function(userAgent) { + this.userAgent = userAgent; + }; + AdjustConfig.prototype.setIsDeviceKnown = function(isDeviceKnown) { + this.isDeviceKnown = isDeviceKnown; + }; + AdjustConfig.prototype.setAppSecret = function(secretId, info1, info2, info3, info4) { + this.secretId = secretId; + this.info1 = info1; + this.info2 = info2; + this.info3 = info3; + this.info4 = info4; + }; + + AdjustConfig.prototype.setOpenDeferredDeeplink = function(shouldOpen) { + this.openDeferredDeeplink = shouldOpen; + }; + + AdjustConfig.prototype.setAttributionCallback = function(callback) { + this.attributionCallback = callback; + }; + + AdjustConfig.prototype.setEventSuccessCallback = function(callback) { + this.eventSuccessCallback = callback; + }; + + AdjustConfig.prototype.setEventFailureCallback = function(callback) { + this.eventFailureCallback = callback; + }; + + AdjustConfig.prototype.setSessionSuccessCallback = function(callback) { + this.sessionSuccessCallback = callback; + }; + + AdjustConfig.prototype.setSessionFailureCallback = function(callback) { + this.sessionFailureCallback = callback; + }; + + AdjustConfig.prototype.setDeferredDeeplinkCallback = function(callback) { + this.deferredDeeplinkCallback = callback; + }; + + AdjustConfig.prototype.setFbPixelDefaultEventToken = function(fbPixelDefaultEventToken) { + this.fbPixelDefaultEventToken = fbPixelDefaultEventToken; + }; + + AdjustConfig.prototype.addFbPixelMapping = function(fbEventNameKey, adjEventTokenValue) { + this.fbPixelMapping.push(fbEventNameKey); + this.fbPixelMapping.push(adjEventTokenValue); + }; + + })();); // END preprocessorJSCode + //, augmentedSection]; +#undef __adj_js_func__ + return preprocessorJSCode; } @end diff --git a/AdjustBridge/WebViewJavascriptBridge/AdjustBridge_JS.h b/AdjustBridge/WebViewJavascriptBridge/AdjustBridge_JS.h deleted file mode 100644 index 6fac087a9..000000000 --- a/AdjustBridge/WebViewJavascriptBridge/AdjustBridge_JS.h +++ /dev/null @@ -1,11 +0,0 @@ -// -// AdjustBridge_JS.h -// Adjust SDK -// -// Created by Pedro Filipe (@nonelse) on 20th July 2018. -// Copyright © 2018 Adjust GmbH. All rights reserved. -// - -#import - -NSString * AdjustBridge_js(void); diff --git a/AdjustBridge/WebViewJavascriptBridge/AdjustBridge_JS.m b/AdjustBridge/WebViewJavascriptBridge/AdjustBridge_JS.m deleted file mode 100644 index 89088ee18..000000000 --- a/AdjustBridge/WebViewJavascriptBridge/AdjustBridge_JS.m +++ /dev/null @@ -1,303 +0,0 @@ -// -// AdjustBridge_JS.m -// Adjust SDK -// -// Created by Pedro Filipe (@nonelse) on 20th July 2018. -// Copyright © 2018 Adjust GmbH. All rights reserved. -// - -// This file including the header and format is copied with adaptions from -// WebViewJavascriptBridge_JS.m - -// This file contains the source for the Javascript side of the -// Adjust Webview bridge. It is plaintext, but converted to an NSString -// via some preprocessor tricks. - -// Previous implementations of Adjust Webview bridge loaded the javascript source -// from a resource. This worked fine for app developers, but library developers who -// included the bridge into their library, awkwardly had to ask consumers of their -// library to include the resource, violating their encapsulation. By including the -// Javascript as a string resource, the encapsulation of the library is maintained. - -#import "AdjustBridge_JS.h" - -NSString * AdjustBridge_js() { - #define __adj_wvjb_js_func__(x) #x - // BEGIN preprocessorJSCode - static NSString * preprocessorJSCode = @__adj_wvjb_js_func__( -;(function() { - if (window.Adjust) { - return; - } - - // copied from adjust.js - window.Adjust = { - appDidLaunch: function (adjustConfig) { - if (WebViewJavascriptBridge) { - if (adjustConfig) { - adjustConfig.iterateConfiguredCallbacks( - function(callbackName, callback) { - WebViewJavascriptBridge.callHandler('adjust_setCallback', callbackName, callback); - } - ); - WebViewJavascriptBridge.callHandler('adjust_appDidLaunch', adjustConfig, null); - } - } - }, - trackEvent: function (adjustEvent) { - if (WebViewJavascriptBridge) { - WebViewJavascriptBridge.callHandler('adjust_trackEvent', adjustEvent, null); - } - }, - trackSubsessionStart: function() { - if (WebViewJavascriptBridge) { - WebViewJavascriptBridge.callHandler('adjust_trackSubsessionStart', null, null); - } - }, - trackSubsessionEnd: function() { - if (WebViewJavascriptBridge) { - WebViewJavascriptBridge.callHandler('adjust_trackSubsessionEnd', null, null); - } - }, - setEnabled: function (enabled) { - if (WebViewJavascriptBridge) { - WebViewJavascriptBridge.callHandler('adjust_setEnabled', enabled, null); - } - }, - isEnabled: function (callback) { - if (WebViewJavascriptBridge) { - WebViewJavascriptBridge.callHandler('adjust_isEnabled', null, - function(response) { - callback(new Boolean(response)); - } - ); - } - }, - appWillOpenUrl: function (url) { - if (WebViewJavascriptBridge) { - WebViewJavascriptBridge.callHandler('adjust_appWillOpenUrl', url, null); - } - }, - setDeviceToken: function (deviceToken) { - if (WebViewJavascriptBridge) { - WebViewJavascriptBridge.callHandler('adjust_setDeviceToken', deviceToken, null); - } - }, - setOfflineMode: function(isOffline) { - if (WebViewJavascriptBridge) { - WebViewJavascriptBridge.callHandler('adjust_setOfflineMode', isOffline, null); - } - }, - getIdfa: function (callback) { - if (WebViewJavascriptBridge) { - WebViewJavascriptBridge.callHandler('adjust_idfa', null, callback); - } - }, - getAdid: function (callback) { - if (WebViewJavascriptBridge) { - WebViewJavascriptBridge.callHandler('adjust_adid', null, callback); - } - }, - getAttribution: function (callback) { - if (WebViewJavascriptBridge) { - WebViewJavascriptBridge.callHandler('adjust_attribution', null, callback); - } - }, - sendFirstPackages: function () { - if (WebViewJavascriptBridge) { - WebViewJavascriptBridge.callHandler('adjust_sendFirstPackages', null, null); - } - }, - addSessionCallbackParameter: function (key, value) { - if (WebViewJavascriptBridge != null) { - WebViewJavascriptBridge.callHandler('adjust_addSessionCallbackParameter', {key: key, value: value}, null); - } - }, - addSessionPartnerParameter: function (key, value) { - if (WebViewJavascriptBridge != null) { - WebViewJavascriptBridge.callHandler('adjust_addSessionPartnerParameter', {key: key, value: value}, null); - } - }, - removeSessionCallbackParameter: function (key) { - if (WebViewJavascriptBridge != null) { - WebViewJavascriptBridge.callHandler('adjust_removeSessionCallbackParameter', key, null); - } - }, - removeSessionPartnerParameter: function (key) { - if (WebViewJavascriptBridge != null) { - WebViewJavascriptBridge.callHandler('adjust_removeSessionPartnerParameter', key, null); - } - }, - resetSessionCallbackParameters: function () { - if (WebViewJavascriptBridge != null) { - WebViewJavascriptBridge.callHandler('adjust_resetSessionCallbackParameters', null, null); - } - }, - resetSessionPartnerParameters: function () { - if (WebViewJavascriptBridge != null) { - WebViewJavascriptBridge.callHandler('adjust_resetSessionPartnerParameters', null, null); - } - }, - gdprForgetMe: function () { - if (WebViewJavascriptBridge != null) { - WebViewJavascriptBridge.callHandler('adjust_gdprForgetMe', null, null); - } - } - }; - - // copied from adjust_event.js - window.AdjustEvent = function (eventToken) { - this.eventToken = eventToken; - - this.revenue = null; - this.currency = null; - this.transactionId = null; - - this.callbackParameters = []; - this.partnerParameters = []; - }; - - AdjustEvent.prototype.addCallbackParameter = function(key, value) { - this.callbackParameters.push(key); - this.callbackParameters.push(value); - }; - - AdjustEvent.prototype.addPartnerParameter = function(key, value) { - this.partnerParameters.push(key); - this.partnerParameters.push(value); - }; - - AdjustEvent.prototype.setRevenue = function(revenue, currency) { - this.revenue = revenue; - this.currency = currency; - }; - - AdjustEvent.prototype.setTransactionId = function(transactionId) { - this.transactionId = transactionId; - }; - - // copied from adjust_config.js - window.AdjustConfig = function (appToken, environment, legacy) { - - if (arguments.length === 2) { - // New format does not require bridge as first parameter. - this.appToken = appToken; - this.environment = environment; - } else if (arguments.length === 3) { - // New format with allowSuppressLogLevel. - if (typeof(legacy) == typeof(true)) { - this.appToken = appToken; - this.environment = environment; - this.allowSuppressLogLevel = legacy; - } else { - // Old format with first argument being the bridge instance. - this.bridge = appToken; - this.appToken = environment; - this.environment = legacy; - } - } - - this.sdkPrefix = 'web-bridge4.14.0'; - this.defaultTracker = null; - this.logLevel = null; - this.eventBufferingEnabled = null; - this.sendInBackground = null; - this.delayStart = null; - this.userAgent = null; - this.isDeviceKnown = null; - this.secretId = null; - this.info1 = null; - this.info2 = null; - this.info3 = null; - this.info4 = null; - this.openDeferredDeeplink = null; - this.callbacksMap = {}; - }; - AdjustConfig.EnvironmentSandbox = 'sandbox'; - AdjustConfig.EnvironmentProduction = 'production'; - - AdjustConfig.LogLevelVerbose = 'VERBOSE'; - AdjustConfig.LogLevelDebug = 'DEBUG'; - AdjustConfig.LogLevelInfo = 'INFO'; - AdjustConfig.LogLevelWarn = 'WARN'; - AdjustConfig.LogLevelError = 'ERROR'; - AdjustConfig.LogLevelAssert = 'ASSERT'; - AdjustConfig.LogLevelSuppress = 'SUPPRESS'; - - AdjustConfig.prototype.iterateConfiguredCallbacks = function(handleCallbackWithName) { - if (!this.callbacksMap) { - return; - } - var keysArray = Object.keys(this.callbacksMap); - for (var idx in keysArray) { - var key = keysArray[idx]; - handleCallbackWithName(key, this.callbacksMap[key]); - } - }; - - AdjustConfig.prototype.setSdkPrefix = function(sdkPrefix) { - this.sdkPrefix = sdkPrefix; - }; - AdjustConfig.prototype.setDefaultTracker = function(defaultTracker) { - this.defaultTracker = defaultTracker; - }; - AdjustConfig.prototype.setLogLevel = function(logLevel) { - this.logLevel = logLevel; - }; - AdjustConfig.prototype.setEventBufferingEnabled = function(isEnabled) { - this.eventBufferingEnabled = isEnabled; - }; - AdjustConfig.prototype.setSendInBackground = function(isEnabled) { - this.sendInBackground = isEnabled; - }; - AdjustConfig.prototype.setDelayStart = function(delayStartInSeconds) { - this.delayStart = delayStartInSeconds; - }; - AdjustConfig.prototype.setUserAgent = function(userAgent) { - this.userAgent = userAgent; - }; - AdjustConfig.prototype.setIsDeviceKnown = function(isDeviceKnown) { - this.isDeviceKnown = isDeviceKnown; - }; - AdjustConfig.prototype.setAppSecret = function(secretId, info1, info2, info3, info4) { - this.secretId = secretId; - this.info1 = info1; - this.info2 = info2; - this.info3 = info3; - this.info4 = info4; - }; - - AdjustConfig.prototype.setOpenDeferredDeeplink = function(shouldOpen) { - this.openDeferredDeeplink = shouldOpen; - }; - - AdjustConfig.prototype.setAttributionCallback = function(callback) { - this.callbacksMap['attributionCallback'] = callback; - }; - - AdjustConfig.prototype.setEventSuccessCallback = function(callback) { - this.callbacksMap['eventSuccessCallback'] = callback; - }; - - AdjustConfig.prototype.setEventFailureCallback = function(callback) { - this.callbacksMap['eventFailureCallback'] = callback; - }; - - AdjustConfig.prototype.setSessionSuccessCallback = function(callback) { - this.callbacksMap['sessionSuccessCallback'] = callback; - }; - - AdjustConfig.prototype.setSessionFailureCallback = function(callback) { - this.callbacksMap['sessionFailureCallback'] = callback; - }; - - AdjustConfig.prototype.setDeferredDeeplinkCallback = function(callback) { - this.callbacksMap['deferredDeeplinkCallback'] = callback; - }; - - })(); - ); // END preprocessorJSCode - -#undef __adj_wvjb_js_func__ - return preprocessorJSCode; -}; diff --git a/AdjustBridge/WebViewJavascriptBridge/WebViewJavascriptBridgeBase.m b/AdjustBridge/WebViewJavascriptBridge/WebViewJavascriptBridgeBase.m index b6f4ec141..d68140586 100755 --- a/AdjustBridge/WebViewJavascriptBridge/WebViewJavascriptBridgeBase.m +++ b/AdjustBridge/WebViewJavascriptBridge/WebViewJavascriptBridgeBase.m @@ -8,7 +8,8 @@ #import #import "WebViewJavascriptBridgeBase.h" #import "WebViewJavascriptBridge_JS.h" -#import "AdjustBridge_JS.h" +//#import "AdjustBridge_JS.h" +#import "AdjustBridgeRegister.h" @implementation WebViewJavascriptBridgeBase { __weak id _webViewDelegate; @@ -115,7 +116,8 @@ - (void)injectJavascriptFile { NSString *js = WebViewJavascriptBridge_js(); [self _evaluateJavascript:js]; // Added to inject adjust js code - NSString *adjust_js = AdjustBridge_js(); + //NSString *adjust_js = AdjustBridge_js(); + NSString *adjust_js = [AdjustBridgeRegister AdjustBridge_js]; [self _evaluateJavascript:adjust_js]; if (self.startupMessageQueue) { NSArray* queue = self.startupMessageQueue; diff --git a/AdjustTests/AdjustTestApp/AdjustTestApp/ATAAdjustCommandExecutor.m b/AdjustTests/AdjustTestApp/AdjustTestApp/ATAAdjustCommandExecutor.m index fed0461a5..21a8475a0 100644 --- a/AdjustTests/AdjustTestApp/AdjustTestApp/ATAAdjustCommandExecutor.m +++ b/AdjustTests/AdjustTestApp/AdjustTestApp/ATAAdjustCommandExecutor.m @@ -371,6 +371,14 @@ - (void)event:(NSDictionary *)parameters { } [adjustEvent setTransactionId:transactionId]; } + + if ([parameters objectForKey:@"callbackId"]) { + NSString *callbackId = [parameters objectForKey:@"callbackId"][0]; + if (callbackId == (id)[NSNull null]) { + callbackId = nil; + } + [adjustEvent setCallbackId:callbackId]; + } } - (void)trackEvent:(NSDictionary *)parameters { diff --git a/AdjustTests/AdjustTestApp/AdjustTestApp/Delegates/ATAAdjustDelegateEventFailure.m b/AdjustTests/AdjustTestApp/AdjustTestApp/Delegates/ATAAdjustDelegateEventFailure.m index b394da9d6..17ba3479f 100644 --- a/AdjustTests/AdjustTestApp/AdjustTestApp/Delegates/ATAAdjustDelegateEventFailure.m +++ b/AdjustTests/AdjustTestApp/AdjustTestApp/Delegates/ATAAdjustDelegateEventFailure.m @@ -38,6 +38,7 @@ - (void)adjustEventTrackingFailed:(ADJEventFailure *)eventFailureResponseData { [self.testLibrary addInfoToSend:@"timestamp" value:eventFailureResponseData.timeStamp]; [self.testLibrary addInfoToSend:@"adid" value:eventFailureResponseData.adid]; [self.testLibrary addInfoToSend:@"eventToken" value:eventFailureResponseData.eventToken]; + [self.testLibrary addInfoToSend:@"callbackId" value:eventFailureResponseData.callbackId]; [self.testLibrary addInfoToSend:@"willRetry" value:(eventFailureResponseData.willRetry ? @"true" : @"false")]; NSError *error; diff --git a/AdjustTests/AdjustTestApp/AdjustTestApp/Delegates/ATAAdjustDelegateEventSuccess.m b/AdjustTests/AdjustTestApp/AdjustTestApp/Delegates/ATAAdjustDelegateEventSuccess.m index bfe2b33d6..573eafce7 100644 --- a/AdjustTests/AdjustTestApp/AdjustTestApp/Delegates/ATAAdjustDelegateEventSuccess.m +++ b/AdjustTests/AdjustTestApp/AdjustTestApp/Delegates/ATAAdjustDelegateEventSuccess.m @@ -38,6 +38,7 @@ - (void)adjustEventTrackingSucceeded:(ADJEventSuccess *)eventSuccessResponseData [self.testLibrary addInfoToSend:@"timestamp" value:eventSuccessResponseData.timeStamp]; [self.testLibrary addInfoToSend:@"adid" value:eventSuccessResponseData.adid]; [self.testLibrary addInfoToSend:@"eventToken" value:eventSuccessResponseData.eventToken]; + [self.testLibrary addInfoToSend:@"callbackId" value:eventSuccessResponseData.callbackId]; NSError *error; NSData *jsonData = [NSJSONSerialization dataWithJSONObject:eventSuccessResponseData.jsonResponse diff --git a/AdjustTests/AdjustTestApp/AdjustTestApp/ViewController.m b/AdjustTests/AdjustTestApp/AdjustTestApp/ViewController.m index e736de85c..58c65b45b 100644 --- a/AdjustTests/AdjustTestApp/AdjustTestApp/ViewController.m +++ b/AdjustTests/AdjustTestApp/AdjustTestApp/ViewController.m @@ -36,7 +36,7 @@ - (void)viewDidLoad { } - (void)startTestSession { - [self.testLibrary startTestSession:@"ios4.14.3"]; + [self.testLibrary startTestSession:@"ios4.15.0"]; } - (void)didReceiveMemoryWarning { diff --git a/AdjustTests/AdjustUnitTests/ADJPackageFields.m b/AdjustTests/AdjustUnitTests/ADJPackageFields.m index 3509cea9f..4bdd13b98 100644 --- a/AdjustTests/AdjustUnitTests/ADJPackageFields.m +++ b/AdjustTests/AdjustUnitTests/ADJPackageFields.m @@ -16,7 +16,7 @@ - (id) init { // default values self.appToken = @"qwerty123456"; - self.clientSdk = @"ios4.14.3"; + self.clientSdk = @"ios4.15.0"; self.suffix = @""; self.environment = @"sandbox"; diff --git a/CHANGELOG.md b/CHANGELOG.md index b46d80dbc..acd387ce3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,20 @@ +### Version 4.15.0 (31st August 2018) +#### Added +- Added `setCallbackId` method on `ADJEvent` object for users to set custom ID on event object which will later be reported in event success/failure callbacks. +- Added `callbackId` property to `ADJEventSuccess` class. +- Added `callbackId` property to `ADJEventFailure` class. +- Added support for tracking Facebook Pixel events with iOS web view SDK. +- Aligned feature set of iOS web view SDK with native iOS SDK. +- Added example app which demonstrates how iOS web view SDK can be used to track Facebook Pixel events. + +#### Changed +- SDK will now fire attribution request each time upon session tracking finished in case it lacks attribution info. + +#### Fixed +- Web bridge callbacks can now be called more than once + +--- + ### Version 4.14.3 (16th August 2018) #### Changed - Changed deployment target of iMessage dynamic framework target back to 8.0. diff --git a/README.md b/README.md index ec14b49fb..fd1947dc9 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,7 @@ If your app is an app which uses web views you would like to use adjust tracking * [In-App Purchase verification](#iap-verification) * [Callback parameters](#callback-parameters) * [Partner parameters](#partner-parameters) + * [Callback identifier](#callback-id) * [Session parameters](#session-parameters) * [Session callback parameters](#session-callback-parameters) * [Session partner parameters](#session-partner-parameters) @@ -69,13 +70,13 @@ We will describe the steps to integrate the Adjust SDK into your iOS project. We If you're using [CocoaPods][cocoapods], you can add the following line to your `Podfile` and continue from [this step](#sdk-integrate): ```ruby -pod 'Adjust', '~> 4.14.3' +pod 'Adjust', '~> 4.15.0' ``` or: ```ruby -pod 'Adjust', :git => 'https://github.com/adjust/ios_sdk.git', :tag => 'v4.14.3' +pod 'Adjust', :git => 'https://github.com/adjust/ios_sdk.git', :tag => 'v4.15.0' ``` --- @@ -373,6 +374,19 @@ ADJEvent *event = [ADJEvent eventWithEventToken:@"abc123"]; You can read more about special partners and these integrations in our [guide to special partners][special-partners]. +### Callback identifier + +You can also add custom string identifier to each event you want to track. This identifier will later be reported in event success and/or event failure callbacks to enable you to keep track on which event was successfully tracked or not. You can set this identifier by calling the `setCallbackId` method on your `ADJEvent` instance: + + +```objc +ADJEvent *event = [ADJEvent eventWithEventToken:@"abc123"]; + +[event setCallbackId:@"Your-Custom-Id"]; + +[Adjust trackEvent:event]; +``` + ### 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. @@ -525,6 +539,7 @@ The delegate functions will be called after the SDK tries to send a package to t Both event response data objects contain: - `NSString eventToken` the event token, if the package tracked was an event. +- `NSString callbackid` the custom defined callback ID set on event object. If any value is unavailable, it will default to `nil`. diff --git a/VERSION b/VERSION index 453b50f24..5c517bf11 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -4.14.3 +4.15.0 diff --git a/doc/english/fb_pixel.md b/doc/english/fb_pixel.md new file mode 100644 index 000000000..53b81cb10 --- /dev/null +++ b/doc/english/fb_pixel.md @@ -0,0 +1,126 @@ +## Facebook pixel integration + +[The Facebook Pixel](https://www.facebook.com/business/help/952192354843755) is a web-only analytics tool from Facebook. In the past it was impossible to use the Facebook SDK to track Pixel events in an app's webview. Since the release of [FB SDK](https://developers.facebook.com/docs/analytics) v4.34, it's now possible to do so, and use the [Hybrid Mobile App Events](https://developers.facebook.com/docs/app-events/hybrid-app-events) to convert Facebook Pixel events into Facebook App events. + +It is also now possible to use the Facebook Pixel with the Adjust SDK, without integrating the FB SDK. + +## Facebook integration + +### Example app + +There is an example app inside the [`AdjustExample-FbPixel` directory][example-fbpixel] that demonstrates how Facebook Pixel events can be tracked with usage of Adjust web view SDK. + +### Facebook App ID + +There is no need to integrate the FB SDK; however, you must follow a few of the same integration steps from the FB SDK in order for the Adjust SDK to integrate the Facebook Pixel. + +As is described in the [FB SDK iOS SDK guide](https://developers.facebook.com/docs/ios/getting-started/#xcode) you will need to add your Facebook App ID to the app. You can follow the steps in that guide, but we've also copied them here below: + +- In Xcode, right click on your project's `Info.plist` file and select Open As -> Source Code. +- Insert the following XML snippet into the body of your file just before the final `` element: + + ```xml + + ... + FacebookAppID + {your-app-id} + ... + + ``` + +- Replace `{your-app-id}` with your app's App ID (found on the *Facebook App Dashboard*). + +### Facebook Pixel configuration + +Follow Facebook's guide on how to integrate the Facebook Pixel. The Javascript code should look something like this: + +```js + + +... + +``` + +Now, just as described in the [Hybrid Mobile App Events guide](https://developers.facebook.com/docs/app-events/hybrid-app-events) `Update Your Pixel` section, you'll need to update the Facebook Pixel code like this: + +```js +fbq('init', ); +fbq('set', 'mobileBridge', , ); +``` + +**Note**: Please pay attention that it is **very important** that you first call `'init'` and immediately afterwards `'set'` method. Facebook's script snipet they offer you to paste to your HTML web page (like shown above) contains `'track'` method for page view event right after call to `'init'` method. In order for this page view event to be properly tracked, please make sure to call `'set'` method in between! + +## Adjust integration + +### Augment the web view + +Follow the integration guide for [iOS web view](web_views.md) apps. In the section where you load the webview bridge (see below): + +```objc +- (void)viewWillAppear:(BOOL)animated { + ... + UIWebView *webView = [[UIWebView alloc] initWithFrame:self.view.bounds]; + // or with WKWebView: + // WKWebView *webView = [[WKWebView alloc] initWithFrame:self.view.bounds]; + + // add @property (nonatomic, strong) AdjustBridge *adjustBridge; on your interface + self.adjustBridge = [[AdjustBridge alloc] init]; + [self.adjustBridge loadUIWebViewBridge:webView]; + // optionally you can add a web view delegate so that you can also capture its events + // [self.adjustBridge loadUIWebViewBridge:webView webViewDelegate:(UIWebViewDelegate*)self]; + + // or with WKWebView: + // [self.adjustBridge loadWKWebViewBridge:webView]; + // optionally you can add a web view delegate so that you can also capture its events + // [self.adjustBridge loadWKWebViewBridge:webView wkWebViewDelegate:(id)self]; + ... +``` + +No matter how you choose to load the web view into the Adjust bridge, follow that step by adding the following line: + +```objc +[self.adjustBridge augmentHybridWebView]; +``` + +### Event name configuration + +The Adjust web bridge SDK translates Facebook Pixel events into Adjust events. + +For this reason, it's necessary to map Facebook Pixels to specific Adjust events, or to configure a default Adjust event token ***before*** starting Adjust SDK and tracking any Facebook Pixel event, including the copy-pasted `fbq('track', 'PageView');` from the Facebook Pixel configuration. + +To map Facebook Pixel events and Adjust events, call `addFbPixelMapping(fbEventNameKey, adjEventTokenValue)` in the `adjustConfig` instance before initializing the Adjust SDK. Here's an example of what that could look like: + +```js +adjustConfig.addFbPixelMapping('fb_mobile_search', adjustEventTokenForSearch); +adjustConfig.addFbPixelMapping('fb_mobile_purchase', adjustEventTokenForPurchase); +``` + +Note that this would match when tracking the following Facebook Pixel events: `fbq('track', 'Search', ...);` and `fbq('track', 'Purchase', ...);` respectively. Unfortunately, we do not have access to the entire mapping scheme between the event names tracked in Javascript and the event names used by the FB SDK. + +To help you, here is the event name information we've found so far: + +| Pixel event name | Corresponding Facebook app event name +| ---------------- | ------------------------------------- +| ViewContent | fb_mobile_content_view +| Search | fb_mobile_search +| AddToCart | fb_mobile_add_to_cart +| AddToWishlist | fb_mobile_add_to_wishlist +| InitiateCheckout | fb_mobile_initiated_checkout +| AddPaymentInfo | fb_mobile_add_payment_info +| Purchase | fb_mobile_purchase +| CompleteRegistration | fb_mobile_complete_registration + +This may not be an exhaustive list; it's also possible that Facebook adds to or updates the current listing. While testing, check the Adjust logs for warnings such as: + +``` +There is not a default event token configured or a mapping found for event named: 'fb_mobile_search'. It won't be tracked as an adjust event +``` + +There is also the option to use a default Adjust event if you do not have mapping configured. Just call `adjustConfig.setFbPixelDefaultEventToken(defaultEventToken);` before initializing the Adjust SDK. + +[example-fbpixel]: ../../examples/AdjustExample-FbPixel diff --git a/doc/english/migrate.md b/doc/english/migrate.md index 2c7853625..32d8245f8 100644 --- a/doc/english/migrate.md +++ b/doc/english/migrate.md @@ -1,4 +1,4 @@ -## Migrate your adjust SDK for iOS to v4.14.3 from v3.4.0 +## Migrate your adjust SDK for iOS to v4.15.0 from v3.4.0 ### Initial setup diff --git a/doc/english/web_view_migration.md b/doc/english/web_view_migration.md index 6036f5005..60670554b 100644 --- a/doc/english/web_view_migration.md +++ b/doc/english/web_view_migration.md @@ -1,4 +1,4 @@ -## Migrate your Adjust web bridge SDK to v4.14.0 or later from v4.9.1 or earlier +## Migrate your Adjust web bridge SDK to v4.15.0 or later from v4.9.1 or earlier ### Integration diff --git a/doc/english/web_views.md b/doc/english/web_views.md index 82e9d3f8e..a764c000b 100644 --- a/doc/english/web_views.md +++ b/doc/english/web_views.md @@ -63,7 +63,7 @@ We will describe the steps to integrate the Adjust SDK into your iOS project. We If you're using [CocoaPods][cocoapods], you can add the following line to your `Podfile` and continue from [this step](#sdk-integrate): ```ruby -pod 'Adjust/WebBridge', '~> 4.14.3' +pod 'Adjust/WebBridge', '~> 4.15.0' ``` --- diff --git a/doc/japanese/migrate_ja.md b/doc/japanese/migrate_ja.md index 667864622..f828663f4 100644 --- a/doc/japanese/migrate_ja.md +++ b/doc/japanese/migrate_ja.md @@ -1,4 +1,4 @@ -## iOS用adjust SDKのv3.4.0からv4.14.3への移行 +## iOS用adjust SDKのv3.4.0からv4.15.0への移行 ### 初期設定 diff --git a/doc/migrate.md b/doc/migrate.md index 2c7853625..32d8245f8 100644 --- a/doc/migrate.md +++ b/doc/migrate.md @@ -1,4 +1,4 @@ -## Migrate your adjust SDK for iOS to v4.14.3 from v3.4.0 +## Migrate your adjust SDK for iOS to v4.15.0 from v3.4.0 ### Initial setup diff --git a/examples/AdjustExample-FbPixel/AdjustExample-FbPixel.xcodeproj/project.pbxproj b/examples/AdjustExample-FbPixel/AdjustExample-FbPixel.xcodeproj/project.pbxproj new file mode 100644 index 000000000..6d5ef595b --- /dev/null +++ b/examples/AdjustExample-FbPixel/AdjustExample-FbPixel.xcodeproj/project.pbxproj @@ -0,0 +1,648 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 50; + objects = { + +/* Begin PBXBuildFile section */ + 9D9D1533212EB3920081445E /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D9D1532212EB3920081445E /* AppDelegate.m */; }; + 9D9D1539212EB3920081445E /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 9D9D1537212EB3920081445E /* Main.storyboard */; }; + 9D9D153B212EB3940081445E /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 9D9D153A212EB3940081445E /* Assets.xcassets */; }; + 9D9D153E212EB3940081445E /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 9D9D153C212EB3940081445E /* LaunchScreen.storyboard */; }; + 9D9D1541212EB3940081445E /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D9D1540212EB3940081445E /* main.m */; }; + 9D9D1561212EB4080081445E /* iAd.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9D9D1560212EB4080081445E /* iAd.framework */; }; + 9D9D1563212EB40D0081445E /* AdSupport.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9D9D1562212EB40D0081445E /* AdSupport.framework */; }; + 9D9D1565212EB4130081445E /* WebKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9D9D1564212EB4130081445E /* WebKit.framework */; }; + 9D9D15BA212EB4570081445E /* ADJDeviceInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D9D1569212EB4560081445E /* ADJDeviceInfo.m */; }; + 9D9D15BB212EB4570081445E /* ADJTimerOnce.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D9D156A212EB4560081445E /* ADJTimerOnce.m */; }; + 9D9D15BC212EB4570081445E /* ADJAttributionHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D9D156B212EB4560081445E /* ADJAttributionHandler.m */; }; + 9D9D15BD212EB4570081445E /* ADJRequestHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D9D156E212EB4560081445E /* ADJRequestHandler.m */; }; + 9D9D15BE212EB4570081445E /* ADJKeychain.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D9D1571212EB4560081445E /* ADJKeychain.m */; }; + 9D9D15BF212EB4570081445E /* ADJSdkClickHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D9D1572212EB4560081445E /* ADJSdkClickHandler.m */; }; + 9D9D15C0212EB4570081445E /* ADJEvent.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D9D1574212EB4560081445E /* ADJEvent.m */; }; + 9D9D15C1212EB4570081445E /* ADJSessionSuccess.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D9D1578212EB4560081445E /* ADJSessionSuccess.m */; }; + 9D9D15C2212EB4570081445E /* ADJEventFailure.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D9D1579212EB4560081445E /* ADJEventFailure.m */; }; + 9D9D15C3212EB4570081445E /* ADJEventSuccess.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D9D157B212EB4560081445E /* ADJEventSuccess.m */; }; + 9D9D15C4212EB4570081445E /* ADJActivityState.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D9D157C212EB4560081445E /* ADJActivityState.m */; }; + 9D9D15C5212EB4570081445E /* ADJSessionFailure.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D9D157D212EB4560081445E /* ADJSessionFailure.m */; }; + 9D9D15C6212EB4570081445E /* ADJTimerCycle.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D9D1581212EB4560081445E /* ADJTimerCycle.m */; }; + 9D9D15C7212EB4570081445E /* ADJSessionParameters.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D9D1582212EB4560081445E /* ADJSessionParameters.m */; }; + 9D9D15C8212EB4570081445E /* ADJLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D9D1583212EB4560081445E /* ADJLogger.m */; }; + 9D9D15C9212EB4570081445E /* ADJBackoffStrategy.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D9D1584212EB4560081445E /* ADJBackoffStrategy.m */; }; + 9D9D15CA212EB4570081445E /* Adjust.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D9D1586212EB4560081445E /* Adjust.m */; }; + 9D9D15CB212EB4570081445E /* ADJConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D9D158A212EB4560081445E /* ADJConfig.m */; }; + 9D9D15CC212EB4570081445E /* ADJPackageHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D9D158B212EB4560081445E /* ADJPackageHandler.m */; }; + 9D9D15CD212EB4570081445E /* ADJActivityKind.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D9D158E212EB4560081445E /* ADJActivityKind.m */; }; + 9D9D15CE212EB4570081445E /* NSString+ADJAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D9D1591212EB4560081445E /* NSString+ADJAdditions.m */; }; + 9D9D15CF212EB4570081445E /* NSData+ADJAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D9D1593212EB4560081445E /* NSData+ADJAdditions.m */; }; + 9D9D15D0212EB4570081445E /* UIDevice+ADJAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D9D1595212EB4560081445E /* UIDevice+ADJAdditions.m */; }; + 9D9D15D1212EB4570081445E /* ADJAttribution.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D9D1597212EB4560081445E /* ADJAttribution.m */; }; + 9D9D15D2212EB4570081445E /* ADJSystemProfile.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D9D1598212EB4560081445E /* ADJSystemProfile.m */; }; + 9D9D15D3212EB4570081445E /* ADJActivityPackage.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D9D159A212EB4560081445E /* ADJActivityPackage.m */; }; + 9D9D15D4212EB4570081445E /* ADJUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D9D159B212EB4560081445E /* ADJUtil.m */; }; + 9D9D15D5212EB4570081445E /* ADJAdjustFactory.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D9D159E212EB4560081445E /* ADJAdjustFactory.m */; }; + 9D9D15D6212EB4570081445E /* ADJResponseData.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D9D15A1212EB4560081445E /* ADJResponseData.m */; }; + 9D9D15D7212EB4570081445E /* ADJPackageBuilder.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D9D15A3212EB4560081445E /* ADJPackageBuilder.m */; }; + 9D9D15D8212EB4570081445E /* ADJUserDefaults.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D9D15A4212EB4560081445E /* ADJUserDefaults.m */; }; + 9D9D15DA212EB4570081445E /* ADJActivityHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D9D15AA212EB4560081445E /* ADJActivityHandler.m */; }; + 9D9D15DB212EB4570081445E /* ADJReachability.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D9D15AB212EB4560081445E /* ADJReachability.m */; }; + 9D9D15DC212EB4570081445E /* AdjustBridge.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D9D15AD212EB4570081445E /* AdjustBridge.m */; }; + 9D9D15DD212EB4570081445E /* WebViewJavascriptBridgeBase.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D9D15B0212EB4570081445E /* WebViewJavascriptBridgeBase.m */; }; + 9D9D15DE212EB4570081445E /* WKWebViewJavascriptBridge.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D9D15B1212EB4570081445E /* WKWebViewJavascriptBridge.m */; }; + 9D9D15DF212EB4570081445E /* WebViewJavascriptBridge.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D9D15B2212EB4570081445E /* WebViewJavascriptBridge.m */; }; + 9D9D15E0212EB4570081445E /* WebViewJavascriptBridge_JS.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D9D15B5212EB4570081445E /* WebViewJavascriptBridge_JS.m */; }; + 9D9D15E1212EB4570081445E /* AdjustBridgeRegister.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D9D15B9212EB4570081445E /* AdjustBridgeRegister.m */; }; + 9D9D15E3212EB47C0081445E /* AdjustExample-FbPixel.html in Resources */ = {isa = PBXBuildFile; fileRef = 9D9D15E2212EB47C0081445E /* AdjustExample-FbPixel.html */; }; + 9D9D15E8212EB5230081445E /* UIWebViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D9D15E4212EB5230081445E /* UIWebViewController.m */; }; + 9D9D15E9212EB5230081445E /* WKWebViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D9D15E6212EB5230081445E /* WKWebViewController.m */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 9D9D152E212EB3920081445E /* AdjustExample-FbPixel.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "AdjustExample-FbPixel.app"; sourceTree = BUILT_PRODUCTS_DIR; }; + 9D9D1531212EB3920081445E /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; + 9D9D1532212EB3920081445E /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; + 9D9D1538212EB3920081445E /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 9D9D153A212EB3940081445E /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 9D9D153D212EB3940081445E /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 9D9D153F212EB3940081445E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 9D9D1540212EB3940081445E /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; + 9D9D1560212EB4080081445E /* iAd.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = iAd.framework; path = System/Library/Frameworks/iAd.framework; sourceTree = SDKROOT; }; + 9D9D1562212EB40D0081445E /* AdSupport.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AdSupport.framework; path = System/Library/Frameworks/AdSupport.framework; sourceTree = SDKROOT; }; + 9D9D1564212EB4130081445E /* WebKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WebKit.framework; path = System/Library/Frameworks/WebKit.framework; sourceTree = SDKROOT; }; + 9D9D1568212EB4560081445E /* ADJConfig.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ADJConfig.h; sourceTree = ""; }; + 9D9D1569212EB4560081445E /* ADJDeviceInfo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ADJDeviceInfo.m; sourceTree = ""; }; + 9D9D156A212EB4560081445E /* ADJTimerOnce.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ADJTimerOnce.m; sourceTree = ""; }; + 9D9D156B212EB4560081445E /* ADJAttributionHandler.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ADJAttributionHandler.m; sourceTree = ""; }; + 9D9D156C212EB4560081445E /* Adjust.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Adjust.h; sourceTree = ""; }; + 9D9D156D212EB4560081445E /* ADJActivityPackage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ADJActivityPackage.h; sourceTree = ""; }; + 9D9D156E212EB4560081445E /* ADJRequestHandler.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ADJRequestHandler.m; sourceTree = ""; }; + 9D9D156F212EB4560081445E /* ADJSystemProfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ADJSystemProfile.h; sourceTree = ""; }; + 9D9D1570212EB4560081445E /* ADJAttribution.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ADJAttribution.h; sourceTree = ""; }; + 9D9D1571212EB4560081445E /* ADJKeychain.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ADJKeychain.m; sourceTree = ""; }; + 9D9D1572212EB4560081445E /* ADJSdkClickHandler.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ADJSdkClickHandler.m; sourceTree = ""; }; + 9D9D1573212EB4560081445E /* ADJActivityKind.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ADJActivityKind.h; sourceTree = ""; }; + 9D9D1574212EB4560081445E /* ADJEvent.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ADJEvent.m; sourceTree = ""; }; + 9D9D1575212EB4560081445E /* ADJPackageHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ADJPackageHandler.h; sourceTree = ""; }; + 9D9D1576212EB4560081445E /* ADJPackageBuilder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ADJPackageBuilder.h; sourceTree = ""; }; + 9D9D1577212EB4560081445E /* ADJResponseData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ADJResponseData.h; sourceTree = ""; }; + 9D9D1578212EB4560081445E /* ADJSessionSuccess.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ADJSessionSuccess.m; sourceTree = ""; }; + 9D9D1579212EB4560081445E /* ADJEventFailure.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ADJEventFailure.m; sourceTree = ""; }; + 9D9D157A212EB4560081445E /* ADJAdjustFactory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ADJAdjustFactory.h; sourceTree = ""; }; + 9D9D157B212EB4560081445E /* ADJEventSuccess.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ADJEventSuccess.m; sourceTree = ""; }; + 9D9D157C212EB4560081445E /* ADJActivityState.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ADJActivityState.m; sourceTree = ""; }; + 9D9D157D212EB4560081445E /* ADJSessionFailure.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ADJSessionFailure.m; sourceTree = ""; }; + 9D9D157E212EB4560081445E /* ADJUtil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ADJUtil.h; sourceTree = ""; }; + 9D9D157F212EB4560081445E /* ADJReachability.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ADJReachability.h; sourceTree = ""; }; + 9D9D1580212EB4560081445E /* ADJActivityHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ADJActivityHandler.h; sourceTree = ""; }; + 9D9D1581212EB4560081445E /* ADJTimerCycle.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ADJTimerCycle.m; sourceTree = ""; }; + 9D9D1582212EB4560081445E /* ADJSessionParameters.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ADJSessionParameters.m; sourceTree = ""; }; + 9D9D1583212EB4560081445E /* ADJLogger.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ADJLogger.m; sourceTree = ""; }; + 9D9D1584212EB4560081445E /* ADJBackoffStrategy.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ADJBackoffStrategy.m; sourceTree = ""; }; + 9D9D1585212EB4560081445E /* ADJUserDefaults.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ADJUserDefaults.h; sourceTree = ""; }; + 9D9D1586212EB4560081445E /* Adjust.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Adjust.m; sourceTree = ""; }; + 9D9D1587212EB4560081445E /* ADJAttributionHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ADJAttributionHandler.h; sourceTree = ""; }; + 9D9D1588212EB4560081445E /* ADJTimerOnce.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ADJTimerOnce.h; sourceTree = ""; }; + 9D9D1589212EB4560081445E /* ADJDeviceInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ADJDeviceInfo.h; sourceTree = ""; }; + 9D9D158A212EB4560081445E /* ADJConfig.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ADJConfig.m; sourceTree = ""; }; + 9D9D158B212EB4560081445E /* ADJPackageHandler.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ADJPackageHandler.m; sourceTree = ""; }; + 9D9D158C212EB4560081445E /* ADJEvent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ADJEvent.h; sourceTree = ""; }; + 9D9D158D212EB4560081445E /* ADJSdkClickHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ADJSdkClickHandler.h; sourceTree = ""; }; + 9D9D158E212EB4560081445E /* ADJActivityKind.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ADJActivityKind.m; sourceTree = ""; }; + 9D9D158F212EB4560081445E /* ADJKeychain.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ADJKeychain.h; sourceTree = ""; }; + 9D9D1591212EB4560081445E /* NSString+ADJAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSString+ADJAdditions.m"; sourceTree = ""; }; + 9D9D1592212EB4560081445E /* UIDevice+ADJAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIDevice+ADJAdditions.h"; sourceTree = ""; }; + 9D9D1593212EB4560081445E /* NSData+ADJAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSData+ADJAdditions.m"; sourceTree = ""; }; + 9D9D1594212EB4560081445E /* NSData+ADJAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSData+ADJAdditions.h"; sourceTree = ""; }; + 9D9D1595212EB4560081445E /* UIDevice+ADJAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIDevice+ADJAdditions.m"; sourceTree = ""; }; + 9D9D1596212EB4560081445E /* NSString+ADJAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSString+ADJAdditions.h"; sourceTree = ""; }; + 9D9D1597212EB4560081445E /* ADJAttribution.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ADJAttribution.m; sourceTree = ""; }; + 9D9D1598212EB4560081445E /* ADJSystemProfile.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ADJSystemProfile.m; sourceTree = ""; }; + 9D9D1599212EB4560081445E /* ADJRequestHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ADJRequestHandler.h; sourceTree = ""; }; + 9D9D159A212EB4560081445E /* ADJActivityPackage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ADJActivityPackage.m; sourceTree = ""; }; + 9D9D159B212EB4560081445E /* ADJUtil.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ADJUtil.m; sourceTree = ""; }; + 9D9D159C212EB4560081445E /* ADJSessionFailure.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ADJSessionFailure.h; sourceTree = ""; }; + 9D9D159D212EB4560081445E /* ADJActivityState.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ADJActivityState.h; sourceTree = ""; }; + 9D9D159E212EB4560081445E /* ADJAdjustFactory.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ADJAdjustFactory.m; sourceTree = ""; }; + 9D9D159F212EB4560081445E /* ADJEventSuccess.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ADJEventSuccess.h; sourceTree = ""; }; + 9D9D15A0212EB4560081445E /* ADJEventFailure.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ADJEventFailure.h; sourceTree = ""; }; + 9D9D15A1212EB4560081445E /* ADJResponseData.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ADJResponseData.m; sourceTree = ""; }; + 9D9D15A2212EB4560081445E /* ADJSessionSuccess.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ADJSessionSuccess.h; sourceTree = ""; }; + 9D9D15A3212EB4560081445E /* ADJPackageBuilder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ADJPackageBuilder.m; sourceTree = ""; }; + 9D9D15A4212EB4560081445E /* ADJUserDefaults.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ADJUserDefaults.m; sourceTree = ""; }; + 9D9D15A5212EB4560081445E /* ADJBackoffStrategy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ADJBackoffStrategy.h; sourceTree = ""; }; + 9D9D15A6212EB4560081445E /* ADJLogger.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ADJLogger.h; sourceTree = ""; }; + 9D9D15A7212EB4560081445E /* ADJSessionParameters.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ADJSessionParameters.h; sourceTree = ""; }; + 9D9D15A9212EB4560081445E /* ADJTimerCycle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ADJTimerCycle.h; sourceTree = ""; }; + 9D9D15AA212EB4560081445E /* ADJActivityHandler.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ADJActivityHandler.m; sourceTree = ""; }; + 9D9D15AB212EB4560081445E /* ADJReachability.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ADJReachability.m; sourceTree = ""; }; + 9D9D15AD212EB4570081445E /* AdjustBridge.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AdjustBridge.m; sourceTree = ""; }; + 9D9D15AE212EB4570081445E /* AdjustBridgeRegister.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AdjustBridgeRegister.h; sourceTree = ""; }; + 9D9D15B0212EB4570081445E /* WebViewJavascriptBridgeBase.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WebViewJavascriptBridgeBase.m; sourceTree = ""; }; + 9D9D15B1212EB4570081445E /* WKWebViewJavascriptBridge.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WKWebViewJavascriptBridge.m; sourceTree = ""; }; + 9D9D15B2212EB4570081445E /* WebViewJavascriptBridge.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WebViewJavascriptBridge.m; sourceTree = ""; }; + 9D9D15B3212EB4570081445E /* WebViewJavascriptBridge_JS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebViewJavascriptBridge_JS.h; sourceTree = ""; }; + 9D9D15B4212EB4570081445E /* WebViewJavascriptBridgeBase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebViewJavascriptBridgeBase.h; sourceTree = ""; }; + 9D9D15B5212EB4570081445E /* WebViewJavascriptBridge_JS.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WebViewJavascriptBridge_JS.m; sourceTree = ""; }; + 9D9D15B6212EB4570081445E /* WebViewJavascriptBridge.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebViewJavascriptBridge.h; sourceTree = ""; }; + 9D9D15B7212EB4570081445E /* WKWebViewJavascriptBridge.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WKWebViewJavascriptBridge.h; sourceTree = ""; }; + 9D9D15B8212EB4570081445E /* AdjustBridge.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AdjustBridge.h; sourceTree = ""; }; + 9D9D15B9212EB4570081445E /* AdjustBridgeRegister.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AdjustBridgeRegister.m; sourceTree = ""; }; + 9D9D15E2212EB47C0081445E /* AdjustExample-FbPixel.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "AdjustExample-FbPixel.html"; sourceTree = ""; }; + 9D9D15E4212EB5230081445E /* UIWebViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UIWebViewController.m; sourceTree = ""; }; + 9D9D15E5212EB5230081445E /* UIWebViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UIWebViewController.h; sourceTree = ""; }; + 9D9D15E6212EB5230081445E /* WKWebViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WKWebViewController.m; sourceTree = ""; }; + 9D9D15E7212EB5230081445E /* WKWebViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WKWebViewController.h; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 9D9D152B212EB3920081445E /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 9D9D1561212EB4080081445E /* iAd.framework in Frameworks */, + 9D9D1565212EB4130081445E /* WebKit.framework in Frameworks */, + 9D9D1563212EB40D0081445E /* AdSupport.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 9D9D1525212EB3920081445E = { + isa = PBXGroup; + children = ( + 9D9D1530212EB3920081445E /* AdjustExample-FbPixel */, + 9D9D152F212EB3920081445E /* Products */, + 9D9D155F212EB4080081445E /* Frameworks */, + ); + sourceTree = ""; + }; + 9D9D152F212EB3920081445E /* Products */ = { + isa = PBXGroup; + children = ( + 9D9D152E212EB3920081445E /* AdjustExample-FbPixel.app */, + ); + name = Products; + sourceTree = ""; + }; + 9D9D1530212EB3920081445E /* AdjustExample-FbPixel */ = { + isa = PBXGroup; + children = ( + 9D9D1531212EB3920081445E /* AppDelegate.h */, + 9D9D1532212EB3920081445E /* AppDelegate.m */, + 9D9D15E5212EB5230081445E /* UIWebViewController.h */, + 9D9D15E4212EB5230081445E /* UIWebViewController.m */, + 9D9D15E7212EB5230081445E /* WKWebViewController.h */, + 9D9D15E6212EB5230081445E /* WKWebViewController.m */, + 9D9D1537212EB3920081445E /* Main.storyboard */, + 9D9D153A212EB3940081445E /* Assets.xcassets */, + 9D9D153C212EB3940081445E /* LaunchScreen.storyboard */, + 9D9D153F212EB3940081445E /* Info.plist */, + 9D9D1540212EB3940081445E /* main.m */, + 9D9D15E2212EB47C0081445E /* AdjustExample-FbPixel.html */, + 9D9D1566212EB43D0081445E /* Supporting Files */, + ); + path = "AdjustExample-FbPixel"; + sourceTree = ""; + }; + 9D9D155F212EB4080081445E /* Frameworks */ = { + isa = PBXGroup; + children = ( + 9D9D1564212EB4130081445E /* WebKit.framework */, + 9D9D1562212EB40D0081445E /* AdSupport.framework */, + 9D9D1560212EB4080081445E /* iAd.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + 9D9D1566212EB43D0081445E /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 9D9D1567212EB4560081445E /* Adjust */, + 9D9D15AC212EB4570081445E /* AdjustBridge */, + ); + path = "Supporting Files"; + sourceTree = ""; + }; + 9D9D1567212EB4560081445E /* Adjust */ = { + isa = PBXGroup; + children = ( + 9D9D1568212EB4560081445E /* ADJConfig.h */, + 9D9D1569212EB4560081445E /* ADJDeviceInfo.m */, + 9D9D156A212EB4560081445E /* ADJTimerOnce.m */, + 9D9D156B212EB4560081445E /* ADJAttributionHandler.m */, + 9D9D156C212EB4560081445E /* Adjust.h */, + 9D9D156D212EB4560081445E /* ADJActivityPackage.h */, + 9D9D156E212EB4560081445E /* ADJRequestHandler.m */, + 9D9D156F212EB4560081445E /* ADJSystemProfile.h */, + 9D9D1570212EB4560081445E /* ADJAttribution.h */, + 9D9D1571212EB4560081445E /* ADJKeychain.m */, + 9D9D1572212EB4560081445E /* ADJSdkClickHandler.m */, + 9D9D1573212EB4560081445E /* ADJActivityKind.h */, + 9D9D1574212EB4560081445E /* ADJEvent.m */, + 9D9D1575212EB4560081445E /* ADJPackageHandler.h */, + 9D9D1576212EB4560081445E /* ADJPackageBuilder.h */, + 9D9D1577212EB4560081445E /* ADJResponseData.h */, + 9D9D1578212EB4560081445E /* ADJSessionSuccess.m */, + 9D9D1579212EB4560081445E /* ADJEventFailure.m */, + 9D9D157A212EB4560081445E /* ADJAdjustFactory.h */, + 9D9D157B212EB4560081445E /* ADJEventSuccess.m */, + 9D9D157C212EB4560081445E /* ADJActivityState.m */, + 9D9D157D212EB4560081445E /* ADJSessionFailure.m */, + 9D9D157E212EB4560081445E /* ADJUtil.h */, + 9D9D157F212EB4560081445E /* ADJReachability.h */, + 9D9D1580212EB4560081445E /* ADJActivityHandler.h */, + 9D9D1581212EB4560081445E /* ADJTimerCycle.m */, + 9D9D1582212EB4560081445E /* ADJSessionParameters.m */, + 9D9D1583212EB4560081445E /* ADJLogger.m */, + 9D9D1584212EB4560081445E /* ADJBackoffStrategy.m */, + 9D9D1585212EB4560081445E /* ADJUserDefaults.h */, + 9D9D1586212EB4560081445E /* Adjust.m */, + 9D9D1587212EB4560081445E /* ADJAttributionHandler.h */, + 9D9D1588212EB4560081445E /* ADJTimerOnce.h */, + 9D9D1589212EB4560081445E /* ADJDeviceInfo.h */, + 9D9D158A212EB4560081445E /* ADJConfig.m */, + 9D9D158B212EB4560081445E /* ADJPackageHandler.m */, + 9D9D158C212EB4560081445E /* ADJEvent.h */, + 9D9D158D212EB4560081445E /* ADJSdkClickHandler.h */, + 9D9D158E212EB4560081445E /* ADJActivityKind.m */, + 9D9D158F212EB4560081445E /* ADJKeychain.h */, + 9D9D1590212EB4560081445E /* ADJAdditions */, + 9D9D1597212EB4560081445E /* ADJAttribution.m */, + 9D9D1598212EB4560081445E /* ADJSystemProfile.m */, + 9D9D1599212EB4560081445E /* ADJRequestHandler.h */, + 9D9D159A212EB4560081445E /* ADJActivityPackage.m */, + 9D9D159B212EB4560081445E /* ADJUtil.m */, + 9D9D159C212EB4560081445E /* ADJSessionFailure.h */, + 9D9D159D212EB4560081445E /* ADJActivityState.h */, + 9D9D159E212EB4560081445E /* ADJAdjustFactory.m */, + 9D9D159F212EB4560081445E /* ADJEventSuccess.h */, + 9D9D15A0212EB4560081445E /* ADJEventFailure.h */, + 9D9D15A1212EB4560081445E /* ADJResponseData.m */, + 9D9D15A2212EB4560081445E /* ADJSessionSuccess.h */, + 9D9D15A3212EB4560081445E /* ADJPackageBuilder.m */, + 9D9D15A4212EB4560081445E /* ADJUserDefaults.m */, + 9D9D15A5212EB4560081445E /* ADJBackoffStrategy.h */, + 9D9D15A6212EB4560081445E /* ADJLogger.h */, + 9D9D15A7212EB4560081445E /* ADJSessionParameters.h */, + 9D9D15A9212EB4560081445E /* ADJTimerCycle.h */, + 9D9D15AA212EB4560081445E /* ADJActivityHandler.m */, + 9D9D15AB212EB4560081445E /* ADJReachability.m */, + ); + name = Adjust; + path = ../../../../Adjust; + sourceTree = ""; + }; + 9D9D1590212EB4560081445E /* ADJAdditions */ = { + isa = PBXGroup; + children = ( + 9D9D1591212EB4560081445E /* NSString+ADJAdditions.m */, + 9D9D1592212EB4560081445E /* UIDevice+ADJAdditions.h */, + 9D9D1593212EB4560081445E /* NSData+ADJAdditions.m */, + 9D9D1594212EB4560081445E /* NSData+ADJAdditions.h */, + 9D9D1595212EB4560081445E /* UIDevice+ADJAdditions.m */, + 9D9D1596212EB4560081445E /* NSString+ADJAdditions.h */, + ); + path = ADJAdditions; + sourceTree = ""; + }; + 9D9D15AC212EB4570081445E /* AdjustBridge */ = { + isa = PBXGroup; + children = ( + 9D9D15AD212EB4570081445E /* AdjustBridge.m */, + 9D9D15AE212EB4570081445E /* AdjustBridgeRegister.h */, + 9D9D15AF212EB4570081445E /* WebViewJavascriptBridge */, + 9D9D15B8212EB4570081445E /* AdjustBridge.h */, + 9D9D15B9212EB4570081445E /* AdjustBridgeRegister.m */, + ); + name = AdjustBridge; + path = ../../../../AdjustBridge; + sourceTree = ""; + }; + 9D9D15AF212EB4570081445E /* WebViewJavascriptBridge */ = { + isa = PBXGroup; + children = ( + 9D9D15B0212EB4570081445E /* WebViewJavascriptBridgeBase.m */, + 9D9D15B1212EB4570081445E /* WKWebViewJavascriptBridge.m */, + 9D9D15B2212EB4570081445E /* WebViewJavascriptBridge.m */, + 9D9D15B3212EB4570081445E /* WebViewJavascriptBridge_JS.h */, + 9D9D15B4212EB4570081445E /* WebViewJavascriptBridgeBase.h */, + 9D9D15B5212EB4570081445E /* WebViewJavascriptBridge_JS.m */, + 9D9D15B6212EB4570081445E /* WebViewJavascriptBridge.h */, + 9D9D15B7212EB4570081445E /* WKWebViewJavascriptBridge.h */, + ); + path = WebViewJavascriptBridge; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 9D9D152D212EB3920081445E /* AdjustExample-FbPixel */ = { + isa = PBXNativeTarget; + buildConfigurationList = 9D9D1544212EB3940081445E /* Build configuration list for PBXNativeTarget "AdjustExample-FbPixel" */; + buildPhases = ( + 9D9D152A212EB3920081445E /* Sources */, + 9D9D152B212EB3920081445E /* Frameworks */, + 9D9D152C212EB3920081445E /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "AdjustExample-FbPixel"; + productName = "AdjustExample-FbPixel"; + productReference = 9D9D152E212EB3920081445E /* AdjustExample-FbPixel.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 9D9D1526212EB3920081445E /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0940; + ORGANIZATIONNAME = "Adjust GmbH"; + TargetAttributes = { + 9D9D152D212EB3920081445E = { + CreatedOnToolsVersion = 9.4.1; + }; + }; + }; + buildConfigurationList = 9D9D1529212EB3920081445E /* Build configuration list for PBXProject "AdjustExample-FbPixel" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 9D9D1525212EB3920081445E; + productRefGroup = 9D9D152F212EB3920081445E /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 9D9D152D212EB3920081445E /* AdjustExample-FbPixel */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 9D9D152C212EB3920081445E /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 9D9D15E3212EB47C0081445E /* AdjustExample-FbPixel.html in Resources */, + 9D9D153E212EB3940081445E /* LaunchScreen.storyboard in Resources */, + 9D9D153B212EB3940081445E /* Assets.xcassets in Resources */, + 9D9D1539212EB3920081445E /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 9D9D152A212EB3920081445E /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 9D9D15BF212EB4570081445E /* ADJSdkClickHandler.m in Sources */, + 9D9D15D5212EB4570081445E /* ADJAdjustFactory.m in Sources */, + 9D9D15D0212EB4570081445E /* UIDevice+ADJAdditions.m in Sources */, + 9D9D15E0212EB4570081445E /* WebViewJavascriptBridge_JS.m in Sources */, + 9D9D15D6212EB4570081445E /* ADJResponseData.m in Sources */, + 9D9D15BB212EB4570081445E /* ADJTimerOnce.m in Sources */, + 9D9D15CE212EB4570081445E /* NSString+ADJAdditions.m in Sources */, + 9D9D15C1212EB4570081445E /* ADJSessionSuccess.m in Sources */, + 9D9D15D7212EB4570081445E /* ADJPackageBuilder.m in Sources */, + 9D9D15DF212EB4570081445E /* WebViewJavascriptBridge.m in Sources */, + 9D9D15C9212EB4570081445E /* ADJBackoffStrategy.m in Sources */, + 9D9D15BD212EB4570081445E /* ADJRequestHandler.m in Sources */, + 9D9D15C0212EB4570081445E /* ADJEvent.m in Sources */, + 9D9D15CF212EB4570081445E /* NSData+ADJAdditions.m in Sources */, + 9D9D15CC212EB4570081445E /* ADJPackageHandler.m in Sources */, + 9D9D15C3212EB4570081445E /* ADJEventSuccess.m in Sources */, + 9D9D15D3212EB4570081445E /* ADJActivityPackage.m in Sources */, + 9D9D15DB212EB4570081445E /* ADJReachability.m in Sources */, + 9D9D15DE212EB4570081445E /* WKWebViewJavascriptBridge.m in Sources */, + 9D9D15E8212EB5230081445E /* UIWebViewController.m in Sources */, + 9D9D15CD212EB4570081445E /* ADJActivityKind.m in Sources */, + 9D9D15BE212EB4570081445E /* ADJKeychain.m in Sources */, + 9D9D15E1212EB4570081445E /* AdjustBridgeRegister.m in Sources */, + 9D9D15D2212EB4570081445E /* ADJSystemProfile.m in Sources */, + 9D9D15C4212EB4570081445E /* ADJActivityState.m in Sources */, + 9D9D15C8212EB4570081445E /* ADJLogger.m in Sources */, + 9D9D15E9212EB5230081445E /* WKWebViewController.m in Sources */, + 9D9D15BA212EB4570081445E /* ADJDeviceInfo.m in Sources */, + 9D9D15C6212EB4570081445E /* ADJTimerCycle.m in Sources */, + 9D9D1541212EB3940081445E /* main.m in Sources */, + 9D9D15CA212EB4570081445E /* Adjust.m in Sources */, + 9D9D15D1212EB4570081445E /* ADJAttribution.m in Sources */, + 9D9D15C5212EB4570081445E /* ADJSessionFailure.m in Sources */, + 9D9D15CB212EB4570081445E /* ADJConfig.m in Sources */, + 9D9D15D8212EB4570081445E /* ADJUserDefaults.m in Sources */, + 9D9D15D4212EB4570081445E /* ADJUtil.m in Sources */, + 9D9D15C2212EB4570081445E /* ADJEventFailure.m in Sources */, + 9D9D15BC212EB4570081445E /* ADJAttributionHandler.m in Sources */, + 9D9D1533212EB3920081445E /* AppDelegate.m in Sources */, + 9D9D15DA212EB4570081445E /* ADJActivityHandler.m in Sources */, + 9D9D15C7212EB4570081445E /* ADJSessionParameters.m in Sources */, + 9D9D15DD212EB4570081445E /* WebViewJavascriptBridgeBase.m in Sources */, + 9D9D15DC212EB4570081445E /* AdjustBridge.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 9D9D1537212EB3920081445E /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 9D9D1538212EB3920081445E /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 9D9D153C212EB3940081445E /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 9D9D153D212EB3940081445E /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 9D9D1542212EB3940081445E /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 11.4; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + }; + name = Debug; + }; + 9D9D1543212EB3940081445E /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 11.4; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 9D9D1545212EB3940081445E /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = QGUGW9AUMK; + INFOPLIST_FILE = "AdjustExample-FbPixel/Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.adjust.examples; + PRODUCT_NAME = "$(TARGET_NAME)"; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 9D9D1546212EB3940081445E /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = QGUGW9AUMK; + INFOPLIST_FILE = "AdjustExample-FbPixel/Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.adjust.examples; + PRODUCT_NAME = "$(TARGET_NAME)"; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 9D9D1529212EB3920081445E /* Build configuration list for PBXProject "AdjustExample-FbPixel" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 9D9D1542212EB3940081445E /* Debug */, + 9D9D1543212EB3940081445E /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 9D9D1544212EB3940081445E /* Build configuration list for PBXNativeTarget "AdjustExample-FbPixel" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 9D9D1545212EB3940081445E /* Debug */, + 9D9D1546212EB3940081445E /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 9D9D1526212EB3920081445E /* Project object */; +} diff --git a/examples/AdjustExample-FbPixel/AdjustExample-FbPixel.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/examples/AdjustExample-FbPixel/AdjustExample-FbPixel.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..f9240ddfa --- /dev/null +++ b/examples/AdjustExample-FbPixel/AdjustExample-FbPixel.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/examples/AdjustExample-FbPixel/AdjustExample-FbPixel.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/examples/AdjustExample-FbPixel/AdjustExample-FbPixel.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/examples/AdjustExample-FbPixel/AdjustExample-FbPixel.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/examples/AdjustExample-FbPixel/AdjustExample-FbPixel/AdjustExample-FbPixel.html b/examples/AdjustExample-FbPixel/AdjustExample-FbPixel/AdjustExample-FbPixel.html new file mode 100644 index 000000000..a83d3af34 --- /dev/null +++ b/examples/AdjustExample-FbPixel/AdjustExample-FbPixel/AdjustExample-FbPixel.html @@ -0,0 +1,170 @@ + + + + + +

Adjust Web View Demo

+ + +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ diff --git a/examples/AdjustExample-FbPixel/AdjustExample-FbPixel/AppDelegate.h b/examples/AdjustExample-FbPixel/AdjustExample-FbPixel/AppDelegate.h new file mode 100644 index 000000000..0f41ab7fb --- /dev/null +++ b/examples/AdjustExample-FbPixel/AdjustExample-FbPixel/AppDelegate.h @@ -0,0 +1,17 @@ +// +// AppDelegate.h +// AdjustExample-FbPixel +// +// Created by Uglješa Erceg on 23.08.18. +// Copyright © 2018 Adjust GmbH. All rights reserved. +// + +#import + +@interface AppDelegate : UIResponder + +@property (strong, nonatomic) UIWindow *window; + + +@end + diff --git a/examples/AdjustExample-FbPixel/AdjustExample-FbPixel/AppDelegate.m b/examples/AdjustExample-FbPixel/AdjustExample-FbPixel/AppDelegate.m new file mode 100644 index 000000000..527ae09c0 --- /dev/null +++ b/examples/AdjustExample-FbPixel/AdjustExample-FbPixel/AppDelegate.m @@ -0,0 +1,81 @@ +// +// AppDelegate.m +// AdjustExample-FbPixel +// +// Created by Uglješa Erceg on 23.08.18. +// Copyright © 2018 Adjust GmbH. All rights reserved. +// + +#import "Adjust.h" +#import "AppDelegate.h" +#import "UIWebViewController.h" +#import "WKWebViewController.h" + +@interface AppDelegate () + +@property UIWebViewController *uiWebViewExampleController; +@property WKWebViewController *wkWebViewExampleController; + +@end + +@implementation AppDelegate + + +- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { + // 1. Create the UIWebView example + self.uiWebViewExampleController = [[UIWebViewController alloc] init]; + self.uiWebViewExampleController.tabBarItem.title = @"UIWebView"; + + // 2. Create the tab footer and add the UIWebView example + UITabBarController *tabBarController = [[UITabBarController alloc] init]; + [tabBarController addChildViewController:self.uiWebViewExampleController]; + + // 3. Create the WKWebView example for devices >= iOS 8 + if ([WKWebView class]) { + self.wkWebViewExampleController = [[WKWebViewController alloc] init]; + self.wkWebViewExampleController.tabBarItem.title = @"WKWebView"; + [tabBarController addChildViewController:self.wkWebViewExampleController]; + } + + self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; + self.window.rootViewController = tabBarController; + [self.window makeKeyAndVisible]; + + return YES; +} + +- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation { + [Adjust appWillOpenUrl:url]; + return YES; +} + +- (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity restorationHandler:(void (^)(NSArray *restorableObjects))restorationHandler { + if ([[userActivity activityType] isEqualToString:NSUserActivityTypeBrowsingWeb]) { + [Adjust appWillOpenUrl:[userActivity webpageURL]]; + } + return YES; +} + +- (void)applicationWillResignActive:(UIApplication *)application { + // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. + // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. +} + +- (void)applicationDidEnterBackground:(UIApplication *)application { + // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. + // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. +} + +- (void)applicationWillEnterForeground:(UIApplication *)application { + // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. +} + +- (void)applicationDidBecomeActive:(UIApplication *)application { + // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. +} + +- (void)applicationWillTerminate:(UIApplication *)application { + // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. +} + +@end diff --git a/examples/AdjustExample-FbPixel/AdjustExample-FbPixel/Assets.xcassets/AppIcon.appiconset/Contents.json b/examples/AdjustExample-FbPixel/AdjustExample-FbPixel/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 000000000..d8db8d65f --- /dev/null +++ b/examples/AdjustExample-FbPixel/AdjustExample-FbPixel/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,98 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "3x" + }, + { + "idiom" : "ipad", + "size" : "20x20", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "20x20", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "83.5x83.5", + "scale" : "2x" + }, + { + "idiom" : "ios-marketing", + "size" : "1024x1024", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/examples/AdjustExample-FbPixel/AdjustExample-FbPixel/Assets.xcassets/Contents.json b/examples/AdjustExample-FbPixel/AdjustExample-FbPixel/Assets.xcassets/Contents.json new file mode 100644 index 000000000..da4a164c9 --- /dev/null +++ b/examples/AdjustExample-FbPixel/AdjustExample-FbPixel/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/examples/AdjustExample-FbPixel/AdjustExample-FbPixel/Base.lproj/LaunchScreen.storyboard b/examples/AdjustExample-FbPixel/AdjustExample-FbPixel/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 000000000..f83f6fd58 --- /dev/null +++ b/examples/AdjustExample-FbPixel/AdjustExample-FbPixel/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/AdjustExample-FbPixel/AdjustExample-FbPixel/Base.lproj/Main.storyboard b/examples/AdjustExample-FbPixel/AdjustExample-FbPixel/Base.lproj/Main.storyboard new file mode 100644 index 000000000..d7c78a125 --- /dev/null +++ b/examples/AdjustExample-FbPixel/AdjustExample-FbPixel/Base.lproj/Main.storyboard @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/AdjustExample-FbPixel/AdjustExample-FbPixel/Info.plist b/examples/AdjustExample-FbPixel/AdjustExample-FbPixel/Info.plist new file mode 100644 index 000000000..cc97c7188 --- /dev/null +++ b/examples/AdjustExample-FbPixel/AdjustExample-FbPixel/Info.plist @@ -0,0 +1,47 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + FacebookAppID + 308873563017393 + + diff --git a/examples/AdjustExample-FbPixel/AdjustExample-FbPixel/UIWebViewController.h b/examples/AdjustExample-FbPixel/AdjustExample-FbPixel/UIWebViewController.h new file mode 100644 index 000000000..b0e1b37fa --- /dev/null +++ b/examples/AdjustExample-FbPixel/AdjustExample-FbPixel/UIWebViewController.h @@ -0,0 +1,20 @@ +// +// ViewController.h +// AdjustExample-WebView +// +// Created by Uglješa Erceg on 31/05/16. +// Copyright © 2016 adjust GmbH. All rights reserved. +// + +#import +#import + +#import "AdjustBridge.h" + +@interface UIWebViewController : UINavigationController + +@property AdjustBridge *adjustBridge; +@property JSContext *jsContext; + +@end + diff --git a/examples/AdjustExample-FbPixel/AdjustExample-FbPixel/UIWebViewController.m b/examples/AdjustExample-FbPixel/AdjustExample-FbPixel/UIWebViewController.m new file mode 100644 index 000000000..92863189d --- /dev/null +++ b/examples/AdjustExample-FbPixel/AdjustExample-FbPixel/UIWebViewController.m @@ -0,0 +1,53 @@ +// +// ViewController.m +// AdjustExample-WebView +// +// Created by Uglješa Erceg on 31/05/16. +// Copyright © 2016 adjust GmbH. All rights reserved. +// + +#import "UIWebViewController.h" + +@interface UIWebViewController () + +@end + +@implementation UIWebViewController + +- (void)viewDidLoad { + [super viewDidLoad]; +} + +- (void)viewWillAppear:(BOOL)animated { + [self loadUIWebView]; +} + +- (void)didReceiveMemoryWarning { + [super didReceiveMemoryWarning]; +} + +- (void)loadUIWebView { + UIWebView *uiWebView = [[UIWebView alloc] initWithFrame:self.view.bounds]; + [self.view addSubview:uiWebView]; + + _adjustBridge = [[AdjustBridge alloc] init]; + [_adjustBridge loadUIWebViewBridge:uiWebView webViewDelegate:self]; + [_adjustBridge augmentHybridWebView]; + + _jsContext = [uiWebView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"]; + _jsContext[@"console"][@"log"] = ^(JSValue * msg) { + NSLog(@"JavaScript %@ log message: %@", [JSContext currentContext], msg); + }; + + NSString *htmlPath = [[NSBundle mainBundle] pathForResource:@"AdjustExample-FbPixel" ofType:@"html"]; + NSString *appHtml = [NSString stringWithContentsOfFile:htmlPath encoding:NSUTF8StringEncoding error:nil]; + NSURL *baseURL = [NSURL fileURLWithPath:htmlPath]; + [uiWebView loadHTMLString:appHtml baseURL:baseURL]; +} + +- (void)callUiHandler:(id)sender { + +} + +@end + diff --git a/examples/AdjustExample-FbPixel/AdjustExample-FbPixel/WKWebViewController.h b/examples/AdjustExample-FbPixel/AdjustExample-FbPixel/WKWebViewController.h new file mode 100644 index 000000000..5ac43082b --- /dev/null +++ b/examples/AdjustExample-FbPixel/AdjustExample-FbPixel/WKWebViewController.h @@ -0,0 +1,18 @@ +// +// WKWebViewController.h +// AdjustExample-WebView +// +// Created by Uglješa Erceg on 31/05/16. +// Copyright © 2016 adjust GmbH. All rights reserved. +// + +#import +#import + +#import "AdjustBridge.h" + +@interface WKWebViewController : UINavigationController + +@property AdjustBridge *adjustBridge; + +@end diff --git a/examples/AdjustExample-FbPixel/AdjustExample-FbPixel/WKWebViewController.m b/examples/AdjustExample-FbPixel/AdjustExample-FbPixel/WKWebViewController.m new file mode 100644 index 000000000..37e1ffa41 --- /dev/null +++ b/examples/AdjustExample-FbPixel/AdjustExample-FbPixel/WKWebViewController.m @@ -0,0 +1,48 @@ +// +// WKWebViewController.m +// AdjustExample-WebView +// +// Created by Uglješa Erceg on 31/05/16. +// Copyright © 2016 adjust GmbH. All rights reserved. +// + +#import "WKWebViewController.h" + +@interface WKWebViewController () + +@end + +@implementation WKWebViewController + +- (void)viewDidLoad { + [super viewDidLoad]; +} + +- (void)viewWillAppear:(BOOL)animated { + [self loadWKWebView]; +} + +- (void)didReceiveMemoryWarning { + [super didReceiveMemoryWarning]; +} + +- (void)loadWKWebView { + WKWebView *webView = [[NSClassFromString(@"WKWebView") alloc] initWithFrame:self.view.bounds]; + webView.navigationDelegate = self; + [self.view addSubview:webView]; + + _adjustBridge = [[AdjustBridge alloc] init]; + [_adjustBridge loadWKWebViewBridge:webView wkWebViewDelegate:self]; + [_adjustBridge augmentHybridWebView]; + + NSString *htmlPath = [[NSBundle mainBundle] pathForResource:@"AdjustExample-FbPixel" ofType:@"html"]; + NSString *appHtml = [NSString stringWithContentsOfFile:htmlPath encoding:NSUTF8StringEncoding error:nil]; + NSURL *baseURL = [NSURL fileURLWithPath:htmlPath]; + [webView loadHTMLString:appHtml baseURL:baseURL]; +} + +- (void)callWkHandler:(id)sender { + +} + +@end diff --git a/examples/AdjustExample-FbPixel/AdjustExample-FbPixel/main.m b/examples/AdjustExample-FbPixel/AdjustExample-FbPixel/main.m new file mode 100644 index 000000000..84d221d25 --- /dev/null +++ b/examples/AdjustExample-FbPixel/AdjustExample-FbPixel/main.m @@ -0,0 +1,16 @@ +// +// main.m +// AdjustExample-FbPixel +// +// Created by Uglješa Erceg on 23.08.18. +// Copyright © 2018 Adjust GmbH. All rights reserved. +// + +#import +#import "AppDelegate.h" + +int main(int argc, char * argv[]) { + @autoreleasepool { + return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); + } +} diff --git a/examples/AdjustExample-WebView/AdjustExample-WebView.xcodeproj/project.pbxproj b/examples/AdjustExample-WebView/AdjustExample-WebView.xcodeproj/project.pbxproj index af3dbcb87..faed1db2b 100644 --- a/examples/AdjustExample-WebView/AdjustExample-WebView.xcodeproj/project.pbxproj +++ b/examples/AdjustExample-WebView/AdjustExample-WebView.xcodeproj/project.pbxproj @@ -7,7 +7,6 @@ objects = { /* Begin PBXBuildFile section */ - 6FA69FEB2101EA2900FCD3B5 /* AdjustBridge_JS.m in Sources */ = {isa = PBXBuildFile; fileRef = 6FA69FEA2101EA2900FCD3B5 /* AdjustBridge_JS.m */; }; 6FCC85121F2794D900D6A0ED /* ADJReachability.m in Sources */ = {isa = PBXBuildFile; fileRef = 6FCC85111F2794D600D6A0ED /* ADJReachability.m */; }; 968595F11D0B2E630011CA2B /* AdjustBridgeRegister.m in Sources */ = {isa = PBXBuildFile; fileRef = 968595F01D0B2E630011CA2B /* AdjustBridgeRegister.m */; }; 9D1082A91CFDAF8E0050568B /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D1082A81CFDAF8E0050568B /* main.m */; }; @@ -63,8 +62,6 @@ /* End PBXBuildFile section */ /* Begin PBXFileReference section */ - 6FA69FE92101EA2900FCD3B5 /* AdjustBridge_JS.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AdjustBridge_JS.h; sourceTree = ""; }; - 6FA69FEA2101EA2900FCD3B5 /* AdjustBridge_JS.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AdjustBridge_JS.m; sourceTree = ""; }; 6FCC85101F2794D600D6A0ED /* ADJReachability.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ADJReachability.h; sourceTree = ""; }; 6FCC85111F2794D600D6A0ED /* ADJReachability.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ADJReachability.m; sourceTree = ""; }; 968595EF1D0B2E630011CA2B /* AdjustBridgeRegister.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AdjustBridgeRegister.h; sourceTree = ""; }; @@ -323,8 +320,6 @@ 9D75F18F1D07463800E5D222 /* WebViewJavascriptBridge */ = { isa = PBXGroup; children = ( - 6FA69FE92101EA2900FCD3B5 /* AdjustBridge_JS.h */, - 6FA69FEA2101EA2900FCD3B5 /* AdjustBridge_JS.m */, 9D75F1871D07463800E5D222 /* WebViewJavascriptBridge.h */, 9D75F1881D07463800E5D222 /* WebViewJavascriptBridge.m */, 9D75F1891D07463800E5D222 /* WebViewJavascriptBridge_JS.h */, @@ -445,7 +440,6 @@ 9D75F19A1D07463800E5D222 /* AdjustBridge.m in Sources */, 9D449EF21E6EDD4100E7E80B /* ADJSessionFailure.m in Sources */, 9D449EDD1E6EDD4100E7E80B /* ADJActivityState.m in Sources */, - 6FA69FEB2101EA2900FCD3B5 /* AdjustBridge_JS.m in Sources */, 9D449EEB1E6EDD4100E7E80B /* ADJKeychain.m in Sources */, 9D449EE11E6EDD4100E7E80B /* ADJAdjustFactory.m in Sources */, 9D75F1971D07463800E5D222 /* WebViewJavascriptBridge_JS.m in Sources */, diff --git a/examples/AdjustExample-WebView/AdjustExample-WebView/AdjustExample-WebView.html b/examples/AdjustExample-WebView/AdjustExample-WebView/AdjustExample-WebView.html index 1e92c7fd9..e574eb5fb 100644 --- a/examples/AdjustExample-WebView/AdjustExample-WebView/AdjustExample-WebView.html +++ b/examples/AdjustExample-WebView/AdjustExample-WebView/AdjustExample-WebView.html @@ -43,6 +43,7 @@

Adjust Web View Demo

console.log('Message = ' + eventSuccess.message + '\n' + 'Timestamp = ' + eventSuccess.timestamp + '\n' + 'Adid = ' + eventSuccess.adid + '\n' + + 'CallbackId = ' + eventSuccess.callbackId + '\n' + 'Event token = ' + eventSuccess.eventToken) }) adjustConfig.setEventFailureCallback(function(eventFailure) { @@ -50,6 +51,7 @@

Adjust Web View Demo

'Timestamp = ' + eventFailure.timestamp + '\n' + 'Adid = ' + eventFailure.adid + '\n' + 'Event token = ' + eventFailure.eventToken + '\n' + + 'CallbackId = ' + eventSuccess.callbackId + '\n' + 'Will retry = ' + eventFailure.willRetry) }) adjustConfig.setSessionSuccessCallback(function(sessionSuccess) { diff --git a/examples/AdjustExample-iOS/AdjustExample-iOS/ViewControlleriOS.m b/examples/AdjustExample-iOS/AdjustExample-iOS/ViewControlleriOS.m index a86d84ac8..2a8e28864 100644 --- a/examples/AdjustExample-iOS/AdjustExample-iOS/ViewControlleriOS.m +++ b/examples/AdjustExample-iOS/AdjustExample-iOS/ViewControlleriOS.m @@ -37,6 +37,9 @@ - (void)didReceiveMemoryWarning { - (IBAction)clickTrackSimpleEvent:(UIButton *)sender { ADJEvent *event = [ADJEvent eventWithEventToken:kEventToken1]; + // Attach callback ID to event. + [event setCallbackId:@"RandomCallbackId"]; + [Adjust trackEvent:event]; }