diff --git a/Adjust.podspec b/Adjust.podspec index 9cc7f9255..8707587d0 100644 --- a/Adjust.podspec +++ b/Adjust.podspec @@ -1,11 +1,11 @@ Pod::Spec.new do |s| s.name = "Adjust" - s.version = "4.11.5" + s.version = "4.12.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.11.5" } + s.source = { :git => "https://github.com/adjust/ios_sdk.git", :tag => "v4.12.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 a8440fb59..4ca04ea44 100644 --- a/Adjust.xcodeproj/project.pbxproj +++ b/Adjust.xcodeproj/project.pbxproj @@ -22,6 +22,13 @@ /* End PBXAggregateTarget section */ /* Begin PBXBuildFile section */ + 2067002A1F18BDC700B4FDE1 /* CoreTelephony.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9601C19C1A31DD7F00A9AE21 /* CoreTelephony.framework */; settings = {ATTRIBUTES = (Weak, ); }; }; + 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 */; }; + 6FCC85051F27946100D6A0ED /* ADJReachability.m in Sources */ = {isa = PBXBuildFile; fileRef = 6FCC85031F27944600D6A0ED /* ADJReachability.m */; }; + 6FCC85081F27948C00D6A0ED /* ADJReachability.h in Headers */ = {isa = PBXBuildFile; fileRef = 6FCC85071F27948700D6A0ED /* ADJReachability.h */; }; + 6FCC85091F27949000D6A0ED /* ADJReachability.m in Sources */ = {isa = PBXBuildFile; fileRef = 6FCC85061F27948700D6A0ED /* ADJReachability.m */; }; 9601C1A01A31DD8900A9AE21 /* CoreTelephony.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9601C19C1A31DD7F00A9AE21 /* CoreTelephony.framework */; settings = {ATTRIBUTES = (Weak, ); }; }; 9601C1A31A31DE0D00A9AE21 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9601C1A11A31DE0300A9AE21 /* SystemConfiguration.framework */; settings = {ATTRIBUTES = (Weak, ); }; }; 9601CAE41C74B70600670879 /* ADJEventSuccess.h in Headers */ = {isa = PBXBuildFile; fileRef = 9601CAE21C74B70600670879 /* ADJEventSuccess.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -142,6 +149,12 @@ 9D7431F81EB9F9B700969F14 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 9D7431F61EB9F9B700969F14 /* LaunchScreen.storyboard */; }; 9DB457B01D743704004D69E8 /* ADJBackoffStrategy.m in Sources */ = {isa = PBXBuildFile; fileRef = 9DF9C8DF1D6F3CA5008E362F /* ADJBackoffStrategy.m */; }; 9DB457B11D743704004D69E8 /* ADJSdkClickHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = 9DF9C8F71D6F3CA5008E362F /* ADJSdkClickHandler.m */; }; + 9DD0E9AE1F44690B00B2A759 /* ADJUserDefaults.h in Headers */ = {isa = PBXBuildFile; fileRef = 9DD0E9AC1F44690B00B2A759 /* ADJUserDefaults.h */; }; + 9DD0E9AF1F44690B00B2A759 /* ADJUserDefaults.m in Sources */ = {isa = PBXBuildFile; fileRef = 9DD0E9AD1F44690B00B2A759 /* ADJUserDefaults.m */; }; + 9DDF243B1F7BE4A4001C1A70 /* ADJUserDefaults.m in Sources */ = {isa = PBXBuildFile; fileRef = 9DD0E9AD1F44690B00B2A759 /* ADJUserDefaults.m */; }; + 9DDF24431F7BE4BA001C1A70 /* ADJUserDefaults.h in Headers */ = {isa = PBXBuildFile; fileRef = 9DD0E9AC1F44690B00B2A759 /* ADJUserDefaults.h */; }; + 9DDF24441F7BE4DF001C1A70 /* ADJUserDefaults.m in Sources */ = {isa = PBXBuildFile; fileRef = 9DD0E9AD1F44690B00B2A759 /* ADJUserDefaults.m */; }; + 9DDF24451F7BE4E7001C1A70 /* ADJUserDefaults.h in Headers */ = {isa = PBXBuildFile; fileRef = 9DD0E9AC1F44690B00B2A759 /* ADJUserDefaults.h */; }; 9DE7C8FD1AE688DA001556E5 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9DE7C8FC1AE688DA001556E5 /* UIKit.framework */; }; 9DF9C8B31D6ED228008E362F /* ADJKeychain.h in Headers */ = {isa = PBXBuildFile; fileRef = 9DF9C8B11D6ED228008E362F /* ADJKeychain.h */; }; 9DF9C8B41D6ED228008E362F /* ADJKeychain.m in Sources */ = {isa = PBXBuildFile; fileRef = 9DF9C8B21D6ED228008E362F /* ADJKeychain.m */; }; @@ -363,6 +376,12 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 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 = ""; }; + 6FCC85031F27944600D6A0ED /* ADJReachability.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ADJReachability.m; sourceTree = ""; }; + 6FCC85061F27948700D6A0ED /* ADJReachability.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ADJReachability.m; sourceTree = ""; }; + 6FCC85071F27948700D6A0ED /* ADJReachability.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ADJReachability.h; sourceTree = ""; }; 9601C19C1A31DD7F00A9AE21 /* CoreTelephony.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreTelephony.framework; path = System/Library/Frameworks/CoreTelephony.framework; sourceTree = SDKROOT; }; 9601C1A11A31DE0300A9AE21 /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = System/Library/Frameworks/SystemConfiguration.framework; sourceTree = SDKROOT; }; 9601CAE21C74B70600670879 /* ADJEventSuccess.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ADJEventSuccess.h; sourceTree = ""; }; @@ -512,6 +531,8 @@ 9D75F1841D07460600E5D222 /* adjust_config.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = adjust_config.js; sourceTree = ""; }; 9D75F1851D07460600E5D222 /* adjust_event.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = adjust_event.js; sourceTree = ""; }; 9D75F1861D07460600E5D222 /* adjust.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = adjust.js; 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 = ""; }; 9DE7C8FC1AE688DA001556E5 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 9DF9C8B11D6ED228008E362F /* ADJKeychain.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ADJKeychain.h; sourceTree = ""; }; 9DF9C8B21D6ED228008E362F /* ADJKeychain.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ADJKeychain.m; sourceTree = ""; }; @@ -660,6 +681,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 2067002A1F18BDC700B4FDE1 /* CoreTelephony.framework in Frameworks */, 96325E89190E892000A97911 /* iAd.framework in Frameworks */, 9DE7C8FD1AE688DA001556E5 /* UIKit.framework in Frameworks */, 96325E8A190E892600A97911 /* AdSupport.framework in Frameworks */, @@ -848,6 +870,10 @@ 9DF9C8B21D6ED228008E362F /* ADJKeychain.m */, 96B6710E1D788EEC0090A023 /* ADJSessionParameters.h */, 96B6710F1D788EEC0090A023 /* ADJSessionParameters.m */, + 6FCC84F81F278CF300D6A0ED /* ADJReachability.h */, + 6FCC84F71F278CF300D6A0ED /* ADJReachability.m */, + 9DD0E9AC1F44690B00B2A759 /* ADJUserDefaults.h */, + 9DD0E9AD1F44690B00B2A759 /* ADJUserDefaults.m */, ); path = Adjust; sourceTree = ""; @@ -1045,6 +1071,8 @@ 9DF9C9071D6F3CA5008E362F /* ADJUtil.m */, 96B671121D788F4A0090A023 /* ADJSessionParameters.h */, 96B671131D788F4A0090A023 /* ADJSessionParameters.m */, + 6FCC85021F27944600D6A0ED /* ADJReachability.h */, + 6FCC85031F27944600D6A0ED /* ADJReachability.m */, 9DF9C9081D6F3CA5008E362F /* Info.plist */, ); path = Adjust; @@ -1143,6 +1171,8 @@ 9DFB06581D7470C0006D48FC /* ADJUtil.m */, 96B671161D788F7A0090A023 /* ADJSessionParameters.h */, 96B671171D788F7A0090A023 /* ADJSessionParameters.m */, + 6FCC85071F27948700D6A0ED /* ADJReachability.h */, + 6FCC85061F27948700D6A0ED /* ADJReachability.m */, 9DFB06591D7470C0006D48FC /* Info.plist */, ); path = Adjust; @@ -1175,12 +1205,14 @@ 96BCFBD11AC99246005A65C5 /* ADJAttribution.h in Headers */, 9601CAE81C74BAAE00670879 /* ADJEventFailure.h in Headers */, 9601CAE41C74B70600670879 /* ADJEventSuccess.h in Headers */, + 6FCC85011F278CF300D6A0ED /* ADJReachability.h in Headers */, 96BCFBD41AC99338005A65C5 /* NSData+ADJAdditions.h in Headers */, 968173871C3C2D36002AE1DE /* ADJSessionFailure.h in Headers */, 968173831C3C2D07002AE1DE /* ADJSessionSuccess.h in Headers */, 96BCFBD21AC99332005A65C5 /* NSString+ADJAdditions.h in Headers */, 96BCFBD31AC99336005A65C5 /* UIDevice+ADJAdditions.h in Headers */, 96BCFBD51AC9933E005A65C5 /* ADJActivityHandler.h in Headers */, + 9DD0E9AE1F44690B00B2A759 /* ADJUserDefaults.h in Headers */, 96BCFBD61AC99345005A65C5 /* ADJActivityKind.h in Headers */, 96BCFBD71AC99348005A65C5 /* ADJActivityPackage.h in Headers */, 96BCFBD81AC9934B005A65C5 /* ADJActivityState.h in Headers */, @@ -1216,6 +1248,8 @@ 9DF9C9271D6F3CA5008E362F /* ADJEventSuccess.h in Headers */, 9DF9C9371D6F3CA5008E362F /* ADJSessionFailure.h in Headers */, 9DF9C9391D6F3CA5008E362F /* ADJSessionSuccess.h in Headers */, + 9DDF24431F7BE4BA001C1A70 /* ADJUserDefaults.h in Headers */, + 6FCC85041F27945E00D6A0ED /* ADJReachability.h in Headers */, 9DF9C9111D6F3CA5008E362F /* NSData+ADJAdditions.h in Headers */, 9DF9C9131D6F3CA5008E362F /* NSString+ADJAdditions.h in Headers */, 9DF9C9151D6F3CA5008E362F /* UIDevice+ADJAdditions.h in Headers */, @@ -1255,6 +1289,8 @@ 9DFB06781D7470C0006D48FC /* ADJEventSuccess.h in Headers */, 9DFB06881D7470C0006D48FC /* ADJSessionFailure.h in Headers */, 9DFB068A1D7470C0006D48FC /* ADJSessionSuccess.h in Headers */, + 9DDF24451F7BE4E7001C1A70 /* ADJUserDefaults.h in Headers */, + 6FCC85081F27948C00D6A0ED /* ADJReachability.h in Headers */, 9DFB06621D7470C0006D48FC /* NSData+ADJAdditions.h in Headers */, 9DFB06641D7470C0006D48FC /* NSString+ADJAdditions.h in Headers */, 9DFB06661D7470C0006D48FC /* UIDevice+ADJAdditions.h in Headers */, @@ -1399,7 +1435,7 @@ 9679920518BBAE2800394606 /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 0820; + LastUpgradeCheck = 0900; ORGANIZATIONNAME = "adjust GmbH"; TargetAttributes = { 9615158E1CD2CB2C0022D336 = { @@ -1648,6 +1684,7 @@ 96E5E39318BBB48A008E7B30 /* ADJLogger.m in Sources */, 96E5E39518BBB48A008E7B30 /* ADJPackageHandler.m in Sources */, 96E5E39418BBB48A008E7B30 /* ADJPackageBuilder.m in Sources */, + 6FCC85001F278CF300D6A0ED /* ADJReachability.m in Sources */, 96E5E39618BBB48A008E7B30 /* ADJRequestHandler.m in Sources */, 96E5E39918BBB48A008E7B30 /* ADJUtil.m in Sources */, 9609BC6A19EEA55800E02303 /* ADJEvent.m in Sources */, @@ -1667,6 +1704,7 @@ 96164D731CC8FA73009431AB /* ADJSdkClickHandler.m in Sources */, 9DF9C8B41D6ED228008E362F /* ADJKeychain.m in Sources */, 96B671111D788EEC0090A023 /* ADJSessionParameters.m in Sources */, + 9DD0E9AF1F44690B00B2A759 /* ADJUserDefaults.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1718,6 +1756,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 9DDF243B1F7BE4A4001C1A70 /* ADJUserDefaults.m in Sources */, 9DF9C9121D6F3CA5008E362F /* NSData+ADJAdditions.m in Sources */, 9DF9C9141D6F3CA5008E362F /* NSString+ADJAdditions.m in Sources */, 9DF9C9161D6F3CA5008E362F /* UIDevice+ADJAdditions.m in Sources */, @@ -1730,6 +1769,7 @@ 9DF9C92C1D6F3CA5008E362F /* ADJLogger.m in Sources */, 9DF9C92E1D6F3CA5008E362F /* ADJPackageBuilder.m in Sources */, 9DF9C9301D6F3CA5008E362F /* ADJPackageHandler.m in Sources */, + 6FCC85051F27946100D6A0ED /* ADJReachability.m in Sources */, 9DF9C9321D6F3CA5008E362F /* ADJRequestHandler.m in Sources */, 9DF9C9461D6F3CA5008E362F /* ADJUtil.m in Sources */, 9DF9C9241D6F3CA5008E362F /* ADJEvent.m in Sources */, @@ -1756,6 +1796,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 9DDF24441F7BE4DF001C1A70 /* ADJUserDefaults.m in Sources */, 9DFB06631D7470C0006D48FC /* NSData+ADJAdditions.m in Sources */, 9DFB06651D7470C0006D48FC /* NSString+ADJAdditions.m in Sources */, 9DFB06671D7470C0006D48FC /* UIDevice+ADJAdditions.m in Sources */, @@ -1768,6 +1809,7 @@ 9DFB067D1D7470C0006D48FC /* ADJLogger.m in Sources */, 9DFB067F1D7470C0006D48FC /* ADJPackageBuilder.m in Sources */, 9DFB06811D7470C0006D48FC /* ADJPackageHandler.m in Sources */, + 6FCC85091F27949000D6A0ED /* ADJReachability.m in Sources */, 9DFB06831D7470C0006D48FC /* ADJRequestHandler.m in Sources */, 9DFB06971D7470C0006D48FC /* ADJUtil.m in Sources */, 9DFB06751D7470C0006D48FC /* ADJEvent.m in Sources */, @@ -1884,14 +1926,20 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 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_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_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; @@ -1929,14 +1977,20 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 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_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_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; diff --git a/Adjust.xcodeproj/xcshareddata/xcschemes/AdjustSdk.xcscheme b/Adjust.xcodeproj/xcshareddata/xcschemes/AdjustSdk.xcscheme index ee69ec69d..34092201a 100644 --- a/Adjust.xcodeproj/xcshareddata/xcschemes/AdjustSdk.xcscheme +++ b/Adjust.xcodeproj/xcshareddata/xcschemes/AdjustSdk.xcscheme @@ -1,6 +1,6 @@ @@ -36,6 +37,7 @@ buildConfiguration = "Release" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" + language = "" launchStyle = "0" useCustomWorkingDirectory = "NO" ignoresPersistentStateOnLaunch = "NO" diff --git a/Adjust.xcodeproj/xcshareddata/xcschemes/AdjustSdkTv.xcscheme b/Adjust.xcodeproj/xcshareddata/xcschemes/AdjustSdkTv.xcscheme index fb99b3218..11211fec7 100644 --- a/Adjust.xcodeproj/xcshareddata/xcschemes/AdjustSdkTv.xcscheme +++ b/Adjust.xcodeproj/xcshareddata/xcschemes/AdjustSdkTv.xcscheme @@ -1,6 +1,6 @@ @@ -36,6 +37,7 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" + language = "" launchStyle = "0" useCustomWorkingDirectory = "NO" ignoresPersistentStateOnLaunch = "NO" diff --git a/Adjust/ADJActivityHandler.h b/Adjust/ADJActivityHandler.h index 9164abef7..2d75ea28f 100644 --- a/Adjust/ADJActivityHandler.h +++ b/Adjust/ADJActivityHandler.h @@ -25,13 +25,24 @@ - (BOOL)isDisabled; - (BOOL)isOffline; - (BOOL)isOnline; -- (BOOL)isBackground; -- (BOOL)isForeground; -- (BOOL)isDelayStart; -- (BOOL)isToStartNow; -- (BOOL)isToUpdatePackages; +- (BOOL)isInBackground; +- (BOOL)isInForeground; +- (BOOL)isInDelayedStart; +- (BOOL)isNotInDelayedStart; +- (BOOL)itHasToUpdatePackages; - (BOOL)isFirstLaunch; -- (BOOL)hasSessionResponseNotProcessed; +- (BOOL)hasSessionResponseNotBeenProcessed; + +@end + +@interface ADJSavedPreLaunch : NSObject + +@property (nonatomic, strong) NSMutableArray *preLaunchActionsArray; +@property (nonatomic, copy) NSData *deviceTokenData; +@property (nonatomic, copy) NSNumber *enabled; +@property (nonatomic, assign) BOOL offline; + +- (id)init; @end @@ -41,8 +52,7 @@ - (NSString *)adid; - (id)initWithConfig:(ADJConfig *)adjustConfig -sessionParametersActionsArray:(NSArray*)sessionParametersActionsArray - deviceToken:(NSData*)deviceToken; + savedPreLaunch:(ADJSavedPreLaunch *)savedPreLaunch; - (void)applicationDidBecomeActive; - (void)applicationWillResignActive; @@ -63,7 +73,6 @@ sessionParametersActionsArray:(NSArray*)sessionParametersActionsArray - (void)setAskingAttribution:(BOOL)askingAttribution; - (BOOL)updateAttributionI:(id)selfI attribution:(ADJAttribution *)attribution; -- (void)setIadDate:(NSDate*)iAdImpressionDate withPurchaseDate:(NSDate*)appPurchaseDate; - (void)setAttributionDetails:(NSDictionary *)attributionDetails error:(NSError *)error retriesLeft:(int)retriesLeft; @@ -87,8 +96,7 @@ sessionParametersActionsArray:(NSArray*)sessionParametersActionsArray @interface ADJActivityHandler : NSObject + (id)handlerWithConfig:(ADJConfig *)adjustConfig - sessionParametersActionsArray:(NSArray*)sessionParametersActionsArray - deviceToken:(NSData*)deviceToken; + savedPreLaunch:(ADJSavedPreLaunch *)savedPreLaunch; - (void)addSessionCallbackParameterI:(ADJActivityHandler *)selfI key:(NSString *)key diff --git a/Adjust/ADJActivityHandler.m b/Adjust/ADJActivityHandler.m index 75d10595c..accae7e50 100644 --- a/Adjust/ADJActivityHandler.m +++ b/Adjust/ADJActivityHandler.m @@ -21,6 +21,7 @@ #import "NSString+ADJAdditions.h" #import "ADJSdkClickHandler.h" #import "ADJSessionParameters.h" +#import "ADJUserDefaults.h" typedef void (^activityHandlerBlockI)(ADJActivityHandler * activityHandler); @@ -57,13 +58,26 @@ - (BOOL)isEnabled { return self.enabled; } - (BOOL)isDisabled { return !self.enabled; } - (BOOL)isOffline { return self.offline; } - (BOOL)isOnline { return !self.offline; } -- (BOOL)isBackground { return self.background; } -- (BOOL)isForeground { return !self.background; } -- (BOOL)isDelayStart { return self.delayStart; } -- (BOOL)isToStartNow { return !self.delayStart; } -- (BOOL)isToUpdatePackages { return self.updatePackages; } +- (BOOL)isInBackground { return self.background; } +- (BOOL)isInForeground { return !self.background; } +- (BOOL)isInDelayedStart { return self.delayStart; } +- (BOOL)isNotInDelayedStart { return !self.delayStart; } +- (BOOL)itHasToUpdatePackages { return self.updatePackages; } - (BOOL)isFirstLaunch { return self.firstLaunch; } -- (BOOL)hasSessionResponseNotProcessed { return !self.sessionResponseProcessed; } +- (BOOL)hasSessionResponseNotBeenProcessed { return !self.sessionResponseProcessed; } + +@end + +@implementation ADJSavedPreLaunch + +- (id)init { + self = [super init]; + if (self == nil) return nil; + + // online by default + self.offline = NO; + return self; +} @end @@ -102,17 +116,14 @@ @implementation ADJActivityHandler @synthesize attribution = _attribution; + (id)handlerWithConfig:(ADJConfig *)adjustConfig - sessionParametersActionsArray:(NSArray*)sessionParametersActionsArray - deviceToken:(NSData*)deviceToken + savedPreLaunch:(ADJSavedPreLaunch *)savedPreLaunch { return [[ADJActivityHandler alloc] initWithConfig:adjustConfig - sessionParametersActionsArray:sessionParametersActionsArray - deviceToken:deviceToken]; + savedPreLaunch:savedPreLaunch]; } - (id)initWithConfig:(ADJConfig *)adjustConfig -sessionParametersActionsArray:(NSArray*)sessionParametersActionsArray - deviceToken:(NSData*)deviceToken + savedPreLaunch:(ADJSavedPreLaunch *)savedPreLaunch { self = [super init]; if (self == nil) return nil; @@ -144,15 +155,21 @@ - (id)initWithConfig:(ADJConfig *)adjustConfig self.internalState = [[ADJInternalState alloc] init]; - // enabled by default - if (self.activityState == nil) { - self.internalState.enabled = YES; - } else { - self.internalState.enabled = self.activityState.enabled; + if (savedPreLaunch.enabled != nil) { + if (savedPreLaunch.preLaunchActionsArray == nil) { + savedPreLaunch.preLaunchActionsArray = [[NSMutableArray alloc] init]; + } + + BOOL newEnabled = [savedPreLaunch.enabled boolValue]; + [savedPreLaunch.preLaunchActionsArray addObject:^(ADJActivityHandler * activityHandler){ + [activityHandler setEnabledI:activityHandler enabled:newEnabled]; + }]; } - // online by default - self.internalState.offline = NO; + // check if SDK is enabled/disabled + self.internalState.enabled = savedPreLaunch.enabled != nil ? [savedPreLaunch.enabled boolValue] : YES; + // reads offline mode from pre launch + self.internalState.offline = savedPreLaunch.offline; // in the background by default self.internalState.background = YES; // delay start not configured by default @@ -170,16 +187,20 @@ - (id)initWithConfig:(ADJConfig *)adjustConfig } // does not have the session response by default self.internalState.sessionResponseProcessed = NO; - self.deviceTokenData = deviceToken; self.internalQueue = dispatch_queue_create(kInternalQueueName, DISPATCH_QUEUE_SERIAL); [ADJUtil launchInQueue:self.internalQueue selfInject:self block:^(ADJActivityHandler * selfI) { [selfI initI:selfI - sessionParametersActionsArray:sessionParametersActionsArray]; + preLaunchActionsArray:savedPreLaunch.preLaunchActionsArray]; }]; + // self.deviceTokenData = savedPreLaunch.deviceTokenData; + if (self.activityState != nil) { + [self setDeviceToken:[ADJUserDefaults getPushToken]]; + } + [self addNotificationObserver]; return self; @@ -284,62 +305,19 @@ - (void)launchAttributionResponseTasks:(ADJAttributionResponseData *)attribution } - (void)setEnabled:(BOOL)enabled { - // compare with the saved or internal state - if (![self hasChangedState:[self isEnabled] - nextState:enabled - trueMessage:@"Adjust already enabled" - falseMessage:@"Adjust already disabled"]) - { - return; - } - - // save new enabled state in internal state - self.internalState.enabled = enabled; - - if (self.activityState == nil) { - [self updateState:!enabled - pausingMessage:@"Handlers will start as paused due to the SDK being disabled" - remainsPausedMessage:@"Handlers will still start as paused" - unPausingMessage:@"Handlers will start as active due to the SDK being enabled"]; - return; - } - - // save new enabled state in activity state - [self writeActivityStateS:self changesInStateBlock:^{ - self.activityState.enabled = enabled; - }]; - - [self updateState:!enabled - pausingMessage:@"Pausing handlers due to SDK being disabled" - remainsPausedMessage:@"Handlers remain paused" - unPausingMessage:@"Resuming handlers due to SDK being enabled"]; + [ADJUtil launchInQueue:self.internalQueue + selfInject:self + block:^(ADJActivityHandler * selfI) { + [selfI setEnabledI:selfI enabled:enabled]; + }]; } - (void)setOfflineMode:(BOOL)offline { - // compare with the internal state - if (![self hasChangedState:[self.internalState isOffline] - nextState:offline - trueMessage:@"Adjust already in offline mode" - falseMessage:@"Adjust already in online mode"]) - { - return; - } - - // save new offline state in internal state - self.internalState.offline = offline; - - if (self.activityState == nil) { - [self updateState:offline - pausingMessage:@"Handlers will start paused due to SDK being offline" - remainsPausedMessage:@"Handlers will still start as paused" - unPausingMessage:@"Handlers will start as active due to SDK being online"]; - return; - } - - [self updateState:offline - pausingMessage:@"Pausing handlers to put SDK offline mode" - remainsPausedMessage:@"Handlers remain paused" - unPausingMessage:@"Resuming handlers to put SDK in online mode"]; + [ADJUtil launchInQueue:self.internalQueue + selfInject:self + block:^(ADJActivityHandler * selfI) { + [selfI setOfflineModeI:selfI offline:offline]; + }]; } - (BOOL)isEnabled { @@ -353,50 +331,6 @@ - (NSString *)adid { return self.activityState.adid; } -- (BOOL)hasChangedState:(BOOL)previousState - nextState:(BOOL)nextState - trueMessage:(NSString *)trueMessage - falseMessage:(NSString *)falseMessage -{ - if (previousState != nextState) { - return YES; - } - - if (previousState) { - [self.logger debug:trueMessage]; - } else { - [self.logger debug:falseMessage]; - } - - return NO; -} - -- (void)updateState:(BOOL)pausingState - pausingMessage:(NSString *)pausingMessage -remainsPausedMessage:(NSString *)remainsPausedMessage - unPausingMessage:(NSString *)unPausingMessage -{ - // it is changing from an active state to a pause state - if (pausingState) { - [self.logger info:pausingMessage]; - } - // check if it's remaining in a pause state - else if ([self pausedI:self sdkClickHandlerOnly:NO]) { - // including the sdk click handler - if ([self pausedI:self sdkClickHandlerOnly:YES]) { - [self.logger info:remainsPausedMessage]; - } else { - // or except it - [self.logger info:[remainsPausedMessage stringByAppendingString:@", except the Sdk Click Handler"]]; - } - } else { - // it is changing from a pause state to an active state - [self.logger info:unPausingMessage]; - } - - [self updateHandlersStatusAndSend]; -} - - (void)appWillOpenUrl:(NSURL*)url { [ADJUtil launchInQueue:self.internalQueue selfInject:self @@ -413,16 +347,6 @@ - (void)setDeviceToken:(NSData *)deviceToken { }]; } -- (void)setIadDate:(NSDate *)iAdImpressionDate - withPurchaseDate:(NSDate *)appPurchaseDate -{ - [ADJUtil launchInQueue:self.internalQueue - selfInject:self - block:^(ADJActivityHandler * selfI) { - [selfI setIadDateI:selfI iAdImpressionDate:iAdImpressionDate withPurchaseDate:appPurchaseDate]; - }]; -} - - (void)setAttributionDetails:(NSDictionary *)attributionDetails error:(NSError *)error retriesLeft:(int)retriesLeft @@ -485,6 +409,10 @@ - (void)setAttributionDetails:(NSDictionary *)attributionDetails - (void)sendIad3ClickPackage:(ADJActivityHandler *)selfI attributionDetails:(NSDictionary *)attributionDetails { + if (![selfI isEnabledI:selfI]) { + return; + } + double now = [NSDate.date timeIntervalSince1970]; if (selfI.activityState != nil) { double lastInterval = now - selfI.activityState.lastActivity; @@ -494,11 +422,12 @@ - (void)sendIad3ClickPackage:(ADJActivityHandler *)selfI initWithDeviceInfo:selfI.deviceInfo activityState:selfI.activityState config:selfI.adjustConfig + sessionParameters:self.sessionParameters createdAt:now]; clickBuilder.attributionDetails = attributionDetails; - ADJActivityPackage *clickPackage = [clickBuilder buildClickPackage:@"iad3" sessionParameters:selfI.sessionParameters]; + ADJActivityPackage *clickPackage = [clickBuilder buildClickPackage:@"iad3"]; [selfI.sdkClickHandler sendSdkClick:clickPackage]; } @@ -511,16 +440,11 @@ - (void)saveAttributionDetailsI:(ADJActivityHandler *)selfI } - (void)setAskingAttribution:(BOOL)askingAttribution { - [self writeActivityStateS:self changesInStateBlock:^{ - self.activityState.askingAttribution = askingAttribution; - }]; -} - -- (void)updateHandlersStatusAndSend { [ADJUtil launchInQueue:self.internalQueue selfInject:self block:^(ADJActivityHandler * selfI) { - [selfI updateHandlersStatusAndSendI:selfI]; + [selfI setAskingAttributionI:selfI + askingAttribution:askingAttribution]; }]; } @@ -624,6 +548,12 @@ - (void)teardown:(BOOL)deleteState [self teardownAttributionS:deleteState]; [self teardownAllSessionParametersS:deleteState]; + if (deleteState) { + [ADJUserDefaults clearAdjustStuff]; + } + + [ADJUtil teardown]; + self.internalQueue = nil; self.packageHandler = nil; self.attributionHandler = nil; @@ -640,7 +570,7 @@ - (void)teardown:(BOOL)deleteState #pragma mark - internal - (void)initI:(ADJActivityHandler *)selfI -sessionParametersActionsArray:(NSArray*)sessionParametersActionsArray +preLaunchActionsArray:(NSArray*)preLaunchActionsArray { // get session values kSessionInterval = ADJAdjustFactory.sessionInterval; @@ -670,6 +600,12 @@ - (void)initI:(ADJActivityHandler *)selfI if (selfI.activityState != nil) { [selfI setDeviceToken:selfI.deviceTokenData]; } + } else { + if (selfI.activityState != nil) { + NSData *deviceToken = [ADJUserDefaults getPushToken]; + + [selfI setDeviceToken:deviceToken]; + } } selfI.foregroundTimer = [ADJTimerCycle timerWithBlock:^{ @@ -705,7 +641,7 @@ - (void)initI:(ADJActivityHandler *)selfI sdkClickHandlerOnly:NO]]; // update session parameters in package queue - if ([selfI isToUpdatePackagesI:selfI]) { + if ([selfI itHasToUpdatePackagesI:selfI]) { [selfI updatePackagesI:selfI]; } @@ -714,6 +650,7 @@ - (void)initI:(ADJActivityHandler *)selfI initWithDeviceInfo:selfI.deviceInfo activityState:selfI.activityState config:selfI.adjustConfig + sessionParameters:selfI.sessionParameters createdAt:now]; ADJActivityPackage *attributionPackage = [attributionBuilder buildAttributionPackage]; selfI.attributionHandler = [ADJAdjustFactory attributionHandlerForActivityHandler:selfI @@ -721,13 +658,13 @@ - (void)initI:(ADJActivityHandler *)selfI startsSending:[selfI toSendI:selfI sdkClickHandlerOnly:NO]]; - selfI.sdkClickHandler = [ADJAdjustFactory sdkClickHandlerWithStartsPaused:selfI - startsSending:[selfI toSendI:selfI - sdkClickHandlerOnly:YES]]; + selfI.sdkClickHandler = [ADJAdjustFactory sdkClickHandlerForActivityHandler:selfI + startsSending:[selfI toSendI:selfI + sdkClickHandlerOnly:YES]]; [[UIDevice currentDevice] adjSetIad:selfI triesV3Left:kTryIadV3]; - [selfI sessionParametersActionsI:selfI sessionParametersActionsArray:sessionParametersActionsArray]; + [selfI preLaunchActionsI:selfI preLaunchActionsArray:preLaunchActionsArray]; [selfI startI:selfI]; } @@ -752,14 +689,23 @@ - (void)processSessionI:(ADJActivityHandler *)selfI { // very first session if (selfI.activityState == nil) { selfI.activityState = [[ADJActivityState alloc] init]; - selfI.activityState.sessionCount = 1; // this is the first session - selfI.activityState.deviceToken = [ADJUtil convertDeviceToken:selfI.deviceTokenData]; - [selfI transferSessionPackageI:selfI now:now]; + // selfI.activityState.deviceToken = [ADJUtil convertDeviceToken:selfI.deviceTokenData]; + selfI.activityState.deviceToken = [ADJUtil convertDeviceToken:[ADJUserDefaults getPushToken]]; + + // track the first session package only if it's enabled + if ([selfI.internalState isEnabled]) { + selfI.activityState.sessionCount = 1; // this is the first session + [selfI transferSessionPackageI:selfI now:now]; + } + [selfI.activityState resetSessionAttributes:now]; selfI.activityState.enabled = [selfI.internalState isEnabled]; - selfI.activityState.updatePackages = [selfI.internalState isToUpdatePackages]; + selfI.activityState.updatePackages = [selfI.internalState itHasToUpdatePackages]; + [selfI writeActivityStateI:selfI]; + [ADJUserDefaults removePushToken]; + return; } @@ -773,12 +719,7 @@ - (void)processSessionI:(ADJActivityHandler *)selfI { // new session if (lastInterval > kSessionInterval) { - selfI.activityState.sessionCount++; - selfI.activityState.lastInterval = lastInterval; - - [selfI transferSessionPackageI:selfI now:now]; - [selfI.activityState resetSessionAttributes:now]; - [selfI writeActivityStateI:selfI]; + [self trackNewSessionI:now withActivityHandler:selfI]; return; } @@ -797,14 +738,26 @@ - (void)processSessionI:(ADJActivityHandler *)selfI { [selfI.logger verbose:@"Time span since last activity too short for a new subsession"]; } +- (void)trackNewSessionI:(double)now withActivityHandler:(ADJActivityHandler *)selfI { + double lastInterval = now - selfI.activityState.lastActivity; + + selfI.activityState.sessionCount++; + selfI.activityState.lastInterval = lastInterval; + + [selfI transferSessionPackageI:selfI now:now]; + [selfI.activityState resetSessionAttributes:now]; + [selfI writeActivityStateI:selfI]; +} + - (void)transferSessionPackageI:(ADJActivityHandler *)selfI now:(double)now { ADJPackageBuilder *sessionBuilder = [[ADJPackageBuilder alloc] initWithDeviceInfo:selfI.deviceInfo activityState:selfI.activityState config:selfI.adjustConfig + sessionParameters:selfI.sessionParameters createdAt:now]; - ADJActivityPackage *sessionPackage = [sessionBuilder buildSessionPackage:selfI.sessionParameters isInDelay:[selfI.internalState isDelayStart]]; + ADJActivityPackage *sessionPackage = [sessionBuilder buildSessionPackage:[selfI.internalState isInDelayedStart]]; [selfI.packageHandler addPackage:sessionPackage]; [selfI.packageHandler sendFirstPackage]; } @@ -815,7 +768,7 @@ - (void)checkAttributionStateI:(ADJActivityHandler *)selfI { // if it's the first launch if ([selfI.internalState isFirstLaunch]) { // and it hasn't received the session response - if ([selfI.internalState hasSessionResponseNotProcessed]) { + if ([selfI.internalState hasSessionResponseNotBeenProcessed]) { return; } } @@ -856,8 +809,10 @@ - (void)eventI:(ADJActivityHandler *)selfI initWithDeviceInfo:selfI.deviceInfo activityState:selfI.activityState config:selfI.adjustConfig + sessionParameters:selfI.sessionParameters createdAt:now]; - ADJActivityPackage *eventPackage = [eventBuilder buildEventPackage:event sessionParameters:selfI.sessionParameters isInDelay:[selfI.internalState isDelayStart]]; + ADJActivityPackage *eventPackage = [eventBuilder buildEventPackage:event + isInDelay:[selfI.internalState isInDelayedStart]]; [selfI.packageHandler addPackage:eventPackage]; if (selfI.adjustConfig.eventBufferingEnabled) { @@ -867,7 +822,7 @@ - (void)eventI:(ADJActivityHandler *)selfI } // if it is in the background and it can send, start the background timer - if (selfI.adjustConfig.sendInBackground && [selfI.internalState isBackground]) { + if (selfI.adjustConfig.sendInBackground && [selfI.internalState isInBackground]) { [selfI startBackgroundTimerI:selfI]; } @@ -906,6 +861,11 @@ - (void)launchSessionResponseTasksI:(ADJActivityHandler *)selfI BOOL toLaunchAttributionDelegate = [selfI updateAttributionI:selfI attribution:sessionResponseData.attribution]; + // mark install as tracked on success + if (sessionResponseData.success) { + [ADJUserDefaults setInstallTracked]; + } + // session success callback if (sessionResponseData.success && [selfI.adjustDelegate respondsToSelector:@selector(adjustSessionTrackingSucceeded:)]) @@ -933,7 +893,7 @@ - (void)launchSessionResponseTasksI:(ADJActivityHandler *)selfI withObject:sessionResponseData.attribution]; } - self.internalState.sessionResponseProcessed = YES; + selfI.internalState.sessionResponseProcessed = YES; } - (void)launchSdkClickResponseTasksI:(ADJActivityHandler *)selfI @@ -1032,12 +992,140 @@ - (BOOL)updateAttributionI:(ADJActivityHandler *)selfI return YES; } +- (void)setEnabledI:(ADJActivityHandler *)selfI enabled:(BOOL)enabled { + // compare with the saved or internal state + if (![selfI hasChangedStateI:selfI + previousState:[selfI isEnabled] + nextState:enabled + trueMessage:@"Adjust already enabled" + falseMessage:@"Adjust already disabled"]) { + return; + } + + // save new enabled state in internal state + selfI.internalState.enabled = enabled; + + if (selfI.activityState == nil) { + [selfI checkStatusI:selfI + pausingState:!enabled + pausingMessage:@"Handlers will start as paused due to the SDK being disabled" + remainsPausedMessage:@"Handlers will still start as paused" + unPausingMessage:@"Handlers will start as active due to the SDK being enabled"]; + return; + } + + // Check if upon enabling install has been tracked. + if (enabled) { + if (![ADJUserDefaults getInstallTracked]) { + double now = [NSDate.date timeIntervalSince1970]; + [self trackNewSessionI:now withActivityHandler:selfI]; + } + + NSData *deviceToken = [ADJUserDefaults getPushToken]; + + if (deviceToken != nil && ![selfI.activityState.deviceToken isEqualToString:[ADJUtil convertDeviceToken:deviceToken]]) { + [self setDeviceToken:deviceToken]; + } + } + + // save new enabled state in activity state + selfI.activityState.enabled = enabled; + [selfI writeActivityStateI:selfI]; + + [selfI checkStatusI:selfI + pausingState:!enabled + pausingMessage:@"Pausing handlers due to SDK being disabled" + remainsPausedMessage:@"Handlers remain paused" + unPausingMessage:@"Resuming handlers due to SDK being enabled"]; +} + +- (void)setOfflineModeI:(ADJActivityHandler *)selfI + offline:(BOOL)offline { + // compare with the internal state + if (![selfI hasChangedStateI:selfI + previousState:[selfI.internalState isOffline] + nextState:offline + trueMessage:@"Adjust already in offline mode" + falseMessage:@"Adjust already in online mode"]) + { + return; + } + + // save new offline state in internal state + selfI.internalState.offline = offline; + + if (selfI.activityState == nil) { + [selfI checkStatusI:selfI + pausingState:offline + pausingMessage:@"Handlers will start paused due to SDK being offline" + remainsPausedMessage:@"Handlers will still start as paused" + unPausingMessage:@"Handlers will start as active due to SDK being online"]; + return; + } + + [selfI checkStatusI:selfI + pausingState:offline + pausingMessage:@"Pausing handlers to put SDK offline mode" + remainsPausedMessage:@"Handlers remain paused" + unPausingMessage:@"Resuming handlers to put SDK in online mode"]; +} + +- (BOOL)hasChangedStateI:(ADJActivityHandler *)selfI + previousState:(BOOL)previousState + nextState:(BOOL)nextState + trueMessage:(NSString *)trueMessage + falseMessage:(NSString *)falseMessage +{ + if (previousState != nextState) { + return YES; + } + + if (previousState) { + [selfI.logger debug:trueMessage]; + } else { + [selfI.logger debug:falseMessage]; + } + + return NO; +} + +- (void)checkStatusI:(ADJActivityHandler *)selfI + pausingState:(BOOL)pausingState + pausingMessage:(NSString *)pausingMessage +remainsPausedMessage:(NSString *)remainsPausedMessage + unPausingMessage:(NSString *)unPausingMessage +{ + // it is changing from an active state to a pause state + if (pausingState) { + [selfI.logger info:pausingMessage]; + } + // check if it's remaining in a pause state + else if ([selfI pausedI:selfI sdkClickHandlerOnly:NO]) { + // including the sdk click handler + if ([selfI pausedI:selfI sdkClickHandlerOnly:YES]) { + [selfI.logger info:remainsPausedMessage]; + } else { + // or except it + [selfI.logger info:[remainsPausedMessage stringByAppendingString:@", except the Sdk Click Handler"]]; + } + } else { + // it is changing from a pause state to an active state + [selfI.logger info:unPausingMessage]; + } + + [selfI updateHandlersStatusAndSendI:selfI]; +} + - (void)appWillOpenUrlI:(ADJActivityHandler *)selfI url:(NSURL *)url { if ([ADJUtil isNull:url]) { return; } + if (![selfI isEnabledI:selfI]) { + return; + } + if ([[url absoluteString] length] == 0) { return; } @@ -1062,13 +1150,14 @@ - (void)appWillOpenUrlI:(ADJActivityHandler *)selfI initWithDeviceInfo:selfI.deviceInfo activityState:selfI.activityState config:selfI.adjustConfig + sessionParameters:selfI.sessionParameters createdAt:now]; clickBuilder.deeplinkParameters = adjustDeepLinks; clickBuilder.attribution = deeplinkAttribution; clickBuilder.clickTime = [NSDate date]; clickBuilder.deeplink = [url absoluteString]; - ADJActivityPackage *clickPackage = [clickBuilder buildClickPackage:@"deeplink" sessionParameters:selfI.sessionParameters]; + ADJActivityPackage *clickPackage = [clickBuilder buildClickPackage:@"deeplink"]; [selfI.sdkClickHandler sendSdkClick:clickPackage]; } @@ -1129,6 +1218,10 @@ - (BOOL)trySetAttributionDeeplink:(ADJAttribution *)deeplinkAttribution - (void)setDeviceTokenI:(ADJActivityHandler *)selfI deviceToken:(NSData *)deviceToken { + if (![selfI isEnabledI:selfI]) { + return; + } + NSString *deviceTokenString = [ADJUtil convertDeviceToken:deviceToken]; if (deviceTokenString == nil) { @@ -1145,49 +1238,26 @@ - (void)setDeviceTokenI:(ADJActivityHandler *)selfI // send info package double now = [NSDate.date timeIntervalSince1970]; - ADJPackageBuilder * infoBuilder = [[ADJPackageBuilder alloc] - initWithDeviceInfo:selfI.deviceInfo - activityState:selfI.activityState - config:selfI.adjustConfig - createdAt:now]; + ADJPackageBuilder *infoBuilder = [[ADJPackageBuilder alloc] initWithDeviceInfo:selfI.deviceInfo + activityState:selfI.activityState + config:selfI.adjustConfig + sessionParameters:selfI.sessionParameters + createdAt:now]; - ADJActivityPackage * infoPackage = [infoBuilder buildInfoPackage:@"push"]; + ADJActivityPackage *infoPackage = [infoBuilder buildInfoPackage:@"push"]; [selfI.packageHandler addPackage:infoPackage]; - [selfI.packageHandler sendFirstPackage]; -} -- (void)setIadDateI:(ADJActivityHandler *)selfI - iAdImpressionDate:(NSDate *)iAdImpressionDate - withPurchaseDate:(NSDate *)appPurchaseDate -{ - if (iAdImpressionDate == nil) { - [self.logger debug:@"iAdImpressionDate not received"]; - return; - } - - [self.logger debug:@"iAdImpressionDate received: %@", iAdImpressionDate]; + // if push token was cached, remove it + [ADJUserDefaults removePushToken]; - double now = [NSDate.date timeIntervalSince1970]; - if (selfI.activityState != nil) { - double lastInterval = now - selfI.activityState.lastActivity; - selfI.activityState.lastInterval = lastInterval; + if (selfI.adjustConfig.eventBufferingEnabled) { + [selfI.logger info:@"Buffered info %@", infoPackage.suffix]; + } else { + [selfI.packageHandler sendFirstPackage]; } - - ADJPackageBuilder *clickBuilder = [[ADJPackageBuilder alloc] - initWithDeviceInfo:self.deviceInfo - activityState:self.activityState - config:self.adjustConfig - createdAt:now]; - - clickBuilder.purchaseTime = appPurchaseDate; - clickBuilder.clickTime = iAdImpressionDate; - - ADJActivityPackage *clickPackage = [clickBuilder buildClickPackage:@"iad" sessionParameters:selfI.sessionParameters]; - [self.sdkClickHandler sendSdkClick:clickPackage]; } - #pragma mark - private - (BOOL)isEnabledI:(ADJActivityHandler *)selfI { @@ -1198,11 +1268,11 @@ - (BOOL)isEnabledI:(ADJActivityHandler *)selfI { } } -- (BOOL)isToUpdatePackagesI:(ADJActivityHandler *)selfI { +- (BOOL)itHasToUpdatePackagesI:(ADJActivityHandler *)selfI { if (selfI.activityState != nil) { return selfI.activityState.updatePackages; } else { - return [selfI.internalState isToUpdatePackages]; + return [selfI.internalState itHasToUpdatePackages]; } } @@ -1230,21 +1300,12 @@ - (BOOL)updateActivityStateI:(ADJActivityHandler *)selfI } - (void)writeActivityStateI:(ADJActivityHandler *)selfI -{ - [selfI writeActivityStateS:selfI changesInStateBlock:nil]; -} - -- (void)writeActivityStateS:(ADJActivityHandler *)selfS - changesInStateBlock:(void (^)(void))changesInStateBlock { @synchronized ([ADJActivityState class]) { - if (selfS.activityState == nil) { + if (selfI.activityState == nil) { return; } - if (changesInStateBlock != nil) { - changesInStateBlock(); - } - [ADJUtil writeObject:selfS.activityState filename:kActivityStateFilename objectName:@"Activity state"]; + [ADJUtil writeObject:selfI.activityState fileName:kActivityStateFilename objectName:@"Activity state"]; } } @@ -1255,7 +1316,7 @@ - (void)teardownActivityStateS:(BOOL)deleteState return; } if (deleteState) { - [ADJUtil deleteFile:kActivityStateFilename]; + [ADJUtil deleteFileWithName:kActivityStateFilename]; } self.activityState = nil; } @@ -1266,7 +1327,7 @@ - (void)writeAttributionI:(ADJActivityHandler *)selfI { if (selfI.attribution == nil) { return; } - [ADJUtil writeObject:selfI.attribution filename:kAttributionFilename objectName:@"Attribution"]; + [ADJUtil writeObject:selfI.attribution fileName:kAttributionFilename objectName:@"Attribution"]; } } @@ -1277,7 +1338,7 @@ - (void)teardownAttributionS:(BOOL)deleteState return; } if (deleteState) { - [ADJUtil deleteFile:kAttributionFilename]; + [ADJUtil deleteFileWithName:kAttributionFilename]; } self.attribution = nil; } @@ -1302,7 +1363,7 @@ - (void)writeSessionCallbackParametersI:(ADJActivityHandler *)selfI { return; } [ADJUtil writeObject:selfI.sessionParameters.callbackParameters - filename:kSessionCallbackParametersFilename + fileName:kSessionCallbackParametersFilename objectName:@"Session Callback parameters"]; } } @@ -1313,7 +1374,7 @@ - (void)writeSessionPartnerParametersI:(ADJActivityHandler *)selfI { return; } [ADJUtil writeObject:selfI.sessionParameters.partnerParameters - filename:kSessionPartnerParametersFilename + fileName:kSessionPartnerParametersFilename objectName:@"Session Partner parameters"]; } } @@ -1324,8 +1385,8 @@ - (void)teardownAllSessionParametersS:(BOOL)deleteState { return; } if (deleteState) { - [ADJUtil deleteFile:kSessionCallbackParametersFilename]; - [ADJUtil deleteFile:kSessionPartnerParametersFilename]; + [ADJUtil deleteFileWithName:kSessionCallbackParametersFilename]; + [ADJUtil deleteFileWithName:kSessionPartnerParametersFilename]; } [self.sessionParameters.callbackParameters removeAllObjects]; [self.sessionParameters.partnerParameters removeAllObjects]; @@ -1355,6 +1416,14 @@ - (void)updateHandlersStatusAndSendI:(ADJActivityHandler *)selfI { [selfI resumeSendingI:selfI]; + // try to send if it's the first launch and it hasn't received the session response + // even if event buffering is enabled + if ([selfI.internalState isFirstLaunch] && + [selfI.internalState hasSessionResponseNotBeenProcessed]) + { + [selfI.packageHandler sendFirstPackage]; + } + // try to send if (!selfI.adjustConfig.eventBufferingEnabled) { [selfI.packageHandler sendFirstPackage]; @@ -1394,7 +1463,7 @@ - (BOOL)pausedI:(ADJActivityHandler *)selfI // other handlers are paused if either: return [selfI.internalState isOffline] || // it's offline ![selfI isEnabledI:selfI] || // is disabled - [selfI.internalState isDelayStart]; // is in delayed start + [selfI.internalState isInDelayedStart]; // is in delayed start } - (BOOL)toSendI:(ADJActivityHandler *)selfI { @@ -1415,7 +1484,14 @@ - (BOOL)toSendI:(ADJActivityHandler *)selfI } // doesn't have the option -> depends on being on the background/foreground - return [selfI.internalState isForeground]; + return [selfI.internalState isInForeground]; +} + +- (void)setAskingAttributionI:(ADJActivityHandler *)selfI + askingAttribution:(BOOL)askingAttribution +{ + selfI.activityState.askingAttribution = askingAttribution; + [selfI writeActivityStateI:selfI]; } # pragma mark - timer @@ -1484,12 +1560,12 @@ - (void)backgroundTimerFiredI:(ADJActivityHandler *)selfI { #pragma mark - delay - (void)delayStartI:(ADJActivityHandler *)selfI { // it's not configured to start delayed or already finished - if ([selfI.internalState isToStartNow]) { + if ([selfI.internalState isNotInDelayedStart]) { return; } // the delay has already started - if ([selfI isToUpdatePackagesI:selfI]) { + if ([selfI itHasToUpdatePackagesI:selfI]) { return; } @@ -1519,7 +1595,7 @@ - (void)delayStartI:(ADJActivityHandler *)selfI { } - (void)sendFirstPackagesI:(ADJActivityHandler *)selfI { - if ([selfI.internalState isToStartNow]) { + if ([selfI.internalState isNotInDelayedStart]) { [selfI.logger info:@"Start delay expired or never configured"]; return; } @@ -1672,13 +1748,13 @@ - (void)resetSessionPartnerParametersI:(ADJActivityHandler *)selfI { [selfI writeSessionPartnerParametersI:selfI]; } -- (void)sessionParametersActionsI:(ADJActivityHandler *)selfI - sessionParametersActionsArray:(NSArray*)sessionParametersActionsArray +- (void)preLaunchActionsI:(ADJActivityHandler *)selfI + preLaunchActionsArray:(NSArray*)preLaunchActionsArray { - if (sessionParametersActionsArray == nil) { + if (preLaunchActionsArray == nil) { return; } - for (activityHandlerBlockI activityHandlerActionI in sessionParametersActionsArray) { + for (activityHandlerBlockI activityHandlerActionI in preLaunchActionsArray) { activityHandlerActionI(selfI); } } diff --git a/Adjust/ADJActivityPackage.m b/Adjust/ADJActivityPackage.m index 23fa4e543..0fb097f47 100644 --- a/Adjust/ADJActivityPackage.m +++ b/Adjust/ADJActivityPackage.m @@ -15,6 +15,7 @@ @implementation ADJActivityPackage - (NSString *)extendedString { NSMutableString *builder = [NSMutableString string]; + NSArray *excludedKeys = @[@"secret_id", @"app_secret"]; [builder appendFormat:@"Path: %@\n", self.path]; [builder appendFormat:@"ClientSdk: %@\n", self.clientSdk]; @@ -26,7 +27,12 @@ - (NSString *)extendedString { [builder appendFormat:@"Parameters:"]; for (NSUInteger i = 0; i < keyCount; i++) { - NSString *key = (NSString*)[sortedKeys objectAtIndex:i]; + NSString *key = (NSString *)[sortedKeys objectAtIndex:i]; + + if ([excludedKeys containsObject:key]) { + continue; + } + NSString *value = [self.parameters objectForKey:key]; [builder appendFormat:@"\n\t\t%-22s %@", [key UTF8String], value]; diff --git a/Adjust/ADJAdditions/NSString+ADJAdditions.h b/Adjust/ADJAdditions/NSString+ADJAdditions.h index 6ec8a711a..f3a14dfa3 100644 --- a/Adjust/ADJAdditions/NSString+ADJAdditions.h +++ b/Adjust/ADJAdditions/NSString+ADJAdditions.h @@ -9,7 +9,9 @@ @interface NSString(ADJAdditions) +- (NSString *)adjMd5; - (NSString *)adjSha1; +- (NSString *)adjSha256; - (NSString *)adjTrim; - (NSString *)adjUrlEncode; - (NSString *)adjUrlDecode; diff --git a/Adjust/ADJAdditions/NSString+ADJAdditions.m b/Adjust/ADJAdditions/NSString+ADJAdditions.m index 90cf1bdad..b14e6938d 100644 --- a/Adjust/ADJAdditions/NSString+ADJAdditions.m +++ b/Adjust/ADJAdditions/NSString+ADJAdditions.m @@ -43,6 +43,18 @@ - (NSString *)adjRemoveColons { return [self stringByReplacingOccurrencesOfString:@":" withString:@""]; } +- (NSString *)adjMd5 { + const char *cStr = [self UTF8String]; + unsigned char digest[CC_MD5_DIGEST_LENGTH]; + CC_MD5(cStr, (CC_LONG)strlen(cStr), digest); + + NSMutableString *output = [NSMutableString stringWithCapacity:CC_MD5_DIGEST_LENGTH * 2]; + for(int i = 0; i < CC_MD5_DIGEST_LENGTH; i++) { + [output appendFormat:@"%02x", digest[i]]; + } + return output; +} + - (NSString *)adjSha1 { NSData *data = [self dataUsingEncoding:NSUTF8StringEncoding]; uint8_t digest[CC_SHA1_DIGEST_LENGTH]; @@ -58,6 +70,19 @@ - (NSString *)adjSha1 { return output; } +- (NSString *)adjSha256 { + const char* str = [self UTF8String]; + unsigned char result[CC_SHA256_DIGEST_LENGTH]; + CC_SHA256(str, (CC_LONG)strlen(str), result); + + NSMutableString *ret = [NSMutableString stringWithCapacity:CC_SHA256_DIGEST_LENGTH*2]; + for(int i = 0; i iad v2 + // if no tries for iad v3 left, stop trying if (triesV3Left == 0) { - [logger warn:@"Reached limit number of retry for iAd v3. Trying iAd v2"]; - [self adjSetIadWithDates:activityHandler ADClientSharedClientInstance:ADClientSharedClientInstance]; + [logger warn:@"Reached limit number of retry for iAd v3"]; return; } @@ -179,10 +186,10 @@ - (void)adjSetIad:(ADJActivityHandler *)activityHandler ADClientSharedClientInstance:ADClientSharedClientInstance retriesLeft:(triesV3Left - 1)]; - // if iad v3 not available -> iad v2 + // if iad v3 not available if (!isIadV3Avaliable) { - [logger warn:@"iAd v3 not available. Trying iAd v2"]; - [self adjSetIadWithDates:activityHandler ADClientSharedClientInstance:ADClientSharedClientInstance]; + [logger warn:@"iAd v3 not available"]; + return; } #pragma clang diagnostic pop #endif @@ -209,22 +216,4 @@ - (BOOL)adjSetIadWithDetails:(ADJActivityHandler *)activityHandler return YES; } -- (BOOL)adjSetIadWithDates:(ADJActivityHandler *)activityHandler -ADClientSharedClientInstance:(id)ADClientSharedClientInstance -{ - SEL iadDateSelector = NSSelectorFromString(@"lookupAdConversionDetails:"); - - if (![ADClientSharedClientInstance respondsToSelector:iadDateSelector]) { - return NO; - } -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Warc-performSelector-leaks" - [ADClientSharedClientInstance performSelector:iadDateSelector - withObject:^(NSDate *appPurchaseDate, NSDate *iAdImpressionDate) { - [activityHandler setIadDate:iAdImpressionDate withPurchaseDate:appPurchaseDate]; - }]; - -#pragma clang diagnostic pop - return YES; -} @end diff --git a/Adjust/ADJAdjustFactory.h b/Adjust/ADJAdjustFactory.h index 02a6a9fbc..f134db80b 100644 --- a/Adjust/ADJAdjustFactory.h +++ b/Adjust/ADJAdjustFactory.h @@ -22,10 +22,9 @@ startsSending:(BOOL)startsSending; + (id)requestHandlerForPackageHandler:(id)packageHandler; + (id)activityHandlerWithConfig:(ADJConfig *)adjustConfig - sessionParametersActionsArray:(NSArray*)sessionParametersActionsArray - deviceToken:(NSData*)deviceToken; -+ (id)sdkClickHandlerWithStartsPaused:(id)activityHandler - startsSending:(BOOL)startsSending; + savedPreLaunch:(ADJSavedPreLaunch *)savedPreLaunch; ++ (id)sdkClickHandlerForActivityHandler:(id)activityHandler + startsSending:(BOOL)startsSending; + (id)logger; + (double)sessionInterval; diff --git a/Adjust/ADJAdjustFactory.m b/Adjust/ADJAdjustFactory.m index a2de8f731..9ba60bef5 100644 --- a/Adjust/ADJAdjustFactory.m +++ b/Adjust/ADJAdjustFactory.m @@ -43,18 +43,15 @@ @implementation ADJAdjustFactory } + (id)activityHandlerWithConfig:(ADJConfig *)adjustConfig - sessionParametersActionsArray:(NSArray*)sessionParametersActionsArray - deviceToken:(NSData*)deviceToken + savedPreLaunch:(ADJSavedPreLaunch *)savedPreLaunch { if (internalActivityHandler == nil) { return [ADJActivityHandler handlerWithConfig:adjustConfig - sessionParametersActionsArray:sessionParametersActionsArray - deviceToken:deviceToken + savedPreLaunch:savedPreLaunch ]; } return [internalActivityHandler initWithConfig:adjustConfig - sessionParametersActionsArray:sessionParametersActionsArray - deviceToken:deviceToken]; + savedPreLaunch:savedPreLaunch]; } + (id)logger { @@ -122,8 +119,8 @@ + (ADJBackoffStrategy *)sdkClickHandlerBackoffStrategy { startsSending:startsSending]; } -+ (id)sdkClickHandlerWithStartsPaused:(id)activityHandler - startsSending:(BOOL)startsSending ++ (id)sdkClickHandlerForActivityHandler:(id)activityHandler + startsSending:(BOOL)startsSending { if (internalSdkClickHandler == nil) { return [ADJSdkClickHandler handlerWithActivityHandler:activityHandler startsSending:startsSending]; diff --git a/Adjust/ADJAttributionHandler.m b/Adjust/ADJAttributionHandler.m index 5f506f8b6..1a9544c4f 100644 --- a/Adjust/ADJAttributionHandler.m +++ b/Adjust/ADJAttributionHandler.m @@ -23,12 +23,10 @@ @interface ADJAttributionHandler() @property (nonatomic, weak) id logger; @property (nonatomic, strong) ADJTimerOnce *attributionTimer; @property (nonatomic, strong) ADJActivityPackage * attributionPackage; -@property (nonatomic, assign) BOOL paused; +@property (atomic, assign) BOOL paused; @end -static const double kRequestTimeout = 60; // 60 seconds - @implementation ADJAttributionHandler + (id)handlerWithActivityHandler:(id)activityHandler @@ -184,15 +182,15 @@ - (void)requestAttributionI:(ADJAttributionHandler*)selfI { } [selfI.logger verbose:@"%@", selfI.attributionPackage.extendedString]; - [ADJUtil sendRequest:[selfI requestI:selfI] - prefixErrorMessage:@"Failed to get attribution" - activityPackage:selfI.attributionPackage - responseDataHandler:^(ADJResponseData * responseData) - { - if ([responseData isKindOfClass:[ADJAttributionResponseData class]]) { - [selfI checkAttributionResponse:(ADJAttributionResponseData*)responseData]; - } - }]; + [ADJUtil sendGetRequest:[NSURL URLWithString:ADJUtil.baseUrl] + prefixErrorMessage:@"Failed to get attribution" + activityPackage:selfI.attributionPackage + responseDataHandler:^(ADJResponseData * responseData) + { + if ([responseData isKindOfClass:[ADJAttributionResponseData class]]) { + [selfI checkAttributionResponse:(ADJAttributionResponseData*)responseData]; + } + }]; } - (void)waitRequestAttributionWithDelayI:(ADJAttributionHandler*)selfI @@ -214,25 +212,6 @@ - (void)waitRequestAttributionWithDelayI:(ADJAttributionHandler*)selfI #pragma mark - private -- (NSMutableURLRequest *)requestI:(ADJAttributionHandler*)selfI { - NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[selfI urlI:selfI]]; - request.timeoutInterval = kRequestTimeout; - request.HTTPMethod = @"GET"; - - [request setValue:selfI.attributionPackage.clientSdk forHTTPHeaderField:@"Client-Sdk"]; - - return request; -} - -- (NSURL *)urlI:(ADJAttributionHandler*)selfI { - NSString *parameters = [ADJUtil queryString:selfI.attributionPackage.parameters]; - NSString *relativePath = [NSString stringWithFormat:@"%@?%@", selfI.attributionPackage.path, parameters]; - NSURL *baseUrl = [NSURL URLWithString:ADJUtil.baseUrl]; - NSURL *url = [NSURL URLWithString:relativePath relativeToURL:baseUrl]; - - return url; -} - - (void)teardown { [ADJAdjustFactory.logger verbose:@"ADJAttributionHandler teardown"]; diff --git a/Adjust/ADJConfig.h b/Adjust/ADJConfig.h index 700275f8e..c44c369e9 100644 --- a/Adjust/ADJConfig.h +++ b/Adjust/ADJConfig.h @@ -150,6 +150,30 @@ */ @property (nonatomic, copy, nullable) NSString *userAgent; +/** + * @brief Set if the device is known. + */ +@property (nonatomic, assign) BOOL isDeviceKnown; + +/** + * @brief Adjust app secret id. + */ +@property (nonatomic, copy, readonly, nullable) NSString *secretId; + +/** + * @brief Adjust app secret. + */ +@property (nonatomic, copy, readonly, nullable) NSString *appSecret; + +/** + * @brief Adjust set app secret. + */ +- (void)setAppSecret:(NSUInteger)secretId + info1:(NSUInteger)info1 + info2:(NSUInteger)info2 + info3:(NSUInteger)info3 + info4:(NSUInteger)info4; + /** * @brief Get configuration object for the initialization of the Adjust SDK. * diff --git a/Adjust/ADJConfig.m b/Adjust/ADJConfig.m index 78f883c06..592aeb246 100644 --- a/Adjust/ADJConfig.m +++ b/Adjust/ADJConfig.m @@ -166,6 +166,19 @@ - (BOOL)isValid { return self.appToken != nil; } +- (void)setAppSecret:(NSUInteger)secretId + info1:(NSUInteger)info1 + info2:(NSUInteger)info2 + info3:(NSUInteger)info3 + info4:(NSUInteger)info4 { + _secretId = [NSString stringWithFormat:@"%lu", (unsigned long)secretId]; + _appSecret = [NSString stringWithFormat:@"%lu%lu%lu%lu", + (unsigned long)info1, + (unsigned long)info2, + (unsigned long)info3, + (unsigned long)info4]; +} + -(id)copyWithZone:(NSZone *)zone { ADJConfig* copy = [[[self class] allocWithZone:zone] init]; @@ -179,6 +192,9 @@ -(id)copyWithZone:(NSZone *)zone copy.sendInBackground = self.sendInBackground; copy.delayStart = self.delayStart; copy.userAgent = [self.userAgent copyWithZone:zone]; + copy.isDeviceKnown = self.isDeviceKnown; + copy->_secretId = [self.secretId copyWithZone:zone]; + copy->_appSecret = [self.appSecret copyWithZone:zone]; // adjust delegate not copied } diff --git a/Adjust/ADJDeviceInfo.m b/Adjust/ADJDeviceInfo.m index 475ece787..3284eadac 100644 --- a/Adjust/ADJDeviceInfo.m +++ b/Adjust/ADJDeviceInfo.m @@ -12,6 +12,12 @@ #import "ADJUtil.h" #import "ADJSystemProfile.h" #import "NSData+ADJAdditions.h" +#import "ADJReachability.h" + +#if !TARGET_OS_TV +#import +#import +#endif @implementation ADJDeviceInfo @@ -44,7 +50,7 @@ - (id)initWithSdkPrefix:(NSString *)sdkPrefix { self.machineModel = [ADJSystemProfile machineModel]; self.cpuSubtype = [ADJSystemProfile cpuSubtype]; self.osBuild = [ADJSystemProfile osVersion]; - + if (sdkPrefix == nil) { self.clientSdk = ADJUtil.clientSdk; } else { @@ -71,6 +77,7 @@ - (void)injectInstallReceipt:(NSBundle *)bundle{ } @catch (NSException *exception) { } } + /* -(id)copyWithZone:(NSZone *)zone { diff --git a/Adjust/ADJKeychain.m b/Adjust/ADJKeychain.m index 42639f027..2cffe7201 100644 --- a/Adjust/ADJKeychain.m +++ b/Adjust/ADJKeychain.m @@ -169,7 +169,7 @@ - (BOOL)wasWritingSuccessful:(NSString *)value forKeychainKey:(NSString *)key in NSString *writtenValue; writtenValue = [self valueForKeychainKeyV1:key service:service]; - + if ([writtenValue isEqualToString:value]) { return YES; } else { diff --git a/Adjust/ADJLogger.h b/Adjust/ADJLogger.h index 20be0d952..95bb7433a 100644 --- a/Adjust/ADJLogger.h +++ b/Adjust/ADJLogger.h @@ -79,6 +79,6 @@ typedef enum { * * @return Log level as ADJLogLevel enumeration. */ -+ (ADJLogLevel)LogLevelFromString:(nonnull NSString *)logLevelString; ++ (ADJLogLevel)logLevelFromString:(nonnull NSString *)logLevelString; @end diff --git a/Adjust/ADJLogger.m b/Adjust/ADJLogger.m index f31ad1ec1..f0deef8ef 100644 --- a/Adjust/ADJLogger.m +++ b/Adjust/ADJLogger.m @@ -105,7 +105,7 @@ - (void)logLevel:(NSString *)logLevel format:(NSString *)format parameters:(va_l } } -+ (ADJLogLevel)LogLevelFromString:(NSString *)logLevelString { ++ (ADJLogLevel)logLevelFromString:(NSString *)logLevelString { if ([logLevelString isEqualToString:@"verbose"]) return ADJLogLevelVerbose; @@ -124,6 +124,9 @@ + (ADJLogLevel)LogLevelFromString:(NSString *)logLevelString { if ([logLevelString isEqualToString:@"assert"]) return ADJLogLevelAssert; + if ([logLevelString isEqualToString:@"suppress"]) + return ADJLogLevelSuppress; + // default value if string does not match return ADJLogLevelInfo; } diff --git a/Adjust/ADJPackageBuilder.h b/Adjust/ADJPackageBuilder.h index b4eab24cd..2f2ed2117 100644 --- a/Adjust/ADJPackageBuilder.h +++ b/Adjust/ADJPackageBuilder.h @@ -30,19 +30,17 @@ - (id)initWithDeviceInfo:(ADJDeviceInfo *)deviceInfo activityState:(ADJActivityState *)activityState config:(ADJConfig *)adjustConfig + sessionParameters:(ADJSessionParameters *)sessionParameters createdAt:(double)createdAt; -- (ADJActivityPackage *)buildSessionPackage:(ADJSessionParameters *)sessionParameters - isInDelay:(BOOL)isInDelay; +- (ADJActivityPackage *)buildSessionPackage:(BOOL)isInDelay; - (ADJActivityPackage *)buildAttributionPackage; - (ADJActivityPackage *)buildEventPackage:(ADJEvent *)event - sessionParameters:(ADJSessionParameters *)sessionParameters isInDelay:(BOOL)isInDelay; -- (ADJActivityPackage *)buildClickPackage:(NSString *)clickSource - sessionParameters:(ADJSessionParameters *)sessionParameters; +- (ADJActivityPackage *)buildClickPackage:(NSString *)clickSource; - (ADJActivityPackage *)buildInfoPackage:(NSString *)infoSource; diff --git a/Adjust/ADJPackageBuilder.m b/Adjust/ADJPackageBuilder.m index ccc6676c0..3c68bd080 100644 --- a/Adjust/ADJPackageBuilder.m +++ b/Adjust/ADJPackageBuilder.m @@ -12,6 +12,7 @@ #import "ADJPackageBuilder.h" #import "ADJActivityPackage.h" #import "NSData+ADJAdditions.h" +#import "UIDevice+ADJAdditions.h" @interface ADJPackageBuilder() @@ -23,6 +24,8 @@ @interface ADJPackageBuilder() @property (nonatomic, copy) ADJActivityState *activityState; +@property (nonatomic, weak) ADJSessionParameters *sessionParameters; + @end @implementation ADJPackageBuilder @@ -32,6 +35,7 @@ @implementation ADJPackageBuilder - (id)initWithDeviceInfo:(ADJDeviceInfo *)deviceInfo activityState:(ADJActivityState *)activityState config:(ADJConfig *)adjustConfig + sessionParameters:(ADJSessionParameters *)sessionParameters createdAt:(double)createdAt { self = [super init]; @@ -43,20 +47,16 @@ - (id)initWithDeviceInfo:(ADJDeviceInfo *)deviceInfo self.deviceInfo = deviceInfo; self.adjustConfig = adjustConfig; self.activityState = activityState; + self.sessionParameters = sessionParameters; return self; } #pragma mark - Public methods -- (ADJActivityPackage *)buildSessionPackage:(ADJSessionParameters *)sessionParameters - isInDelay:(BOOL)isInDelay { +- (ADJActivityPackage *)buildSessionPackage:(BOOL)isInDelay { NSMutableDictionary *parameters; - if (!isInDelay) { - parameters = [self attributableParameters:sessionParameters]; - } else { - parameters = [self attributableParameters:nil]; - } + parameters = [self attributableParameters:isInDelay]; ADJActivityPackage *sessionPackage = [self defaultActivityPackage]; sessionPackage.path = @"/session"; @@ -68,7 +68,6 @@ - (ADJActivityPackage *)buildSessionPackage:(ADJSessionParameters *)sessionParam } - (ADJActivityPackage *)buildEventPackage:(ADJEvent *)event - sessionParameters:(ADJSessionParameters *)sessionParameters isInDelay:(BOOL)isInDelay { NSMutableDictionary *parameters = [self defaultParameters]; @@ -78,10 +77,10 @@ - (ADJActivityPackage *)buildEventPackage:(ADJEvent *)event [ADJPackageBuilder parameters:parameters setString:event.eventToken forKey:@"event_token"]; if (!isInDelay) { - NSDictionary *mergedCallbackParameters = [ADJUtil mergeParameters:sessionParameters.callbackParameters + NSDictionary *mergedCallbackParameters = [ADJUtil mergeParameters:self.sessionParameters.callbackParameters source:event.callbackParameters parameterName:@"Callback"]; - NSDictionary *mergedPartnerParameters = [ADJUtil mergeParameters:sessionParameters.partnerParameters + NSDictionary *mergedPartnerParameters = [ADJUtil mergeParameters:self.sessionParameters.partnerParameters source:event.partnerParameters parameterName:@"Partner"]; @@ -116,10 +115,9 @@ - (ADJActivityPackage *)buildEventPackage:(ADJEvent *)event return eventPackage; } -- (ADJActivityPackage *)buildClickPackage:(NSString *)clickSource - sessionParameters:(ADJSessionParameters *)sessionParameters +- (ADJActivityPackage *)buildClickPackage:(NSString *)clickSource; { - NSMutableDictionary *parameters = [self attributableParameters:sessionParameters]; + NSMutableDictionary *parameters = [self attributableParameters:NO]; [ADJPackageBuilder parameters:parameters setString:clickSource forKey:@"source"]; [ADJPackageBuilder parameters:parameters setDictionary:self.deeplinkParameters forKey:@"params"]; @@ -193,7 +191,7 @@ - (NSMutableDictionary *)idsParameters { return parameters; } -- (NSMutableDictionary *)attributableParameters:(ADJSessionParameters *)sessionParameters { +- (NSMutableDictionary *)attributableParameters:(BOOL)isInDelay { NSMutableDictionary *parameters = [self defaultParameters]; [ADJPackageBuilder parameters:parameters setString:[ADJUtil getUpdateTime] forKey:@"app_updated_at"]; @@ -201,9 +199,9 @@ - (NSMutableDictionary *)attributableParameters:(ADJSessionParameters *)sessionP [ADJPackageBuilder parameters:parameters setDuration:self.activityState.lastInterval forKey:@"last_interval"]; [ADJPackageBuilder parameters:parameters setString:self.adjustConfig.defaultTracker forKey:@"default_tracker"]; - if (sessionParameters != nil) { - [ADJPackageBuilder parameters:parameters setDictionary:sessionParameters.callbackParameters forKey:@"callback_params"]; - [ADJPackageBuilder parameters:parameters setDictionary:sessionParameters.partnerParameters forKey:@"partner_params"]; + if (!isInDelay) { + [ADJPackageBuilder parameters:parameters setDictionary:self.sessionParameters.callbackParameters forKey:@"callback_params"]; + [ADJPackageBuilder parameters:parameters setDictionary:self.sessionParameters.partnerParameters forKey:@"partner_params"]; } return parameters; @@ -227,7 +225,7 @@ - (void)injectCommonParameters:(NSMutableDictionary *)parameters { } - (void)injectDeviceInfoIds:(ADJDeviceInfo *)deviceInfo intoParameters:(NSMutableDictionary *)parameters { - [ADJPackageBuilder parameters:parameters setString:deviceInfo.idForAdvertisers forKey:@"idfa"]; + [ADJPackageBuilder parameters:parameters setString:UIDevice.currentDevice.adjIdForAdvertisers forKey:@"idfa"]; [ADJPackageBuilder parameters:parameters setString:deviceInfo.vendorId forKey:@"idfv"]; } @@ -249,12 +247,23 @@ - (void)injectDeviceInfo:(ADJDeviceInfo *)deviceInfo intoParameters:(NSMutableDi [ADJPackageBuilder parameters:parameters setString:deviceInfo.cpuSubtype forKey:@"cpu_type"]; [ADJPackageBuilder parameters:parameters setString:deviceInfo.installReceiptBase64 forKey:@"install_receipt"]; [ADJPackageBuilder parameters:parameters setString:deviceInfo.osBuild forKey:@"os_build"]; + [ADJPackageBuilder parameters:parameters setNumberInt:[ADJUtil readReachabilityFlags] forKey:@"connectivity_type"]; +#if !TARGET_OS_TV + [ADJPackageBuilder parameters:parameters setString:[ADJUtil readMCC] forKey:@"mcc"]; + [ADJPackageBuilder parameters:parameters setString:[ADJUtil readMNC] forKey:@"mnc"]; + [ADJPackageBuilder parameters:parameters setString:[ADJUtil readCurrentRadioAccessTechnology] forKey:@"network_type"]; +#endif } - (void)injectConfig:(ADJConfig *)adjustConfig intoParameters:(NSMutableDictionary *) parameters { [ADJPackageBuilder parameters:parameters setString:adjustConfig.appToken forKey:@"app_token"]; [ADJPackageBuilder parameters:parameters setString:adjustConfig.environment forKey:@"environment"]; [ADJPackageBuilder parameters:parameters setBool:adjustConfig.eventBufferingEnabled forKey:@"event_buffering_enabled"]; + if (adjustConfig.isDeviceKnown) { + [ADJPackageBuilder parameters:parameters setBool:adjustConfig.isDeviceKnown forKey:@"device_known"]; + } + [ADJPackageBuilder parameters:parameters setString:adjustConfig.secretId forKey:@"secret_id"]; + [ADJPackageBuilder parameters:parameters setString:adjustConfig.appSecret forKey:@"app_secret"]; } - (void)injectActivityState:(ADJActivityState *)activityState intoParamters:(NSMutableDictionary *)parameters { @@ -401,4 +410,12 @@ + (void)parameters:(NSMutableDictionary *)parameters setNumber:(NSNumber *)value [ADJPackageBuilder parameters:parameters setString:numberString forKey:key]; } ++ (void)parameters:(NSMutableDictionary *)parameters setNumberInt:(NSNumber *)value forKey:(NSString *)key { + if (value == nil) { + return; + } + + [ADJPackageBuilder parameters:parameters setInt:[value intValue] forKey:key]; +} + @end diff --git a/Adjust/ADJPackageHandler.m b/Adjust/ADJPackageHandler.m index 779ceaf5b..d7e163cdb 100644 --- a/Adjust/ADJPackageHandler.m +++ b/Adjust/ADJPackageHandler.m @@ -238,25 +238,15 @@ - (void)updatePackagesI:(ADJPackageHandler *)selfI #pragma mark - private - (void)readPackageQueueI:(ADJPackageHandler *)selfI { - @try { - [NSKeyedUnarchiver setClass:[ADJActivityPackage class] forClassName:@"AIActivityPackage"]; - NSString *filename = selfI.packageQueueFilename; - id object = [NSKeyedUnarchiver unarchiveObjectWithFile:filename]; - if ([object isKindOfClass:[NSArray class]]) { - selfI.packageQueue = object; - [selfI.logger debug:@"Package handler read %d packages", selfI.packageQueue.count]; - return; - } else if (object == nil) { - [selfI.logger verbose:@"Package queue file not found"]; - } else { - [selfI.logger error:@"Failed to read package queue"]; - } - } @catch (NSException *exception) { - [selfI.logger error:@"Failed to read package queue (%@)", exception]; - } + [NSKeyedUnarchiver setClass:[ADJActivityPackage class] forClassName:@"AIActivityPackage"]; + + id object = [ADJUtil readObject:kPackageQueueFilename objectName:@"Package queue" class:[NSArray class]]; - // start with a fresh package queue in case of any exception - selfI.packageQueue = [NSMutableArray array]; + if (object != nil) { + selfI.packageQueue = object; + } else { + selfI.packageQueue = [NSMutableArray array]; + } } - (void)writePackageQueueS:(ADJPackageHandler *)selfS { @@ -264,41 +254,28 @@ - (void)writePackageQueueS:(ADJPackageHandler *)selfS { if (selfS.packageQueue == nil) { return; } - NSString *filename = selfS.packageQueueFilename; - BOOL result = [NSKeyedArchiver archiveRootObject:selfS.packageQueue toFile:filename]; - if (result == YES) { - [ADJUtil excludeFromBackup:filename]; - [selfS.logger debug:@"Package handler wrote %d packages", selfS.packageQueue.count]; - } else { - [selfS.logger error:@"Failed to write package queue"]; - } + + [ADJUtil writeObject:selfS.packageQueue fileName:kPackageQueueFilename objectName:@"Package queue"]; } } -- (void)teardownPackageQueueS:(BOOL)deleteState -{ +- (void)teardownPackageQueueS:(BOOL)deleteState { @synchronized ([ADJPackageHandler class]) { if (self.packageQueue == nil) { return; } + if (deleteState) { - [ADJUtil deleteFile:self.packageQueueFilename]; + [ADJUtil deleteFileWithName:kPackageQueueFilename]; } - [self.packageQueue removeAllObjects]; + [self.packageQueue removeAllObjects]; self.packageQueue = nil; } } -- (NSString *)packageQueueFilename { - NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); - NSString *path = [paths objectAtIndex:0]; - NSString *filename = [path stringByAppendingPathComponent:kPackageQueueFilename]; - return filename; -} - --(void)dealloc { - //cleanup code +- (void)dealloc { + // Cleanup code if (self.sendingSemaphore != nil) { dispatch_semaphore_signal(self.sendingSemaphore); } diff --git a/Adjust/ADJReachability.h b/Adjust/ADJReachability.h new file mode 100644 index 000000000..6123c72f7 --- /dev/null +++ b/Adjust/ADJReachability.h @@ -0,0 +1,66 @@ +/* + Copyright (C) 2016 Apple Inc. All Rights Reserved. + See LICENSE.txt for this sample’s licensing information + + Abstract: + Basic demonstration of how to use the SystemConfiguration Reachablity APIs. + */ + +#import +#import +#import + + +typedef enum : NSInteger { + NotReachable = 0, + ReachableViaWiFi, + ReachableViaWWAN +} NetworkStatus; + +#pragma mark IPv6 Support +//Reachability fully support IPv6. For full details, see ReadMe.md. + + +extern NSString *kReachabilityChangedNotification; + + +@interface ADJReachability : NSObject + +/*! + * Use to check the reachability of a given host name. + */ ++ (instancetype)reachabilityWithHostName:(NSString *)hostName; + +/*! + * Use to check the reachability of a given IP address. + */ ++ (instancetype)reachabilityWithAddress:(const struct sockaddr *)hostAddress; + +/*! + * Checks whether the default route is available. Should be used by applications that do not connect to a particular host. + */ ++ (instancetype)reachabilityForInternetConnection; + + +#pragma mark reachabilityForLocalWiFi +//reachabilityForLocalWiFi has been removed from the sample. See ReadMe.md for more information. +//+ (instancetype)reachabilityForLocalWiFi; + +/*! + * Start listening for reachability notifications on the current run loop. + */ +- (BOOL)startNotifier; +- (void)stopNotifier; + +- (NetworkStatus)currentReachabilityStatus; + +/*! + * WWAN may be available, but not active until a connection has been established. WiFi may require a connection for VPN on Demand. + */ +- (BOOL)connectionRequired; + +- (NSNumber *)currentReachabilityFlags; + +@end + + diff --git a/Adjust/ADJReachability.m b/Adjust/ADJReachability.m new file mode 100644 index 000000000..a7d46881d --- /dev/null +++ b/Adjust/ADJReachability.m @@ -0,0 +1,247 @@ +/* + Copyright (C) 2016 Apple Inc. All Rights Reserved. + + Abstract: + Basic demonstration of how to use the SystemConfiguration Reachablity APIs. + */ + +#import +#import +#import +#import +#import + +#import + +#import "ADJReachability.h" + +#pragma mark IPv6 Support + +NSString *kReachabilityChangedNotification = @"kNetworkReachabilityChangedNotification"; + +#pragma mark - Supporting functions + +#define kShouldPrintReachabilityFlags 1 + +static void PrintReachabilityFlags(SCNetworkReachabilityFlags flags, const char* comment) +{ +#if kShouldPrintReachabilityFlags + + NSLog(@"Reachability Flag Status: %c%c %c%c%c%c%c%c%c %s\n", + (flags & kSCNetworkReachabilityFlagsIsWWAN) ? 'W' : '-', + (flags & kSCNetworkReachabilityFlagsReachable) ? 'R' : '-', + + (flags & kSCNetworkReachabilityFlagsTransientConnection) ? 't' : '-', + (flags & kSCNetworkReachabilityFlagsConnectionRequired) ? 'c' : '-', + (flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) ? 'C' : '-', + (flags & kSCNetworkReachabilityFlagsInterventionRequired) ? 'i' : '-', + (flags & kSCNetworkReachabilityFlagsConnectionOnDemand) ? 'D' : '-', + (flags & kSCNetworkReachabilityFlagsIsLocalAddress) ? 'l' : '-', + (flags & kSCNetworkReachabilityFlagsIsDirect) ? 'd' : '-', + comment + ); +#endif +} + + +static void ReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkReachabilityFlags flags, void* info) +{ +#pragma unused (target, flags) + NSCAssert(info != NULL, @"info was NULL in ReachabilityCallback"); + NSCAssert([(__bridge NSObject*) info isKindOfClass: [ADJReachability class]], @"info was wrong class in ReachabilityCallback"); + + ADJReachability* noteObject = (__bridge ADJReachability *)info; + // Post a notification to notify the client that the network reachability changed. + [[NSNotificationCenter defaultCenter] postNotificationName: kReachabilityChangedNotification object: noteObject]; +} + + +#pragma mark - Reachability implementation + +@implementation ADJReachability +{ + SCNetworkReachabilityRef _reachabilityRef; +} + ++ (instancetype)reachabilityWithHostName:(NSString *)hostName +{ + ADJReachability* returnValue = NULL; + SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithName(NULL, [hostName UTF8String]); + if (reachability != NULL) + { + returnValue= [[self alloc] init]; + if (returnValue != NULL) + { + returnValue->_reachabilityRef = reachability; + } + else { + CFRelease(reachability); + } + } + return returnValue; +} + + ++ (instancetype)reachabilityWithAddress:(const struct sockaddr *)hostAddress +{ + SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, hostAddress); + + ADJReachability* returnValue = NULL; + + if (reachability != NULL) + { + returnValue = [[self alloc] init]; + if (returnValue != NULL) + { + returnValue->_reachabilityRef = reachability; + } + else { + CFRelease(reachability); + } + } + return returnValue; +} + + ++ (instancetype)reachabilityForInternetConnection +{ + struct sockaddr_in zeroAddress; + bzero(&zeroAddress, sizeof(zeroAddress)); + zeroAddress.sin_len = sizeof(zeroAddress); + zeroAddress.sin_family = AF_INET; + + return [self reachabilityWithAddress: (const struct sockaddr *) &zeroAddress]; +} + + +#pragma mark - Start and stop notifier + +- (BOOL)startNotifier +{ + BOOL returnValue = NO; + SCNetworkReachabilityContext context = {0, (__bridge void *)(self), NULL, NULL, NULL}; + + if (SCNetworkReachabilitySetCallback(_reachabilityRef, ReachabilityCallback, &context)) + { + if (SCNetworkReachabilityScheduleWithRunLoop(_reachabilityRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode)) + { + returnValue = YES; + } + } + + return returnValue; +} + + +- (void)stopNotifier +{ + if (_reachabilityRef != NULL) + { + SCNetworkReachabilityUnscheduleFromRunLoop(_reachabilityRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); + } +} + + +- (void)dealloc +{ + [self stopNotifier]; + if (_reachabilityRef != NULL) + { + CFRelease(_reachabilityRef); + } +} + + +#pragma mark - Network Flag Handling + +- (NetworkStatus)networkStatusForFlags:(SCNetworkReachabilityFlags)flags +{ + PrintReachabilityFlags(flags, "networkStatusForFlags"); + if ((flags & kSCNetworkReachabilityFlagsReachable) == 0) + { + // The target host is not reachable. + return NotReachable; + } + + NetworkStatus returnValue = NotReachable; + + if ((flags & kSCNetworkReachabilityFlagsConnectionRequired) == 0) + { + /* + If the target host is reachable and no connection is required then we'll assume (for now) that you're on Wi-Fi... + */ + returnValue = ReachableViaWiFi; + } + + if ((((flags & kSCNetworkReachabilityFlagsConnectionOnDemand ) != 0) || + (flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) != 0)) + { + /* + ... and the connection is on-demand (or on-traffic) if the calling application is using the CFSocketStream or higher APIs... + */ + + if ((flags & kSCNetworkReachabilityFlagsInterventionRequired) == 0) + { + /* + ... and no [user] intervention is needed... + */ + returnValue = ReachableViaWiFi; + } + } + + if ((flags & kSCNetworkReachabilityFlagsIsWWAN) == kSCNetworkReachabilityFlagsIsWWAN) + { + /* + ... but WWAN connections are OK if the calling application is using the CFNetwork APIs. + */ + returnValue = ReachableViaWWAN; + } + + return returnValue; +} + + +- (BOOL)connectionRequired +{ + NSAssert(_reachabilityRef != NULL, @"connectionRequired called with NULL reachabilityRef"); + SCNetworkReachabilityFlags flags; + + if (SCNetworkReachabilityGetFlags(_reachabilityRef, &flags)) + { + return (flags & kSCNetworkReachabilityFlagsConnectionRequired); + } + + return NO; +} + + +- (NetworkStatus)currentReachabilityStatus +{ + NSAssert(_reachabilityRef != NULL, @"currentNetworkStatus called with NULL SCNetworkReachabilityRef"); + NetworkStatus returnValue = NotReachable; + SCNetworkReachabilityFlags flags; + + if (SCNetworkReachabilityGetFlags(_reachabilityRef, &flags)) + { + returnValue = [self networkStatusForFlags:flags]; + } + + return returnValue; +} + +- (NSNumber *)currentReachabilityFlags +{ + if (_reachabilityRef == NULL) { + return nil; + } + SCNetworkReachabilityFlags flags; + + if (SCNetworkReachabilityGetFlags(_reachabilityRef, &flags)) + { + return [[NSNumber alloc] initWithUnsignedInt:flags]; + } else { + return [[NSNumber alloc] initWithUnsignedInt:0]; + } +} + +@end diff --git a/Adjust/ADJSessionParameters.m b/Adjust/ADJSessionParameters.m index 1d1f928a1..1c9622ae8 100644 --- a/Adjust/ADJSessionParameters.m +++ b/Adjust/ADJSessionParameters.m @@ -10,6 +10,16 @@ @implementation ADJSessionParameters +- (id)initWithCoder:(NSCoder *)decoder { + self = [super init]; + + if (self == nil) { + return nil; + } + + return self; +} + #pragma mark - NSCopying -(id)copyWithZone:(NSZone *)zone { diff --git a/Adjust/ADJUserDefaults.h b/Adjust/ADJUserDefaults.h new file mode 100644 index 000000000..0c66531e5 --- /dev/null +++ b/Adjust/ADJUserDefaults.h @@ -0,0 +1,25 @@ +// +// ADJUserDefaults.h +// Adjust +// +// Created by Uglješa Erceg on 16.08.17. +// Copyright © 2017 adjust GmbH. All rights reserved. +// + +#import + +@interface ADJUserDefaults : NSObject + ++ (void)savePushToken:(NSData *)pushToken; + ++ (NSData *)getPushToken; + ++ (void)clearAdjustStuff; + ++ (void)removePushToken; + ++ (void)setInstallTracked; + ++ (BOOL)getInstallTracked; + +@end diff --git a/Adjust/ADJUserDefaults.m b/Adjust/ADJUserDefaults.m new file mode 100644 index 000000000..103f159d4 --- /dev/null +++ b/Adjust/ADJUserDefaults.m @@ -0,0 +1,47 @@ +// +// ADJUserDefaults.m +// Adjust +// +// Created by Uglješa Erceg on 16.08.17. +// Copyright © 2017 adjust GmbH. All rights reserved. +// + +#import "ADJUserDefaults.h" + +static NSString * const PREFS_KEY_PUSH_TOKEN = @"adj_push_token"; +static NSString * const PREFS_KEY_INSTALL_TRACKED = @"adj_install_tracked"; + +@implementation ADJUserDefaults + +#pragma mark - Public methods + ++ (void)savePushToken:(NSData *)pushToken { + [[NSUserDefaults standardUserDefaults] setObject:pushToken forKey:PREFS_KEY_PUSH_TOKEN]; + [[NSUserDefaults standardUserDefaults] synchronize]; +} + ++ (NSData *)getPushToken { + return [[NSUserDefaults standardUserDefaults] objectForKey:PREFS_KEY_PUSH_TOKEN]; +} + ++ (void)removePushToken { + [[NSUserDefaults standardUserDefaults] removeObjectForKey:PREFS_KEY_PUSH_TOKEN]; + [[NSUserDefaults standardUserDefaults] synchronize]; +} + ++ (void)setInstallTracked { + [[NSUserDefaults standardUserDefaults] setBool:YES forKey:PREFS_KEY_INSTALL_TRACKED]; + [[NSUserDefaults standardUserDefaults] synchronize]; +} + ++ (BOOL)getInstallTracked { + return [[NSUserDefaults standardUserDefaults] boolForKey:PREFS_KEY_INSTALL_TRACKED]; +} + ++ (void)clearAdjustStuff { + [[NSUserDefaults standardUserDefaults] removeObjectForKey:PREFS_KEY_PUSH_TOKEN]; + [[NSUserDefaults standardUserDefaults] removeObjectForKey:PREFS_KEY_INSTALL_TRACKED]; + [[NSUserDefaults standardUserDefaults] synchronize]; +} + +@end diff --git a/Adjust/ADJUtil.h b/Adjust/ADJUtil.h index 95cf09bb9..f1358867a 100644 --- a/Adjust/ADJUtil.h +++ b/Adjust/ADJUtil.h @@ -19,7 +19,9 @@ typedef void (^selfInjectedBlock)(id); @interface ADJUtil : NSObject -+ (id)readObject:(NSString *)filename ++ (void)teardown; + ++ (id)readObject:(NSString *)fileName objectName:(NSString *)objectName class:(Class)classToRead; @@ -32,7 +34,7 @@ typedef void (^selfInjectedBlock)(id); + (void)updateUrlSessionConfiguration:(ADJConfig *)config; + (void)writeObject:(id)object - filename:(NSString *)filename + fileName:(NSString *)fileName objectName:(NSString *)objectName; + (void)launchInMainThread:(NSObject *)receiver @@ -43,16 +45,10 @@ typedef void (^selfInjectedBlock)(id); selfInject:(id)selfInject block:(selfInjectedBlock)block; -+ (void)sendRequest:(NSMutableURLRequest *)request - prefixErrorMessage:(NSString *)prefixErrorMessage - activityPackage:(ADJActivityPackage *)activityPackage -responseDataHandler:(void (^)(ADJResponseData *responseData))responseDataHandler; - -+ (void)sendRequest:(NSMutableURLRequest *)request - prefixErrorMessage:(NSString *)prefixErrorMessage - suffixErrorMessage:(NSString *)suffixErrorMessage - activityPackage:(ADJActivityPackage *)activityPackage -responseDataHandler:(void (^)(ADJResponseData *responseData))responseDataHandler; ++ (void)sendGetRequest:(NSURL *)baseUrl + prefixErrorMessage:(NSString *)prefixErrorMessage + activityPackage:(ADJActivityPackage *)activityPackage + responseDataHandler:(void (^)(ADJResponseData *responseData))responseDataHandler; + (void)sendPostRequest:(NSURL *)baseUrl queueSize:(NSUInteger)queueSize @@ -79,15 +75,13 @@ responseDataHandler:(void (^)(ADJResponseData *responseData))responseDataHandler + (NSString *)queryString:(NSDictionary *)parameters; -+ (NSString *)getFullFilename:(NSString *)baseFilename; - + (NSString *)convertDeviceToken:(NSData *)deviceToken; + (BOOL)isNull:(id)value; + (BOOL)isNotNull:(id)value; -+ (BOOL)deleteFile:(NSString *)filename; ++ (BOOL)deleteFileWithName:(NSString *)filename; + (BOOL)checkAttributionDetails:(NSDictionary *)attributionDetails; @@ -110,4 +104,16 @@ responseDataHandler:(void (^)(ADJResponseData *responseData))responseDataHandler + (NSTimeInterval)waitingTime:(NSInteger)retries backoffStrategy:(ADJBackoffStrategy *)backoffStrategy; ++ (NSNumber *)readReachabilityFlags; + ++ (NSString *)extractAppSecret:(ADJActivityPackage *)activityPackage; + +#if !TARGET_OS_TV ++ (NSString *)readMCC; + ++ (NSString *)readMNC; + ++ (NSString *)readCurrentRadioAccessTechnology; +#endif + @end diff --git a/Adjust/ADJUtil.m b/Adjust/ADJUtil.m index 3e1f5c6a7..c1d3ca200 100644 --- a/Adjust/ADJUtil.m +++ b/Adjust/ADJUtil.m @@ -18,19 +18,30 @@ #import "ADJAdjustFactory.h" #import "UIDevice+ADJAdditions.h" #import "NSString+ADJAdditions.h" +#import "ADJReachability.h" + +#if !TARGET_OS_TV +#import +#import +#endif static const double kRequestTimeout = 60; // 60 seconds -static NSDateFormatter *dateFormat; static NSRegularExpression *universalLinkRegex = nil; static NSNumberFormatter *secondsNumberFormatter = nil; -static NSRegularExpression *optionalRedirectRegex = 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; +#endif static NSString *userAgent = nil; -static NSString * const kClientSdk = @"ios4.11.5"; +static NSString * const kClientSdk = @"ios4.12.0"; static NSString * const kDeeplinkParam = @"deep_link="; static NSString * const kSchemeDelimiter = @"://"; static NSString * const kDefaultScheme = @"AdjustUniversalScheme"; @@ -48,39 +59,28 @@ + (void)initialize { return; } - [self initializeDateFormat]; [self initializeUniversalLinkRegex]; [self initializeSecondsNumberFormatter]; [self initializeShortUniversalLinkRegex]; [self initializeOptionalRedirectRegex]; [self initializeUrlSessionConfiguration]; + [self initializeReachability]; +#if !TARGET_OS_TV + [self initializeNetworkInfoAndCarrier]; +#endif } -+ (void)initializeDateFormat { - dateFormat = [[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) { -#pragma clang diagnostic pop - calendarIdentifier = NSCalendarIdentifierGregorian; - } else { -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wunreachable-code" -#pragma clang diagnostic ignored "-Wdeprecated-declarations" - calendarIdentifier = NSGregorianCalendar; -#pragma clang diagnostic pop - } - - dateFormat.calendar = [NSCalendar calendarWithIdentifier:calendarIdentifier]; - } - - dateFormat.locale = [NSLocale systemLocale]; - [dateFormat setDateFormat:kDateFormat]; ++ (void)teardown { + universalLinkRegex = nil; + secondsNumberFormatter = nil; + optionalRedirectRegex = nil; + shortUniversalLinkRegex = nil; + urlSessionConfiguration = nil; + reachability = nil; +#if !TARGET_OS_TV + networkInfo = nil; + carrier = nil; +#endif } @@ -134,10 +134,30 @@ + (void)initializeSecondsNumberFormatter { [secondsNumberFormatter setPositiveFormat:@"0.0"]; } ++ (NSURLSessionConfiguration *)getUrlSessionConfiguration { + if (urlSessionConfiguration != nil) { + return urlSessionConfiguration; + } else { + return [NSURLSessionConfiguration defaultSessionConfiguration]; + } +} + + (void)initializeUrlSessionConfiguration { urlSessionConfiguration = [NSURLSessionConfiguration defaultSessionConfiguration]; } +#if !TARGET_OS_TV ++ (void)initializeNetworkInfoAndCarrier { + networkInfo = [[CTTelephonyNetworkInfo alloc] init]; + carrier = [networkInfo subscriberCellularProvider]; +} +#endif + ++ (void)initializeReachability { + reachability = [ADJReachability reachabilityForInternetConnection]; + [reachability startNotifier]; +} + + (void)updateUrlSessionConfiguration:(ADJConfig *)config { userAgent = config.userAgent; } @@ -150,6 +170,35 @@ + (NSString *)clientSdk { return kClientSdk; } ++ (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) { +#pragma clang diagnostic pop + calendarIdentifier = NSCalendarIdentifierGregorian; + } else { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunreachable-code" +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + calendarIdentifier = NSGregorianCalendar; +#pragma clang diagnostic pop + } + + dateFormatter.calendar = [NSCalendar calendarWithIdentifier:calendarIdentifier]; + } + + dateFormatter.locale = [NSLocale systemLocale]; + [dateFormatter setDateFormat:kDateFormat]; + + return dateFormatter; +} + // Inspired by https://gist.github.com/kevinbarrett/2002382 + (void)excludeFromBackup:(NSString *)path { NSURL *url = [NSURL fileURLWithPath:path]; @@ -199,7 +248,13 @@ + (NSString *)formatSeconds1970:(double)value { } + (NSString *)formatDate:(NSDate *)value { - return [dateFormat stringFromDate:value]; + NSDateFormatter *dateFormatter = [ADJUtil getDateFormatter]; + + if (dateFormatter == nil) { + return nil; + } + + return [dateFormatter stringFromDate:value]; } + (void)saveJsonResponse:(NSData *)jsonData responseData:(ADJResponseData *)responseData { @@ -247,51 +302,165 @@ + (NSDictionary *)buildJsonDict:(NSData *)jsonData return jsonDict; } -+ (NSString *)getFullFilename:(NSString *)baseFilename { - NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); - NSString *path = [paths objectAtIndex:0]; - NSString *filename = [path stringByAppendingPathComponent:baseFilename]; - - return filename; -} - -+ (id)readObject:(NSString *)filename ++ (id)readObject:(NSString *)fileName objectName:(NSString *)objectName - class:(Class) classToRead { - id logger = [ADJAdjustFactory logger]; + class:(Class)classToRead { + // Try to read from Application Support directory first. + NSString *documentsFilePath = [ADJUtil getFilePathInDocumentsDir:fileName]; + NSString *appSupportFilePath = [ADJUtil getFilePathInAppSupportDir:fileName]; @try { - NSString *fullFilename = [ADJUtil getFullFilename:filename]; - id object = [NSKeyedUnarchiver unarchiveObjectWithFile:fullFilename]; - - if ([object isKindOfClass:classToRead]) { - [logger debug:@"Read %@: %@", objectName, object]; - return object; - } else if (object == nil) { - [logger verbose:@"%@ file not found", objectName]; + 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]; + [[ADJAdjustFactory logger] verbose:@"%@ file not found in \"Application Support/Adjust\" folder", fileName]; } else { - [logger error:@"Failed to read %@ file", objectName]; + // [[ADJAdjustFactory logger] error:@"Failed to read %@ file", appSupportFilePath]; + [[ADJAdjustFactory logger] error:@"Failed to read %@ file from \"Application Support/Adjust\" folder", fileName]; } - } @catch (NSException *ex ) { - [logger error:@"Failed to read %@ file (%@)", objectName, ex]; + } @catch (NSException *ex) { + // [[ADJAdjustFactory logger] error:@"Failed to read %@ file (%@)", appSupportFilePath, ex]; + [[ADJAdjustFactory logger] error:@"Failed to read %@ file from \"Application Support/Adjust\" folder (%@)", fileName, ex]; } + // 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]; + [[ADJAdjustFactory logger] verbose:@"%@ file not found in Documents folder", fileName]; + } else { + // [[ADJAdjustFactory logger] error:@"Failed to read %@ file", documentsFilePath]; + [[ADJAdjustFactory logger] error:@"Failed to read %@ file from Documents folder", fileName]; + } + } @catch (NSException *ex) { + // [[ADJAdjustFactory logger] error:@"Failed to read %@ file (%@)", documentsFilePath, ex]; + [[ADJAdjustFactory logger] error:@"Failed to read %@ file from Documents folder (%@)", fileName, ex]; + } + return nil; } + (void)writeObject:(id)object - filename:(NSString *)filename + fileName:(NSString *)fileName objectName:(NSString *)objectName { - id logger = [ADJAdjustFactory logger]; - NSString *fullFilename = [ADJUtil getFullFilename:filename]; - BOOL result = [NSKeyedArchiver archiveRootObject:object toFile:fullFilename]; + NSString *filePath = [ADJUtil getFilePathInAppSupportDir:fileName]; + + BOOL result = [NSKeyedArchiver archiveRootObject:object toFile:filePath]; if (result == YES) { - [ADJUtil excludeFromBackup:fullFilename]; - [logger debug:@"Wrote %@: %@", objectName, object]; + [ADJUtil excludeFromBackup:filePath]; + + if ([object isKindOfClass:[NSArray class]]) { + [[ADJAdjustFactory logger] debug:@"Package handler wrote %d packages", [object count]]; + } else { + [[ADJAdjustFactory logger] debug:@"Wrote %@: %@", objectName, object]; + } } else { - [logger error:@"Failed to write %@ file", objectName]; + [[ADJAdjustFactory logger] error:@"Failed to write %@ file", objectName]; + } +} + ++ (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; } + (NSString *)queryString:(NSDictionary *)parameters { @@ -352,46 +521,56 @@ + (NSString *)formatErrorMessage:(NSString *)prefixErrorMessage } } -+ (void)sendPostRequest:(NSURL *)baseUrl - queueSize:(NSUInteger)queueSize - prefixErrorMessage:(NSString *)prefixErrorMessage - suffixErrorMessage:(NSString *)suffixErrorMessage - activityPackage:(ADJActivityPackage *)activityPackage - responseDataHandler:(void (^)(ADJResponseData *responseData))responseDataHandler { - NSMutableURLRequest *request = [ADJUtil requestForPackage:activityPackage baseUrl:baseUrl queueSize:queueSize]; ++ (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]; [ADJUtil sendRequest:request prefixErrorMessage:prefixErrorMessage - suffixErrorMessage:suffixErrorMessage activityPackage:activityPackage + secretId:secretId + appSecret:appSecret responseDataHandler:responseDataHandler]; } -+ (NSMutableURLRequest *)requestForPackage:(ADJActivityPackage *)activityPackage - baseUrl:(NSURL *)baseUrl - queueSize:(NSUInteger)queueSize { - NSURL *url = [NSURL URLWithString:activityPackage.path relativeToURL:baseUrl]; - 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"]; - - NSString *bodyString = [ADJUtil queryString:activityPackage.parameters queueSize:queueSize]; - NSData *body = [NSData dataWithBytes:bodyString.UTF8String length:bodyString.length]; - [request setHTTPBody:body]; - - return request; -} - + (void)sendRequest:(NSMutableURLRequest *)request prefixErrorMessage:(NSString *)prefixErrorMessage activityPackage:(ADJActivityPackage *)activityPackage + secretId:(NSString *)secretId + appSecret:(NSString *)appSecret responseDataHandler:(void (^)(ADJResponseData *responseData))responseDataHandler { [ADJUtil sendRequest:request prefixErrorMessage:prefixErrorMessage suffixErrorMessage:nil + secretId:secretId + appSecret:appSecret + activityPackage:activityPackage + responseDataHandler:responseDataHandler]; +} + ++ (void)sendPostRequest:(NSURL *)baseUrl + queueSize:(NSUInteger)queueSize + prefixErrorMessage:(NSString *)prefixErrorMessage + suffixErrorMessage:(NSString *)suffixErrorMessage + activityPackage:(ADJActivityPackage *)activityPackage + responseDataHandler:(void (^)(ADJResponseData *responseData))responseDataHandler { + + NSString *appSecret = [ADJUtil extractAppSecret:activityPackage]; + NSString *secretId = [ADJUtil extractSecretId:activityPackage]; + + NSMutableURLRequest *request = [ADJUtil requestForPostPackage:activityPackage baseUrl:baseUrl queueSize:queueSize]; + + [ADJUtil sendRequest:request + prefixErrorMessage:prefixErrorMessage + suffixErrorMessage:suffixErrorMessage + secretId:secretId + appSecret:appSecret activityPackage:activityPackage responseDataHandler:responseDataHandler]; } @@ -399,14 +578,24 @@ + (void)sendRequest:(NSMutableURLRequest *)request + (void)sendRequest:(NSMutableURLRequest *)request prefixErrorMessage:(NSString *)prefixErrorMessage suffixErrorMessage:(NSString *)suffixErrorMessage + secretId:(NSString *)secretId + appSecret:(NSString *)appSecret activityPackage:(ADJActivityPackage *)activityPackage responseDataHandler:(void (^)(ADJResponseData *responseData))responseDataHandler { - Class NSURLSessionClass = NSClassFromString(@"NSURLSession"); + + 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"]; } + Class NSURLSessionClass = NSClassFromString(@"NSURLSession"); if (NSURLSessionClass != nil) { [ADJUtil sendNSURLSessionRequest:request prefixErrorMessage:prefixErrorMessage @@ -422,12 +611,176 @@ + (void)sendRequest:(NSMutableURLRequest *)request } } ++ (NSString *)extractAppSecret:(ADJActivityPackage *)activityPackage { + NSString *appSecret = [activityPackage.parameters objectForKey:@"app_secret"]; + + if (appSecret == nil) { + return nil; + } + + [activityPackage.parameters removeObjectForKey:@"app_secret"]; + + return appSecret; +} + ++ (NSString *)extractSecretId:(ADJActivityPackage *)activityPackage { + NSString *appSecret = [activityPackage.parameters objectForKey:@"secret_id"]; + + if (appSecret == nil) { + return nil; + } + + [activityPackage.parameters removeObjectForKey:@"secret_id"]; + + return appSecret; +} + ++ (NSMutableURLRequest *)requestForGetPackage:(ADJActivityPackage *)activityPackage + baseUrl:(NSURL *)baseUrl{ + NSString *parameters = [ADJUtil queryString:activityPackage.parameters]; + NSString *relativePath = [NSString stringWithFormat:@"%@?%@", activityPackage.path, parameters]; + 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"]; + + return request; +} + ++ (NSMutableURLRequest *)requestForPostPackage:(ADJActivityPackage *)activityPackage + baseUrl:(NSURL *)baseUrl + queueSize:(NSUInteger)queueSize { + NSURL *url = [NSURL URLWithString:activityPackage.path relativeToURL:baseUrl]; + 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"]; + + NSString *bodyString = [ADJUtil queryString:activityPackage.parameters queueSize:queueSize]; + NSData *body = [NSData dataWithBytes:bodyString.UTF8String length:bodyString.length]; + [request setHTTPBody:body]; + + return request; +} + ++ (NSString *)buildAuthorizationHeader:(NSString *)appSecret + secretId:(NSString *)secretId + activityPackage:(ADJActivityPackage *)activityPackage { + if (appSecret == nil) { + return nil; + } + + 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]; + + // algorithm part of header + 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) { + [fields deleteCharactersInRange:NSMakeRange(fields.length - 1, 1)]; + } + + NSString *fieldsHeader = [NSString stringWithFormat:@"headers=\"%@\"", fields]; + + // putting it all together + NSString *authorizationHeader = [NSString stringWithFormat:@"Signature %@,%@,%@,%@", secretIdHeader, signatureHeader, algorithmHeader, fieldsHeader]; + + [ADJAdjustFactory.logger debug:@"authorizationHeader %@", authorizationHeader]; + + + return authorizationHeader; +} + ++ (NSDictionary *)buildSignatureParameters:(NSMutableDictionary *)parameters + appSecret:(NSString *)appSecret + 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; +} + ++ (void)checkAndAddEntry:(NSMutableDictionary *)parameters + key:(NSString *)key + value:(NSString *)value { + if (key == nil) { + return; + } + + if (value == nil) { + return; + } + + [parameters setObject:value forKey:key]; +} + ++ (NSString *)getValidIdentifier:(NSMutableDictionary *)parameters { + NSString *idfaName = @"idfa"; + NSString *persistentUUIDName = @"persistent_ios_uuid"; + NSString *uuidName = @"ios_uuid"; + + if ([parameters objectForKey:idfaName] != nil) { + return idfaName; + } + + if ([parameters objectForKey:persistentUUIDName] != nil) { + return persistentUUIDName; + } + + if ([parameters objectForKey:uuidName] != nil) { + return uuidName; + } + + return nil; +} + + (void)sendNSURLSessionRequest:(NSMutableURLRequest *)request prefixErrorMessage:(NSString *)prefixErrorMessage suffixErrorMessage:(NSString *)suffixErrorMessage activityPackage:(ADJActivityPackage *)activityPackage responseDataHandler:(void (^)(ADJResponseData *responseData))responseDataHandler { - NSURLSession *session = [NSURLSession sessionWithConfiguration:urlSessionConfiguration]; + NSURLSession *session = [NSURLSession sessionWithConfiguration:[ADJUtil getUrlSessionConfiguration]]; NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler: @@ -546,7 +899,9 @@ + (NSDictionary *)convertDictionaryValues:(NSDictionary *)dictionary { } else if ([value isKindOfClass:[NSDate class]]) { // Format date to our custom format NSString *dateStingValue = [ADJUtil formatDate:value]; - [convertedDictionary setObject:dateStingValue forKey:key]; + if (dateStingValue != nil) { + [convertedDictionary setObject:dateStingValue forKey:key]; + } } else { // Convert all other objects directly to string NSString *stringValue = [NSString stringWithFormat:@"%@", value]; @@ -739,6 +1094,10 @@ + (NSString *)secondsNumberFormat:(double)seconds { seconds = seconds * -1; } + if (secondsNumberFormatter == nil) { + return nil; + } + return [secondsNumberFormatter stringFromNumber:[NSNumber numberWithDouble:seconds]]; } @@ -862,33 +1221,32 @@ + (void)launchInQueue:(dispatch_queue_t)queue }); } -+ (NSString *)getFilename:(NSString *)filename { - NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); - NSString *path = [paths objectAtIndex:0]; - NSString *filepath = [path stringByAppendingPathComponent:filename]; ++ (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 filepath; + return deletedDocumentsFilePath || deletedAppSupportFilePath; } -+ (BOOL)deleteFile:(NSString *)filename { - NSString *filepath = [ADJUtil getFilename:filename]; - NSFileManager *fileManager = [NSFileManager defaultManager]; - NSError *error = nil; - BOOL exists = [fileManager fileExistsAtPath:filepath]; ++ (BOOL)deleteFileInPath:(NSString *)filePath { + NSError *error; - if (!exists) { - [ADJAdjustFactory.logger verbose:@"File %@ does not exist at path %@", filename, filepath]; + if (![[NSFileManager defaultManager] fileExistsAtPath:filePath]) { + // [[ADJAdjustFactory logger] verbose:@"File does not exist at path %@", filePath]; return YES; } - BOOL deleted = [fileManager removeItemAtPath:filepath error:&error]; + BOOL deleted = [[NSFileManager defaultManager] removeItemAtPath:filePath error:&error]; if (!deleted) { - [ADJAdjustFactory.logger verbose:@"Unable to delete file %@ at path %@", filename, filepath]; + [[ADJAdjustFactory logger] verbose:@"Unable to delete file at path %@", filePath]; } if (error) { - [ADJAdjustFactory.logger error:@"Error (%@) deleting file %@", [error localizedDescription], filename]; + [[ADJAdjustFactory logger] error:@"Error while deleting file at path %@", filePath]; } return deleted; @@ -1006,4 +1364,49 @@ + (BOOL)contains:(NSDictionary *)dictionary return [value isEqualToString:[readValue description]]; } ++ (NSNumber *)readReachabilityFlags { + if (reachability == nil) { + return nil; + } + + return [reachability currentReachabilityFlags]; +} + +#if !TARGET_OS_TV ++ (NSString *)readMCC { + if (carrier == nil) { + return nil; + } + + return [carrier mobileCountryCode]; +} + ++ (NSString *)readMNC { + if (carrier == nil) { + return nil; + } + + return [carrier mobileNetworkCode]; +} + ++ (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 + @end diff --git a/Adjust/Adjust.h b/Adjust/Adjust.h index d96ef5a88..26d8bfd45 100644 --- a/Adjust/Adjust.h +++ b/Adjust/Adjust.h @@ -2,9 +2,9 @@ // Adjust.h // Adjust // -// V4.11.5 -// Created by Christian Wellenbrock on 2012-07-23. -// Copyright (c) 2012-2014 adjust GmbH. All rights reserved. +// V4.12.0 +// Created by Christian Wellenbrock (wellle) on 23rd July 2013. +// Copyright © 2012-2017 Adjust GmbH. All rights reserved. // #import "ADJEvent.h" @@ -193,7 +193,7 @@ extern NSString * __nonnull const ADJEnvironmentProduction; + (void)resetSessionPartnerParameters; /** - * Obtain singleton Adjust object + * Obtain singleton Adjust object. */ + (nullable id)getInstance; diff --git a/Adjust/Adjust.m b/Adjust/Adjust.m index eb6eb3a7a..750b937df 100644 --- a/Adjust/Adjust.m +++ b/Adjust/Adjust.m @@ -2,19 +2,20 @@ // Adjust.m // Adjust // -// Created by Christian Wellenbrock on 2012-07-23. -// Copyright (c) 2012-2014 adjust GmbH. All rights reserved. +// Created by Christian Wellenbrock (wellle) on 23rd July 2013. +// Copyright © 2012-2017 Adjust GmbH. All rights reserved. // #import "Adjust.h" #import "ADJUtil.h" #import "ADJLogger.h" +#import "ADJUserDefaults.h" #import "ADJAdjustFactory.h" #import "ADJActivityHandler.h" #if !__has_feature(objc_arc) #error Adjust requires ARC -// see README for details +// See README for details: https://github.com/adjust/ios_sdk/blob/master/README.md #endif NSString * const ADJEnvironmentSandbox = @"sandbox"; @@ -23,15 +24,44 @@ @interface Adjust() @property (nonatomic, weak) id logger; + @property (nonatomic, strong) id activityHandler; -@property (nonatomic, strong) NSMutableArray *sessionParametersActionsArray; -@property (nonatomic, copy) NSData *deviceTokenData; + +@property (nonatomic, strong) ADJSavedPreLaunch *savedPreLaunch; @end -#pragma mark - @implementation Adjust +#pragma mark - Object lifecycle methods + ++ (id)getInstance { + static Adjust *defaultInstance = nil; + static dispatch_once_t onceToken; + + dispatch_once(&onceToken, ^{ + defaultInstance = [[self alloc] init]; + }); + + return defaultInstance; +} + +- (id)init { + self = [super init]; + + if (self == nil) { + return nil; + } + + self.activityHandler = nil; + self.logger = [ADJAdjustFactory logger]; + self.savedPreLaunch = [[ADJSavedPreLaunch alloc] init]; + + return self; +} + +#pragma mark - Public static methods + + (void)appDidLaunch:(ADJConfig *)adjustConfig { [[Adjust getInstance] appDidLaunch:adjustConfig]; } @@ -49,7 +79,8 @@ + (void)trackSubsessionEnd { } + (void)setEnabled:(BOOL)enabled { - [[Adjust getInstance] setEnabled:enabled]; + Adjust *instance = [Adjust getInstance]; + [instance setEnabled:enabled]; } + (BOOL)isEnabled { @@ -84,14 +115,12 @@ + (void)sendFirstPackages { [[Adjust getInstance] sendFirstPackages]; } -+ (void)addSessionCallbackParameter:(NSString *)key - value:(NSString *)value { ++ (void)addSessionCallbackParameter:(NSString *)key value:(NSString *)value { [[Adjust getInstance] addSessionCallbackParameter:key value:value]; } -+ (void)addSessionPartnerParameter:(NSString *)key - value:(NSString *)value { ++ (void)addSessionPartnerParameter:(NSString *)key value:(NSString *)value { [[Adjust getInstance] addSessionPartnerParameter:key value:value]; } @@ -120,25 +149,7 @@ + (NSString *)adid { return [[Adjust getInstance] adid]; } -+ (id)getInstance { - static Adjust *defaultInstance = nil; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - defaultInstance = [[self alloc] init]; - }); - - return defaultInstance; -} - -- (id) init { - self = [super init]; - if (self == nil) return nil; - - self.activityHandler = nil; - self.logger = [ADJAdjustFactory logger]; - - return self; -} +#pragma mark - Public instance methods - (void)appDidLaunch:(ADJConfig *)adjustConfig { if (self.activityHandler != nil) { @@ -147,50 +158,77 @@ - (void)appDidLaunch:(ADJConfig *)adjustConfig { } self.activityHandler = [ADJAdjustFactory activityHandlerWithConfig:adjustConfig - sessionParametersActionsArray:self.sessionParametersActionsArray - deviceToken:self.deviceTokenData]; + savedPreLaunch:self.savedPreLaunch]; } - (void)trackEvent:(ADJEvent *)event { - if (![self checkActivityHandler]) return; + if (![self checkActivityHandler]) { + return; + } + [self.activityHandler trackEvent:event]; } - (void)trackSubsessionStart { - if (![self checkActivityHandler]) return; + if (![self checkActivityHandler]) { + return; + } + [self.activityHandler applicationDidBecomeActive]; } - (void)trackSubsessionEnd { - if (![self checkActivityHandler]) return; + if (![self checkActivityHandler]) { + return; + } + [self.activityHandler applicationWillResignActive]; } - (void)setEnabled:(BOOL)enabled { - if (![self checkActivityHandler]) return; - [self.activityHandler setEnabled:enabled]; + self.savedPreLaunch.enabled = [NSNumber numberWithBool:enabled]; + + if ([self checkActivityHandler:enabled + trueMessage:@"enabled mode" + falseMessage:@"disabled mode"]) { + [self.activityHandler setEnabled:enabled]; + } } - (BOOL)isEnabled { - if (![self checkActivityHandler]) return NO; + if (![self checkActivityHandler]) { + return [self isInstanceEnabled]; + } + return [self.activityHandler isEnabled]; } - (void)appWillOpenUrl:(NSURL *)url { - if (![self checkActivityHandler]) return; - [self.activityHandler appWillOpenUrl:url]; + if (![self checkActivityHandler]) { + return; + } + + [self.activityHandler appWillOpenUrl:url]; } - (void)setDeviceToken:(NSData *)deviceToken { - self.deviceTokenData = deviceToken; - if (self.activityHandler != nil) { - [self.activityHandler setDeviceToken:deviceToken]; + [ADJUserDefaults savePushToken:deviceToken]; + + if ([self checkActivityHandler:@"device token"]) { + if (self.activityHandler.isEnabled) { + [self.activityHandler setDeviceToken:deviceToken]; + } } } - (void)setOfflineMode:(BOOL)enabled { - if (![self checkActivityHandler]) return; - [self.activityHandler setOfflineMode:enabled]; + if (![self checkActivityHandler:enabled + trueMessage:@"offline mode" + falseMessage:@"online mode"]) { + self.savedPreLaunch.offline = enabled; + } else { + [self.activityHandler setOfflineMode:enabled]; + } } - (NSString *)idfa { @@ -202,109 +240,116 @@ - (NSURL *)convertUniversalLink:(NSURL *)url scheme:(NSString *)scheme { } - (void)sendFirstPackages { - if (![self checkActivityHandler]) return; + if (![self checkActivityHandler]) { + return; + } + [self.activityHandler sendFirstPackages]; } -- (void)addSessionCallbackParameter:(NSString *)key - value:(NSString *)value { - if (self.activityHandler != nil) { +- (void)addSessionCallbackParameter:(NSString *)key value:(NSString *)value { + if ([self checkActivityHandler:@"adding session callback parameter"]) { [self.activityHandler addSessionCallbackParameter:key value:value]; return; } - if (self.sessionParametersActionsArray == nil) { - self.sessionParametersActionsArray = [[NSMutableArray alloc] init]; + if (self.savedPreLaunch.preLaunchActionsArray == nil) { + self.savedPreLaunch.preLaunchActionsArray = [[NSMutableArray alloc] init]; } - [self.sessionParametersActionsArray addObject:^(ADJActivityHandler * activityHandler){ + [self.savedPreLaunch.preLaunchActionsArray addObject:^(ADJActivityHandler *activityHandler) { [activityHandler addSessionCallbackParameterI:activityHandler key:key value:value]; }]; } -- (void)addSessionPartnerParameter:(NSString *)key - value:(NSString *)value { - if (self.activityHandler != nil) { +- (void)addSessionPartnerParameter:(NSString *)key value:(NSString *)value { + if ([self checkActivityHandler:@"adding session partner parameter"]) { [self.activityHandler addSessionPartnerParameter:key value:value]; return; } - if (self.sessionParametersActionsArray == nil) { - self.sessionParametersActionsArray = [[NSMutableArray alloc] init]; + if (self.savedPreLaunch.preLaunchActionsArray == nil) { + self.savedPreLaunch.preLaunchActionsArray = [[NSMutableArray alloc] init]; } - [self.sessionParametersActionsArray addObject:^(ADJActivityHandler * activityHandler){ + [self.savedPreLaunch.preLaunchActionsArray addObject:^(ADJActivityHandler *activityHandler) { [activityHandler addSessionPartnerParameterI:activityHandler key:key value:value]; }]; } - (void)removeSessionCallbackParameter:(NSString *)key { - if (self.activityHandler != nil) { + if ([self checkActivityHandler:@"removing session callback parameter"]) { [self.activityHandler removeSessionCallbackParameter:key]; return; } - if (self.sessionParametersActionsArray == nil) { - self.sessionParametersActionsArray = [[NSMutableArray alloc] init]; + if (self.savedPreLaunch.preLaunchActionsArray == nil) { + self.savedPreLaunch.preLaunchActionsArray = [[NSMutableArray alloc] init]; } - [self.sessionParametersActionsArray addObject:^(ADJActivityHandler * activityHandler){ + [self.savedPreLaunch.preLaunchActionsArray addObject:^(ADJActivityHandler *activityHandler) { [activityHandler removeSessionCallbackParameterI:activityHandler key:key]; }]; } - (void)removeSessionPartnerParameter:(NSString *)key { - if (self.activityHandler != nil) { + if ([self checkActivityHandler:@"removing session partner parameter"]) { [self.activityHandler removeSessionPartnerParameter:key]; return; } - if (self.sessionParametersActionsArray == nil) { - self.sessionParametersActionsArray = [[NSMutableArray alloc] init]; + if (self.savedPreLaunch.preLaunchActionsArray == nil) { + self.savedPreLaunch.preLaunchActionsArray = [[NSMutableArray alloc] init]; } - [self.sessionParametersActionsArray addObject:^(ADJActivityHandler * activityHandler){ + [self.savedPreLaunch.preLaunchActionsArray addObject:^(ADJActivityHandler *activityHandler) { [activityHandler removeSessionPartnerParameterI:activityHandler key:key]; }]; } - (void)resetSessionCallbackParameters { - if (self.activityHandler != nil) { + if ([self checkActivityHandler:@"resetting session callback parameters"]) { [self.activityHandler resetSessionCallbackParameters]; return; } - if (self.sessionParametersActionsArray == nil) { - self.sessionParametersActionsArray = [[NSMutableArray alloc] init]; + if (self.savedPreLaunch.preLaunchActionsArray == nil) { + self.savedPreLaunch.preLaunchActionsArray = [[NSMutableArray alloc] init]; } - [self.sessionParametersActionsArray addObject:^(ADJActivityHandler * activityHandler){ + [self.savedPreLaunch.preLaunchActionsArray addObject:^(ADJActivityHandler *activityHandler) { [activityHandler resetSessionCallbackParametersI:activityHandler]; }]; } - (void)resetSessionPartnerParameters { - if (self.activityHandler != nil) { + if ([self checkActivityHandler:@"resetting session partner parameters"]) { [self.activityHandler resetSessionPartnerParameters]; return; } - if (self.sessionParametersActionsArray == nil) { - self.sessionParametersActionsArray = [[NSMutableArray alloc] init]; + if (self.savedPreLaunch.preLaunchActionsArray == nil) { + self.savedPreLaunch.preLaunchActionsArray = [[NSMutableArray alloc] init]; } - [self.sessionParametersActionsArray addObject:^(ADJActivityHandler * activityHandler){ + [self.savedPreLaunch.preLaunchActionsArray addObject:^(ADJActivityHandler *activityHandler) { [activityHandler resetSessionPartnerParametersI:activityHandler]; }]; } - (ADJAttribution *)attribution { - if (![self checkActivityHandler]) return nil; + if (![self checkActivityHandler]) { + return nil; + } + return [self.activityHandler attribution]; } - (NSString *)adid { - if (![self checkActivityHandler]) return nil; + if (![self checkActivityHandler]) { + return nil; + } + return [self.activityHandler adid]; } @@ -312,20 +357,44 @@ - (void)teardown:(BOOL)deleteState { if (self.activityHandler == nil) { [self.logger error:@"Adjust already down or not initialized"]; return; - } + } + [self.activityHandler teardown:deleteState]; self.activityHandler = nil; } -#pragma mark - private +#pragma mark - Private & helper methods - (BOOL)checkActivityHandler { + return [self checkActivityHandler:nil]; +} + +- (BOOL)checkActivityHandler:(BOOL)status + trueMessage:(NSString *)trueMessage + falseMessage:(NSString *)falseMessage { + if (status) { + return [self checkActivityHandler:trueMessage]; + } else { + return [self checkActivityHandler:falseMessage]; + } +} + +- (BOOL)checkActivityHandler:(NSString *)savedForLaunchWarningSuffixMessage { if (self.activityHandler == nil) { - [self.logger error:@"Please initialize Adjust by calling 'appDidLaunch' before"]; + if (savedForLaunchWarningSuffixMessage != nil) { + [self.logger warn:@"Adjust not initialized, but %@ saved for launch", savedForLaunchWarningSuffixMessage]; + } else { + [self.logger error:@"Please initialize Adjust by calling 'appDidLaunch' before"]; + } + return NO; } else { return YES; } } +- (BOOL)isInstanceEnabled { + return self.savedPreLaunch.enabled == nil || self.savedPreLaunch.enabled; +} + @end diff --git a/AdjustBridge/AdjustBridge.m b/AdjustBridge/AdjustBridge.m index 21d7ef044..35d1fff0e 100644 --- a/AdjustBridge/AdjustBridge.m +++ b/AdjustBridge/AdjustBridge.m @@ -265,7 +265,7 @@ - (void)loadWebViewBridge { if ([adjustConfig isValid]) { // Log level if ([self isFieldValid:logLevel]) { - [adjustConfig setLogLevel:[ADJLogger LogLevelFromString:[logLevel lowercaseString]]]; + [adjustConfig setLogLevel:[ADJLogger logLevelFromString:[logLevel lowercaseString]]]; } // Sending in background diff --git a/AdjustBridge/AdjustBridgeRegister.h b/AdjustBridge/AdjustBridgeRegister.h index f1531109b..3e337adcf 100644 --- a/AdjustBridge/AdjustBridgeRegister.h +++ b/AdjustBridge/AdjustBridgeRegister.h @@ -8,7 +8,6 @@ #import #import "WebViewJavascriptBridge.h" -#import "WKWebViewJavascriptBridge.h" @protocol AdjustBridgeRegister diff --git a/AdjustBridge/AdjustBridgeRegister.m b/AdjustBridge/AdjustBridgeRegister.m index 06a52083a..b1abfc3b8 100644 --- a/AdjustBridge/AdjustBridgeRegister.m +++ b/AdjustBridge/AdjustBridgeRegister.m @@ -58,7 +58,7 @@ - (void)callHandler:(NSString *)handlerName data:(id)data { @interface AdjustWKBridgeRegister() -@property (nonatomic, strong) WKWebViewJavascriptBridge *wkBridge; +@property (nonatomic, strong) WebViewJavascriptBridge *wkBridge; @end @@ -75,7 +75,7 @@ - (id)initWithWKWebView:(WKWebView *)wkWebView { return nil; } - self.wkBridge = [WKWebViewJavascriptBridge bridgeForWebView:wkWebView]; + self.wkBridge = [WebViewJavascriptBridge bridgeForWebView:wkWebView]; return self; } diff --git a/AdjustBridge/WebViewJavascriptBridge/WKWebViewJavascriptBridge.h b/AdjustBridge/WebViewJavascriptBridge/WKWebViewJavascriptBridge.h index 99859f007..4e3404fc0 100644 --- a/AdjustBridge/WebViewJavascriptBridge/WKWebViewJavascriptBridge.h +++ b/AdjustBridge/WebViewJavascriptBridge/WKWebViewJavascriptBridge.h @@ -6,10 +6,10 @@ // #if (__MAC_OS_X_VERSION_MAX_ALLOWED > __MAC_10_9 || __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_7_1) -#define supportsWKWebKit +#define supportsWKWebView #endif -#if defined(supportsWKWebKit ) +#if defined supportsWKWebView #import #import "WebViewJavascriptBridgeBase.h" @@ -21,12 +21,14 @@ + (void)enableLogging; - (void)registerHandler:(NSString*)handlerName handler:(WVJBHandler)handler; +- (void)removeHandler:(NSString*)handlerName; - (void)callHandler:(NSString*)handlerName; - (void)callHandler:(NSString*)handlerName data:(id)data; - (void)callHandler:(NSString*)handlerName data:(id)data responseCallback:(WVJBResponseCallback)responseCallback; - (void)reset; -- (void)setWebViewDelegate:(id)webViewDelegate; +- (void)setWebViewDelegate:(id)webViewDelegate; +- (void)disableJavscriptAlertBoxSafetyTimeout; @end -#endif \ No newline at end of file +#endif diff --git a/AdjustBridge/WebViewJavascriptBridge/WKWebViewJavascriptBridge.m b/AdjustBridge/WebViewJavascriptBridge/WKWebViewJavascriptBridge.m index 0fcf7e25c..3c6caba1e 100644 --- a/AdjustBridge/WebViewJavascriptBridge/WKWebViewJavascriptBridge.m +++ b/AdjustBridge/WebViewJavascriptBridge/WKWebViewJavascriptBridge.m @@ -8,11 +8,11 @@ #import "WKWebViewJavascriptBridge.h" -#if defined(supportsWKWebKit) +#if defined supportsWKWebView @implementation WKWebViewJavascriptBridge { - WKWebView* _webView; - id _webViewDelegate; + __weak WKWebView* _webView; + __weak id _webViewDelegate; long _uniqueId; WebViewJavascriptBridgeBase *_base; } @@ -53,6 +53,10 @@ - (void)registerHandler:(NSString *)handlerName handler:(WVJBHandler)handler { _base.messageHandlers[handlerName] = [handler copy]; } +- (void)removeHandler:(NSString *)handlerName { + [_base.messageHandlers removeObjectForKey:handlerName]; +} + - (void)reset { [_base reset]; } @@ -61,6 +65,10 @@ - (void)setWebViewDelegate:(id)webViewDelegate { _webViewDelegate = webViewDelegate; } +- (void)disableJavscriptAlertBoxSafetyTimeout { + [_base disableJavscriptAlertBoxSafetyTimeout]; +} + /* Internals ***********/ @@ -92,8 +100,7 @@ - (void)WKFlushMessageQueue { }]; } -- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation -{ +- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation { if (webView != _webView) { return; } __strong typeof(_webViewDelegate) strongDelegate = _webViewDelegate; @@ -103,14 +110,35 @@ - (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigat } -- (void)webView:(WKWebView *)webView -decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction -decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler { +- (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler { + if (webView != _webView) { return; } + + __strong typeof(_webViewDelegate) strongDelegate = _webViewDelegate; + if (strongDelegate && [strongDelegate respondsToSelector:@selector(webView:decidePolicyForNavigationResponse:decisionHandler:)]) { + [strongDelegate webView:webView decidePolicyForNavigationResponse:navigationResponse decisionHandler:decisionHandler]; + } + else { + decisionHandler(WKNavigationResponsePolicyAllow); + } +} + +- (void)webView:(WKWebView *)webView didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential *))completionHandler { + if (webView != _webView) { return; } + + __strong typeof(_webViewDelegate) strongDelegate = _webViewDelegate; + if (strongDelegate && [strongDelegate respondsToSelector:@selector(webView:didReceiveAuthenticationChallenge:completionHandler:)]) { + [strongDelegate webView:webView didReceiveAuthenticationChallenge:challenge completionHandler:completionHandler]; + } else { + completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, nil); + } +} + +- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler { if (webView != _webView) { return; } NSURL *url = navigationAction.request.URL; __strong typeof(_webViewDelegate) strongDelegate = _webViewDelegate; - if ([_base isCorrectProcotocolScheme:url]) { + if ([_base isWebViewJavascriptBridgeURL:url]) { if ([_base isBridgeLoadedURL:url]) { [_base injectJavascriptFile]; } else if ([_base isQueueMessageURL:url]) { @@ -136,9 +164,7 @@ - (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation } -- (void)webView:(WKWebView *)webView -didFailNavigation:(WKNavigation *)navigation - withError:(NSError *)error { +- (void)webView:(WKWebView *)webView didFailNavigation:(WKNavigation *)navigation withError:(NSError *)error { if (webView != _webView) { return; } __strong typeof(_webViewDelegate) strongDelegate = _webViewDelegate; @@ -156,8 +182,7 @@ - (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation } } -- (NSString*) _evaluateJavascript:(NSString*)javascriptCommand -{ +- (NSString*) _evaluateJavascript:(NSString*)javascriptCommand { [_webView evaluateJavaScript:javascriptCommand completionHandler:nil]; return NULL; } diff --git a/AdjustBridge/WebViewJavascriptBridge/WebViewJavascriptBridge.h b/AdjustBridge/WebViewJavascriptBridge/WebViewJavascriptBridge.h index aff055312..1b64bb4e9 100755 --- a/AdjustBridge/WebViewJavascriptBridge/WebViewJavascriptBridge.h +++ b/AdjustBridge/WebViewJavascriptBridge/WebViewJavascriptBridge.h @@ -9,8 +9,15 @@ #import #import "WebViewJavascriptBridgeBase.h" +#if (__MAC_OS_X_VERSION_MAX_ALLOWED > __MAC_10_9 || __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_7_1) +#define supportsWKWebView +#endif + +#if defined supportsWKWebView +#import +#endif + #if defined __MAC_OS_X_VERSION_MAX_ALLOWED - #import #define WVJB_PLATFORM_OSX #define WVJB_WEBVIEW_TYPE WebView #define WVJB_WEBVIEW_DELEGATE_TYPE NSObject @@ -25,13 +32,19 @@ @interface WebViewJavascriptBridge : WVJB_WEBVIEW_DELEGATE_INTERFACE -+ (instancetype)bridgeForWebView:(WVJB_WEBVIEW_TYPE*)webView; + ++ (instancetype)bridgeForWebView:(id)webView; ++ (instancetype)bridge:(id)webView; + + (void)enableLogging; + (void)setLogMaxLength:(int)length; - (void)registerHandler:(NSString*)handlerName handler:(WVJBHandler)handler; +- (void)removeHandler:(NSString*)handlerName; - (void)callHandler:(NSString*)handlerName; - (void)callHandler:(NSString*)handlerName data:(id)data; - (void)callHandler:(NSString*)handlerName data:(id)data responseCallback:(WVJBResponseCallback)responseCallback; -- (void)setWebViewDelegate:(WVJB_WEBVIEW_DELEGATE_TYPE*)webViewDelegate; +- (void)setWebViewDelegate:(id)webViewDelegate; +- (void)disableJavscriptAlertBoxSafetyTimeout; + @end diff --git a/AdjustBridge/WebViewJavascriptBridge/WebViewJavascriptBridge.m b/AdjustBridge/WebViewJavascriptBridge/WebViewJavascriptBridge.m index 20e88d4f9..e74a6e24e 100755 --- a/AdjustBridge/WebViewJavascriptBridge/WebViewJavascriptBridge.m +++ b/AdjustBridge/WebViewJavascriptBridge/WebViewJavascriptBridge.m @@ -8,6 +8,10 @@ #import "WebViewJavascriptBridge.h" +#if defined(supportsWKWebView) +#import "WKWebViewJavascriptBridge.h" +#endif + #if __has_feature(objc_arc_weak) #define WVJB_WEAK __weak #else @@ -24,13 +28,29 @@ @implementation WebViewJavascriptBridge { /* API *****/ -+ (void)enableLogging { [WebViewJavascriptBridgeBase enableLogging]; } -+ (void)setLogMaxLength:(int)length { [WebViewJavascriptBridgeBase setLogMaxLength:length]; } ++ (void)enableLogging { + [WebViewJavascriptBridgeBase enableLogging]; +} ++ (void)setLogMaxLength:(int)length { + [WebViewJavascriptBridgeBase setLogMaxLength:length]; +} -+ (instancetype)bridgeForWebView:(WVJB_WEBVIEW_TYPE*)webView { - WebViewJavascriptBridge* bridge = [[self alloc] init]; - [bridge _platformSpecificSetup:webView]; - return bridge; ++ (instancetype)bridgeForWebView:(id)webView { + return [self bridge:webView]; +} ++ (instancetype)bridge:(id)webView { +#if defined supportsWKWebView + if ([webView isKindOfClass:[WKWebView class]]) { + return (WebViewJavascriptBridge*) [WKWebViewJavascriptBridge bridgeForWebView:webView]; + } +#endif + if ([webView isKindOfClass:[WVJB_WEBVIEW_TYPE class]]) { + WebViewJavascriptBridge* bridge = [[self alloc] init]; + [bridge _platformSpecificSetup:webView]; + return bridge; + } + [NSException raise:@"BadWebViewType" format:@"Unknown web view type."]; + return nil; } - (void)setWebViewDelegate:(WVJB_WEBVIEW_DELEGATE_TYPE*)webViewDelegate { @@ -61,6 +81,15 @@ - (void)registerHandler:(NSString *)handlerName handler:(WVJBHandler)handler { _base.messageHandlers[handlerName] = [handler copy]; } +- (void)removeHandler:(NSString *)handlerName { + [_base.messageHandlers removeObjectForKey:handlerName]; +} + +- (void)disableJavscriptAlertBoxSafetyTimeout { + [_base disableJavscriptAlertBoxSafetyTimeout]; +} + + /* Platform agnostic internals *****************************/ @@ -71,20 +100,17 @@ - (void)dealloc { _webViewDelegate = nil; } -- (NSString*) _evaluateJavascript:(NSString*)javascriptCommand -{ +- (NSString*) _evaluateJavascript:(NSString*)javascriptCommand { return [_webView stringByEvaluatingJavaScriptFromString:javascriptCommand]; } +#if defined WVJB_PLATFORM_OSX /* Platform specific internals: OSX **********************************/ -#if defined WVJB_PLATFORM_OSX - (void) _platformSpecificSetup:(WVJB_WEBVIEW_TYPE*)webView { _webView = webView; - _webView.policyDelegate = self; - _base = [[WebViewJavascriptBridgeBase alloc] init]; _base.delegate = self; } @@ -93,12 +119,11 @@ - (void) _platformSpecificDealloc { _webView.policyDelegate = nil; } -- (void)webView:(WebView *)webView decidePolicyForNavigationAction:(NSDictionary *)actionInformation request:(NSURLRequest *)request frame:(WebFrame *)frame decisionListener:(id)listener -{ +- (void)webView:(WebView *)webView decidePolicyForNavigationAction:(NSDictionary *)actionInformation request:(NSURLRequest *)request frame:(WebFrame *)frame decisionListener:(id)listener { if (webView != _webView) { return; } NSURL *url = [request URL]; - if ([_base isCorrectProcotocolScheme:url]) { + if ([_base isWebViewJavascriptBridgeURL:url]) { if ([_base isBridgeLoadedURL:url]) { [_base injectJavascriptFile]; } else if ([_base isQueueMessageURL:url]) { @@ -117,9 +142,9 @@ - (void)webView:(WebView *)webView decidePolicyForNavigationAction:(NSDictionary +#elif defined WVJB_PLATFORM_IOS /* Platform specific internals: iOS **********************************/ -#elif defined WVJB_PLATFORM_IOS - (void) _platformSpecificSetup:(WVJB_WEBVIEW_TYPE*)webView { _webView = webView; @@ -152,9 +177,10 @@ - (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error { - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType { if (webView != _webView) { return YES; } + NSURL *url = [request URL]; __strong WVJB_WEBVIEW_DELEGATE_TYPE* strongDelegate = _webViewDelegate; - if ([_base isCorrectProcotocolScheme:url]) { + if ([_base isWebViewJavascriptBridgeURL:url]) { if ([_base isBridgeLoadedURL:url]) { [_base injectJavascriptFile]; } else if ([_base isQueueMessageURL:url]) { diff --git a/AdjustBridge/WebViewJavascriptBridge/WebViewJavascriptBridgeBase.h b/AdjustBridge/WebViewJavascriptBridge/WebViewJavascriptBridgeBase.h index 16b23c794..54d80acc6 100755 --- a/AdjustBridge/WebViewJavascriptBridge/WebViewJavascriptBridgeBase.h +++ b/AdjustBridge/WebViewJavascriptBridge/WebViewJavascriptBridgeBase.h @@ -7,9 +7,10 @@ #import -#define kCustomProtocolScheme @"wvjbscheme" -#define kQueueHasMessage @"__WVJB_QUEUE_MESSAGE__" -#define kBridgeLoaded @"__BRIDGE_LOADED__" +#define kOldProtocolScheme @"wvjbscheme" +#define kNewProtocolScheme @"https" +#define kQueueHasMessage @"__wvjb_queue_message__" +#define kBridgeLoaded @"__bridge_loaded__" typedef void (^WVJBResponseCallback)(id responseData); typedef void (^WVJBHandler)(id data, WVJBResponseCallback responseCallback); @@ -22,7 +23,7 @@ typedef NSDictionary WVJBMessage; @interface WebViewJavascriptBridgeBase : NSObject -@property (assign) id delegate; +@property (weak, nonatomic) id delegate; @property (strong, nonatomic) NSMutableArray* startupMessageQueue; @property (strong, nonatomic) NSMutableDictionary* responseCallbacks; @property (strong, nonatomic) NSMutableDictionary* messageHandlers; @@ -34,11 +35,12 @@ typedef NSDictionary WVJBMessage; - (void)sendData:(id)data responseCallback:(WVJBResponseCallback)responseCallback handlerName:(NSString*)handlerName; - (void)flushMessageQueue:(NSString *)messageQueueString; - (void)injectJavascriptFile; -- (BOOL)isCorrectProcotocolScheme:(NSURL*)url; +- (BOOL)isWebViewJavascriptBridgeURL:(NSURL*)url; - (BOOL)isQueueMessageURL:(NSURL*)urll; - (BOOL)isBridgeLoadedURL:(NSURL*)urll; - (void)logUnkownMessage:(NSURL*)url; - (NSString *)webViewJavascriptCheckCommand; - (NSString *)webViewJavascriptFetchQueyCommand; +- (void)disableJavscriptAlertBoxSafetyTimeout; -@end \ No newline at end of file +@end diff --git a/AdjustBridge/WebViewJavascriptBridge/WebViewJavascriptBridgeBase.m b/AdjustBridge/WebViewJavascriptBridge/WebViewJavascriptBridgeBase.m index f290a48dd..3ec26ed41 100755 --- a/AdjustBridge/WebViewJavascriptBridge/WebViewJavascriptBridgeBase.m +++ b/AdjustBridge/WebViewJavascriptBridge/WebViewJavascriptBridgeBase.m @@ -10,7 +10,7 @@ #import "WebViewJavascriptBridge_JS.h" @implementation WebViewJavascriptBridgeBase { - id _webViewDelegate; + __weak id _webViewDelegate; long _uniqueId; } @@ -20,13 +20,14 @@ @implementation WebViewJavascriptBridgeBase { + (void)enableLogging { logging = true; } + (void)setLogMaxLength:(int)length { logMaxLength = length;} --(id)init { - self = [super init]; - self.messageHandlers = [NSMutableDictionary dictionary]; - self.startupMessageQueue = [NSMutableArray array]; - self.responseCallbacks = [NSMutableDictionary dictionary]; - _uniqueId = 0; - return(self); +- (id)init { + if (self = [super init]) { + self.messageHandlers = [NSMutableDictionary dictionary]; + self.startupMessageQueue = [NSMutableArray array]; + self.responseCallbacks = [NSMutableDictionary dictionary]; + _uniqueId = 0; + } + return self; } - (void)dealloc { @@ -121,38 +122,44 @@ - (void)injectJavascriptFile { } } --(BOOL)isCorrectProcotocolScheme:(NSURL*)url { - if([[url scheme] isEqualToString:kCustomProtocolScheme]){ - return YES; - } else { +- (BOOL)isWebViewJavascriptBridgeURL:(NSURL*)url { + if (![self isSchemeMatch:url]) { return NO; } + return [self isBridgeLoadedURL:url] || [self isQueueMessageURL:url]; } --(BOOL)isQueueMessageURL:(NSURL*)url { - if([[url host] isEqualToString:kQueueHasMessage]){ - return YES; - } else { - return NO; - } +- (BOOL)isSchemeMatch:(NSURL*)url { + NSString* scheme = url.scheme.lowercaseString; + return [scheme isEqualToString:kNewProtocolScheme] || [scheme isEqualToString:kOldProtocolScheme]; +} + +- (BOOL)isQueueMessageURL:(NSURL*)url { + NSString* host = url.host.lowercaseString; + return [self isSchemeMatch:url] && [host isEqualToString:kQueueHasMessage]; } --(BOOL)isBridgeLoadedURL:(NSURL*)url { - return ([[url scheme] isEqualToString:kCustomProtocolScheme] && [[url host] isEqualToString:kBridgeLoaded]); +- (BOOL)isBridgeLoadedURL:(NSURL*)url { + NSString* host = url.host.lowercaseString; + return [self isSchemeMatch:url] && [host isEqualToString:kBridgeLoaded]; } --(void)logUnkownMessage:(NSURL*)url { - NSLog(@"WebViewJavascriptBridge: WARNING: Received unknown WebViewJavascriptBridge command %@://%@", kCustomProtocolScheme, [url path]); +- (void)logUnkownMessage:(NSURL*)url { + NSLog(@"WebViewJavascriptBridge: WARNING: Received unknown WebViewJavascriptBridge command %@", [url absoluteString]); } --(NSString *)webViewJavascriptCheckCommand { +- (NSString *)webViewJavascriptCheckCommand { return @"typeof WebViewJavascriptBridge == \'object\';"; } --(NSString *)webViewJavascriptFetchQueyCommand { +- (NSString *)webViewJavascriptFetchQueyCommand { return @"WebViewJavascriptBridge._fetchQueue();"; } +- (void)disableJavscriptAlertBoxSafetyTimeout { + [self sendData:nil responseCallback:nil handlerName:@"_disableJavascriptAlertBoxSafetyTimeout"]; +} + // Private // ------------------------------------------- @@ -211,4 +218,4 @@ - (void)_log:(NSString *)action json:(id)json { } } -@end \ No newline at end of file +@end diff --git a/AdjustBridge/WebViewJavascriptBridge/WebViewJavascriptBridge_JS.m b/AdjustBridge/WebViewJavascriptBridge/WebViewJavascriptBridge_JS.m index 3a494dd4d..670a552f1 100644 --- a/AdjustBridge/WebViewJavascriptBridge/WebViewJavascriptBridge_JS.m +++ b/AdjustBridge/WebViewJavascriptBridge/WebViewJavascriptBridge_JS.m @@ -19,9 +19,16 @@ if (window.WebViewJavascriptBridge) { return; } + + if (!window.onerror) { + window.onerror = function(msg, url, line) { + console.log("WebViewJavascriptBridge: ERROR:" + msg + "@" + url + ":" + line); + } + } window.WebViewJavascriptBridge = { registerHandler: registerHandler, callHandler: callHandler, + disableJavscriptAlertBoxSafetyTimeout: disableJavscriptAlertBoxSafetyTimeout, _fetchQueue: _fetchQueue, _handleMessageFromObjC: _handleMessageFromObjC }; @@ -30,11 +37,12 @@ var sendMessageQueue = []; var messageHandlers = {}; - var CUSTOM_PROTOCOL_SCHEME = 'wvjbscheme'; - var QUEUE_HAS_MESSAGE = '__WVJB_QUEUE_MESSAGE__'; + var CUSTOM_PROTOCOL_SCHEME = 'https'; + var QUEUE_HAS_MESSAGE = '__wvjb_queue_message__'; var responseCallbacks = {}; var uniqueId = 1; + var dispatchMessagesWithTimeoutSafety = true; function registerHandler(handlerName, handler) { messageHandlers[handlerName] = handler; @@ -47,6 +55,9 @@ function callHandler(handlerName, data, responseCallback) { } _doSend({ handlerName:handlerName, data:data }, responseCallback); } + function disableJavscriptAlertBoxSafetyTimeout() { + dispatchMessagesWithTimeoutSafety = false; + } function _doSend(message, responseCallback) { if (responseCallback) { @@ -65,7 +76,13 @@ function _fetchQueue() { } function _dispatchMessageFromObjC(messageJSON) { - setTimeout(function _timeoutDispatchMessageFromObjC() { + if (dispatchMessagesWithTimeoutSafety) { + setTimeout(_doDispatchMessageFromObjC); + } else { + _doDispatchMessageFromObjC(); + } + + function _doDispatchMessageFromObjC() { var message = JSON.parse(messageJSON); var messageHandler; var responseCallback; @@ -81,21 +98,18 @@ function _dispatchMessageFromObjC(messageJSON) { if (message.callbackId) { var callbackResponseId = message.callbackId; responseCallback = function(responseData) { - _doSend({ responseId:callbackResponseId, responseData:responseData }); + _doSend({ handlerName:message.handlerName, responseId:callbackResponseId, responseData:responseData }); }; } var handler = messageHandlers[message.handlerName]; - try { - handler(message.data, responseCallback); - } catch(exception) { - console.log("WebViewJavascriptBridge: WARNING: javascript handler threw.", message, exception); - } if (!handler) { console.log("WebViewJavascriptBridge: WARNING: no handler for message from ObjC:", message); + } else { + handler(message.data, responseCallback); } } - }); + } } function _handleMessageFromObjC(messageJSON) { @@ -107,6 +121,8 @@ function _handleMessageFromObjC(messageJSON) { messagingIframe.src = CUSTOM_PROTOCOL_SCHEME + '://' + QUEUE_HAS_MESSAGE; document.documentElement.appendChild(messagingIframe); + registerHandler("_disableJavascriptAlertBoxSafetyTimeout", disableJavscriptAlertBoxSafetyTimeout); + setTimeout(_callWVJBCallbacks, 0); function _callWVJBCallbacks() { var callbacks = window.WVJBCallbacks; @@ -120,4 +136,4 @@ function _callWVJBCallbacks() { #undef __wvjb_js_func__ return preprocessorJSCode; -}; \ No newline at end of file +}; diff --git a/AdjustTests/ADJActivityHandlerMock.m b/AdjustTests/ADJActivityHandlerMock.m index 9020bf376..62431442e 100644 --- a/AdjustTests/ADJActivityHandlerMock.m +++ b/AdjustTests/ADJActivityHandlerMock.m @@ -16,6 +16,8 @@ @interface ADJActivityHandlerMock() @property (nonatomic, strong) ADJLoggerMock *loggerMock; @property (nonatomic, retain) ADJResponseData * lastResponseData; +@property (nonatomic, strong) NSArray *sessionParametersActionsArray; +@property (nonatomic, copy) NSData * deviceToken; @end @@ -23,13 +25,17 @@ @implementation ADJActivityHandlerMock - (id)initWithConfig:(ADJConfig *)adjustConfig sessionParametersActionsArray:(NSArray*)sessionParametersActionsArray + deviceToken:(NSData*)deviceToken { self = [super init]; if (self == nil) return nil; self.loggerMock = (ADJLoggerMock *) [ADJAdjustFactory logger]; - [self.loggerMock test:[prefix stringByAppendingFormat:@"initWithConfig, %@", sessionParametersActionsArray]]; + self.sessionParametersActionsArray = sessionParametersActionsArray; + self.deviceToken = deviceToken; + + [self.loggerMock test:[prefix stringByAppendingFormat:@"initWithConfig"]]; return self; } @@ -61,6 +67,13 @@ - (void)launchSessionResponseTasks:(ADJSessionResponseData *)sessionResponseData self.lastResponseData = sessionResponseData; } +- (void)launchSdkClickResponseTasks:(ADJSdkClickResponseData *)sdkClickResponseData +{ + [self.loggerMock test:[prefix stringByAppendingFormat:@"launchSdkClickResponseTasks, %@", sdkClickResponseData]]; + self.lastResponseData = sdkClickResponseData; +} + + - (void)launchAttributionResponseTasks:(ADJAttributionResponseData *)attributionResponseData { [self.loggerMock test:[prefix stringByAppendingFormat:@"launchAttributionResponseTasks, %@", attributionResponseData]]; self.lastResponseData = attributionResponseData; @@ -106,10 +119,11 @@ - (void) setIadDate:(NSDate*)iAdImpressionDate withPurchaseDate:(NSDate*)appPurc [self.loggerMock test:[prefix stringByAppendingFormat:@"setIadDate, iAdImpressionDate %@ appPurchaseDate, %@", iAdImpressionDate, appPurchaseDate]]; } -- (void)setIadDetails:(NSDictionary *)attributionDetails - error:(NSError *)error - retriesLeft:(int)retriesLeft { - [self.loggerMock test:[prefix stringByAppendingFormat:@"setIadDetails, %@ error, %@", attributionDetails, error]]; +- (void)setAttributionDetails:(NSDictionary *)attributionDetails + error:(NSError *)error + retriesLeft:(int)retriesLeft +{ + [self.loggerMock test:[prefix stringByAppendingFormat:@"setAttributionDetails, %@ error, %@", attributionDetails, error]]; } - (void) setOfflineMode:(BOOL)enabled { @@ -150,6 +164,11 @@ - (void)resetSessionPartnerParameters { [self.loggerMock test:[prefix stringByAppendingFormat:@"resetSessionPartnerParameters"]]; } +- (NSString *)adid { + [self.loggerMock test:[prefix stringByAppendingFormat:@"adid"]]; + return nil; +} + - (void)teardown:(BOOL)deleteState { [self.loggerMock test:[prefix stringByAppendingFormat:@"teardown"]]; } diff --git a/AdjustTests/ADJActivityHandlerTests.m b/AdjustTests/ADJActivityHandlerTests.m index 9839ec667..56922aa6a 100644 --- a/AdjustTests/ADJActivityHandlerTests.m +++ b/AdjustTests/ADJActivityHandlerTests.m @@ -3066,7 +3066,7 @@ - (void)stopActivity:(id)activityHandler { ADJInternalState * internalState = [activityHandler internalState]; // goes to the background - aTrue([internalState isBackground]); + aTrue([internalState isInBackground]); } - (id)getFirstActivityHandler:(ADJConfig *)config @@ -3090,8 +3090,8 @@ - (void)stopActivity:(id)activityHandler { // test default values aiEquals(cState.startEnabled, [internalState isEnabled]); aTrue([internalState isOnline]); - aTrue([internalState isBackground]); - aTrue([internalState isToStartNow]); + aTrue([internalState isInBackground]); + aTrue([internalState isNotInDelayedStart]); aiEquals(cState.isToUpdatePackages, [internalState isToUpdatePackages]); } @@ -3178,7 +3178,7 @@ - (void)checkStartInternal:(ADJSessionState *)sessionState { { // test the subsession message NSString * startedSubsessionLog = [NSString stringWithFormat:@"Started subsession %ld of session %ld", - sessionState.subsessionCount, sessionState.sessionCount]; + (long)sessionState.subsessionCount, sessionState.sessionCount]; aVerbose(startedSubsessionLog); break; } @@ -3198,7 +3198,7 @@ - (void)checkStartInternal:(ADJSessionState *)sessionState { // after processing the session, writes the activity state if (sessionState.sessionType != ADJSessionTypeNonSession) { NSString * wroteActivityLog = [NSString stringWithFormat:@"Wrote Activity state: ec:%ld sc:%ld ssc:%ld", - sessionState.eventCount, sessionState.sessionCount, sessionState.subsessionCount]; + (long)sessionState.eventCount, sessionState.sessionCount, sessionState.subsessionCount]; aDebug(wroteActivityLog); } // check Attribution State @@ -3332,13 +3332,6 @@ - (void)checkFinishTasks:(NSObject *)delegateTest // create activity package test ADJPackageFields * firstSessionPackageFields = [ADJPackageFields fields]; - firstSessionPackageFields.hasResponseDelegate = - attributionDelegatePresent || - eventFailureDelegatePresent || - eventSuccessDelegatePresent || - sessionFailureDelegatePresent || - sessionSuccessDelegatePresent; - // test first session [self testPackageSession:firstSessionPackage fields:firstSessionPackageFields sessionCount:@"1"]; diff --git a/AdjustTests/ADJPackageFields.m b/AdjustTests/ADJPackageFields.m index 848a93b7e..3e6fd6cd7 100644 --- a/AdjustTests/ADJPackageFields.m +++ b/AdjustTests/ADJPackageFields.m @@ -16,7 +16,7 @@ - (id) init { // default values self.appToken = @"qwerty123456"; - self.clientSdk = @"ios4.11.5"; + self.clientSdk = @"ios4.12.0"; self.suffix = @""; self.environment = @"sandbox"; diff --git a/AdjustTests/ADJPackageHandlerTests.m b/AdjustTests/ADJPackageHandlerTests.m index f6d41bcaa..e0a9e614a 100644 --- a/AdjustTests/ADJPackageHandlerTests.m +++ b/AdjustTests/ADJPackageHandlerTests.m @@ -648,7 +648,7 @@ - (void)checkSendFirst:(ADJSendFirst)sendFirstState if (sendFirstState == ADJSendFirstSend) { NSString * aActivitySend = [NSString stringWithFormat:@"RequestHandler sendPackage, activityPackage %@", packageString]; aTest(aActivitySend); - NSString * aQueueSizeSend = [NSString stringWithFormat:@"RequestHandler sendPackage, queueSize %lu", queueSize]; + NSString * aQueueSizeSend = [NSString stringWithFormat:@"RequestHandler sendPackage, queueSize %lu", (unsigned long)queueSize]; aTest(aQueueSizeSend); } else { anTest(@"RequestHandler sendPackage"); diff --git a/AdjustTests/ADJRequestHandlerMock.m b/AdjustTests/ADJRequestHandlerMock.m index e5a9c4e8e..b7d2e67e5 100644 --- a/AdjustTests/ADJRequestHandlerMock.m +++ b/AdjustTests/ADJRequestHandlerMock.m @@ -39,7 +39,7 @@ - (void)sendPackage:(ADJActivityPackage *)activityPackage queueSize:(NSUInteger)queueSize { [self.loggerMock test:[prefix stringByAppendingFormat:@"sendPackage, activityPackage %@", activityPackage]]; - [self.loggerMock test:[prefix stringByAppendingFormat:@"sendPackage, queueSize %lu", queueSize]]; + [self.loggerMock test:[prefix stringByAppendingFormat:@"sendPackage, queueSize %lu", (unsigned long)queueSize]]; /* NSDictionary *jsonDict; diff --git a/AdjustTests/ADJTest.h b/AdjustTests/ADJTest.h index 17de36030..3cb38fffa 100644 --- a/AdjustTests/ADJTest.h +++ b/AdjustTests/ADJTest.h @@ -112,7 +112,7 @@ // assert equals long integer #define aliEquals(field, value) \ - alilEquals(field, value, self.loggerMock) + alilEquals((long)field, (long)value, self.loggerMock) // assert equals #define aEquals(field, value) \ diff --git a/AdjustTests/ADJTestActivityPackage.m b/AdjustTests/ADJTestActivityPackage.m index ea3f174dd..cbb60205c 100644 --- a/AdjustTests/ADJTestActivityPackage.m +++ b/AdjustTests/ADJTestActivityPackage.m @@ -307,8 +307,7 @@ - (void)testConfig:(ADJActivityPackage *)package // environment apspEquals(@"environment", fields.environment); // needs_attribution_data - NSString * hasDelegateString = [NSString stringWithFormat:@"%d",fields.hasResponseDelegate]; - apspEquals(@"needs_response_details", hasDelegateString); + apspEquals(@"needs_response_details", @"1"); // event_buffering_enabled NSString * eventBufferingEnabledString = [NSString stringWithFormat:@"%d",fields.eventBufferingEnabled]; apspEquals(@"event_buffering_enabled", eventBufferingEnabledString); diff --git a/CHANGELOG.md b/CHANGELOG.md index 251eeec34..dddca05b4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,24 @@ +### Version 4.12.0 (13th December 2017) +#### Added +- Added reading of MCC. +- Added reading of MNC. +- Added reading of network type. +- Added reading of connectivity type. +- Added usage of app secret in authorization header. + +#### Changed +- Improved push token handling. +- Migrated Adjust internal files from `Documents` to `Application Support` directory. +- Deprecated `iAd v2` handling. +- Updated `WebViewJavascriptBridge` to `6.0.2`. +- Updated instructions for iOS SDK web bridge integration. + +#### Fixed +- Fixed data race in `ADJAttributionHandler` (https://github.com/adjust/ios_sdk/issues/303) (thanks to @mindbrix). +- Fixed potential deadlock in shared access to `UIPasteboard` with Facebook SDK (https://github.com/adjust/ios_sdk/pull/310) (thanks to @sanekgusev). + +--- + ### Version 4.11.5 (21st September 2017) #### Fixed - Fixed `WKWebViewJavascriptBridge` bug (https://github.com/marcuswestin/WebViewJavascriptBridge/issues/267). diff --git a/README.md b/README.md index 8955fe187..5dd9f2d9a 100644 --- a/README.md +++ b/README.md @@ -8,9 +8,8 @@ If your app is an app which uses web views you would like to use adjust tracking * [Example apps](#example-apps) * [Basic integration](#basic-integration) - * [Get the SDK](#sdk-get) * [Add the SDK to your project](#sdk-add) - * [Add the AdSupport and iAd framework](#sdk-frameworks) + * [Add iOS frameworks](#sdk-frameworks) * [Integrate the SDK into your app](#sdk-integrate) * [Basic setup](#basic-setup) * [Adjust logging](#adjust-logging) @@ -62,35 +61,21 @@ There are example apps inside the [`examples` directory][examples] for [`iOS (Ob We will describe the steps to integrate the adjust SDK into your iOS project. We are going to assume that you are using Xcode for your iOS development. -### Get the SDK - -Download the latest adjust SDK version from our [releases page][releases]. Extract the archive into a directory of your choice. - -### Add the SDK to your project - -You can add the adjust SDK by adding all of it's source files direcly into your app. In Xcode's Project Navigator locate the `Supporting Files` group (or any other group of your choice). From Finder, drag the `Adjust` subdirectory into Xcode's `Supporting Files` group. - -![][drag] - -In the dialog `Choose options for adding these files` make sure to check the checkbox for `Copy items if needed` and select the radio button to `Create groups`. - -![][add] - --- +### Add the SDK to your project 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.11.5' +pod 'Adjust', '~> 4.12.0' ``` or: ```ruby -pod 'Adjust', :git => 'https://github.com/adjust/ios_sdk.git', :tag => 'v4.11.5' +pod 'Adjust', :git => 'https://github.com/adjust/ios_sdk.git', :tag => 'v4.12.0' ``` --- +--- If you're using [Carthage][carthage], you can add following line to your `Cartfile` and continue from [this step](#sdk-frameworks): @@ -99,39 +84,30 @@ If you're using [Carthage][carthage], you can add following line to your `Cartfi github "adjust/ios_sdk" ``` --- +--- You can also choose to integrate the adjust SDK by adding it to your project as a framework. On the [releases page][releases] you can find the following archives: * `AdjustSdkStatic.framework.zip` * `AdjustSdkDynamic.framework.zip` -* `AdjustSdkDynamicWithoutSimulator.framework.zip` * `AdjustSdkTv.framework.zip` Since the release of iOS 8, Apple has introduced dynamic frameworks (also known as embedded frameworks). If your app is targeting iOS 8 or higher, you can use the adjust SDK dynamic framework. Choose which framework you want to use – static or dynamic – and add it to your project. -If you want to use dynamic framework without architectures used for simulator (`x86_64` and `i386`), you can use SDK inside `AdjustSdkDynamicWithoutSimulator.framework.zip` archive. - If you are having `tvOS` app, you can use the adjust SDK with it as well with usage of our tvOS framework which you can extract from `AdjustSdkTv.framework.zip` archive. -If you have chosen one of these ways to integrate the adjust SDK, you may continue from [this step](#sdk-frameworks). If you want to add the adjust SDK by adding its source files to your project, you can continue from [this step](#sdk-get). - -### Add the AdSupport and iAd framework +### Add iOS frameworks -Select your project in the Project Navigator. In the left hand side of the main view, select your target. In the tab `Build Phases`, expand the group `Link Binary with Libraries`. On the bottom of that section click on the `+` button. Select the `AdSupport.framework` and click the `Add` button. Unless you are using tvOS, repeat the same steps to add the `iAd.framework`. Change the `Status` of both frameworks to `Optional`. - -![][framework] +1. Select your project in the Project Navigator +2. In the left-hand side of the main view, select your target +3. In the `Build Phases` tab, expand the `Link Binary with Libraries` group +4. At the bottom of that section, select the `+` button +5. Select the `AdSupport.framework`, then the `Add` button +6. Unless you are using tvOS, repeat the same steps to add the `iAd.framework` and `CoreTelephony.framework` +7. Change the `Status` of the frameworks to `Optional`. ### Integrate the SDK into your app -If you added the adjust SDK from the source, you should use the following import statement: - -```objc -#import "Adjust.h" -``` - --- - If you added the adjust SDK via a Pod repository, you should use one of the following import statements: ```objc @@ -144,7 +120,7 @@ or #import ``` --- +--- If you added the adjust SDK as a static/dynamic framework or via Carthage, you should use the following import statement: @@ -152,7 +128,7 @@ If you added the adjust SDK as a static/dynamic framework or via Carthage, you s #import ``` --- +--- If you are are using the adjust SDK with your tvOS app, you should use the following import statement: @@ -162,7 +138,7 @@ If you are are using the adjust SDK with your tvOS app, you should use the follo Next, we'll set up basic session tracking. -### Basic setup +### Basic setup In the Project Navigator, open the source file of your application delegate. Add the `import` statement at the top of the file, then add the following call to `Adjust` in the `didFinishLaunching` or `didFinishLaunchingWithOptions` method of your app delegate: @@ -199,7 +175,7 @@ NSString *environment = ADJEnvironmentProduction; We use this environment to distinguish between real traffic and test traffic from test devices. It is very important that you keep this value meaningful at all times! This is especially important if you are tracking revenue. -### Adjust logging +### Adjust logging You can increase or decrease the amount of logs that you see during testing by calling `setLogLevel:` on your `ADJConfig` instance with one of the following parameters: @@ -232,7 +208,7 @@ ADJConfig *adjustConfig = [ADJConfig configWithAppToken:yourAppToken [Adjust appDidLaunch:adjustConfig]; ``` -### Build your app +### Build your app Build and run your app. If the build succeeds, you should carefully read the SDK logs in the console. After the app launches for the first time, you should see the info log `Install tracked`. @@ -242,7 +218,7 @@ Build and run your app. If the build succeeds, you should carefully read the SDK Once you integrate the adjust SDK into your project, you can take advantage of the following features. -### Event tracking +### Event tracking You can use adjust to track events. Lets say you want to track every tap on a particular button. You would create a new event token in your [dashboard], which has an associated event token - looking something like `abc123`. In your button's `buttonDown` method you would then add the following lines to track the tap: @@ -255,7 +231,7 @@ When tapping the button you should now see `Event tracked` in the logs. The event instance can be used to configure the event further before tracking it: -### Revenue tracking +### Revenue tracking If your users can generate revenue by tapping on advertisements or making in-app purchases you can track those revenues with events. Lets say a tap is worth one Euro cent. You could then track the revenue event like this: @@ -298,11 +274,11 @@ If you want to track in-app purchases, please make sure to call `trackEvent` aft } ``` -### In-App Purchase verification +### In-App Purchase verification If you want to check the validity of In-App Purchases made in your app using Purchase Verification, adjust's server side receipt verification tool, then check out our iOS purchase SDK and read more about it [here][ios-purchase-verification]. -### Callback parameters +### Callback parameters You can register a callback URL for your events in your [dashboard]. We will send a GET request to that URL whenever the event is tracked. You can add callback parameters to that event by calling `addCallbackParameter` to the event before tracking it. We will then append these parameters to your callback URL. @@ -325,7 +301,7 @@ It should be mentioned that we support a variety of placeholders like `{idfa}` t You can read more about using URL callbacks, including a full list of available values, in our [callbacks guide][callbacks-guide]. -### Partner parameters +### Partner parameters You can also add parameters to be transmitted to network partners, which have been activated in youradjust dashboard. @@ -342,13 +318,13 @@ ADJEvent *event = [ADJEvent eventWithEventToken:@"abc123"]; You can read more about special partners and these integrations in our [guide to special partners][special-partners]. -### Session parameters +### 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. If you want to send session parameters with the initial install event, they must be called before the Adjust SDK launches via `[Adjust appDidLaunch:]`. If you need to send them with an install, but can only obtain the needed values after launch, it's possible to [delay](#delay-start) the first launch of the adjust SDK to allow this behavior. -### Session callback parameters +### Session callback parameters The same callback parameters that are registered for [events](#callback-parameters) can be also saved to be sent in every event or session of the adjust SDK. @@ -372,7 +348,7 @@ If you wish to remove all key and values from the session callback parameters, y [Adjust resetSessionCallbackParameters]; ``` -### Session partner parameters +### Session partner parameters In the same way that there is [session callback parameters](#session-callback-parameters) that are sent every in event or session of the adjust SDK, there is also session partner parameters. @@ -398,7 +374,7 @@ If you wish to remove all key and values from the session partner parameters, yo [Adjust resetSessionPartnerParameters]; ``` -### Delay start +### Delay start Delaying the start of the adjust SDK allows your app some time to obtain session parameters, such as unique identifiers, to be send on install. @@ -412,7 +388,7 @@ In this case this will make the adjust SDK not send the initial install session **The maximum delay start time of the adjust SDK is 10 seconds**. -### Attribution callback +### Attribution callback You can register a delegate callback to be notified of tracker attribution changes. Due to the different sources considered for attribution, this information can not be provided synchronously. Follow these steps to implement the optional delegate protocol in your app delegate: @@ -441,18 +417,18 @@ As the delegate callback is configured using the `ADJConfig` instance, you shoul The delegate function will be called after the SDK receives the final attribution data. Within the delegate function you have access to the `attribution` parameter. Here is a quick summary of its properties: -- `NSString trackerToken` the tracker token of the current install. -- `NSString trackerName` the tracker name of the current install. -- `NSString network` the network grouping level of the current install. -- `NSString campaign` the campaign grouping level of the current install. -- `NSString adgroup` the ad group grouping level of the current install. -- `NSString creative` the creative grouping level of the current install. -- `NSString clickLabel` the click label of the current install. -- `NSString adid` the unique device identifier provided by adjust. +- `NSString trackerToken` the tracker token of the current attribution. +- `NSString trackerName` the tracker name of the current attribution. +- `NSString network` the network grouping level of the current attribution. +- `NSString campaign` the campaign grouping level of the current attribution. +- `NSString adgroup` the ad group grouping level of the current attribution. +- `NSString creative` the creative grouping level of the current attribution. +- `NSString clickLabel` the click label of the current attribution. +- `NSString adid` the unique device identifier provided by attribution. If any value is unavailable, it will default to `nil`. -### Event and session callbacks +### Event and session callbacks You can register a delegate callback to be notified of successful and failed tracked events and/or sessions. The same optional protocol `AdjustDelegate` used for the [attribution callback](#attribution-callback) is used. @@ -501,7 +477,7 @@ And both event and session failed objects also contain: - `BOOL willRetry` indicates that there will be an attempt to resend the package at a later time. -### Disable tracking +### Disable tracking You can disable the adjust SDK from tracking any activities of the current device by calling `setEnabled` with parameter `NO`. **This setting is remembered between sessions**, but it can only be activated after the first session. @@ -511,7 +487,7 @@ You can disable the adjust SDK from tracking any activities of the current devic You can check if the adjust SDK is currently enabled by calling the function `isEnabled`. It is always possible to activate the adjust SDK by invoking `setEnabled` with the enabled parameter as `YES`. -### Offline mode +### Offline mode You can put the adjust SDK in offline mode to suspend transmission to our servers while retaining tracked data to be sent later. While in offline mode, all information is saved in a file, so be careful not to trigger too many events while in offline mode. @@ -525,7 +501,7 @@ Conversely, you can deactivate offline mode by calling `setOfflineMode` with `NO Unlike disabling tracking, this setting is **not remembered** bettween sessions. This means that the SDK is in online mode whenever it is started, even if the app was terminated in offline mode. -### Event buffering +### Event buffering If your app makes heavy use of event tracking, you might want to delay some HTTP requests in order to send them in one batch every minute. You can enable event buffering with your `ADJConfig` instance: @@ -535,7 +511,7 @@ If your app makes heavy use of event tracking, you might want to delay some HTTP If nothing is set, event buffering is **disabled by default**. -### Background tracking +### Background tracking The default behaviour of the adjust SDK is to pause sending HTTP requests while the app is in the background. You can change this in your `AdjustConfig` instance: @@ -545,11 +521,11 @@ The default behaviour of the adjust SDK is to pause sending HTTP requests while If nothing is set, sending in background is **disabled by default**. -### Device IDs +### Device IDs The adjust SDK offers you possibility to obtain some of the device identifiers. -### iOS Advertising Identifier +### iOS Advertising Identifier Certain services (such as Google Analytics) require you to coordinate device and client IDs in order to prevent duplicate reporting. @@ -579,7 +555,7 @@ ADJAttribution *attribution = [Adjust attribution]; **Note**: Information about current attribution is available after app installation has been tracked by the adjust backend and attribution callback has been initially triggered. From that moment on, adjust SDK has information about your user's attribution and you can access it with this method. So, **it is not possible** to access user's attribution value before the SDK has been initialised and attribution callback has been initially triggered. -### Push token +### Push token To send us the push notification token, add the following call to `Adjust` in the `didRegisterForRemoteNotificationsWithDeviceToken` of your app delegate: @@ -589,7 +565,9 @@ To send us the push notification token, add the following call to `Adjust` in th } ``` -### Pre-installed trackers +Push tokens are used for the Adjust Audience Builder and client callbacks, and are required for the upcoming uninstall tracking feature. + +### Pre-installed trackers If you want to use the Adjust SDK to recognize users that found your app pre-installed on their device, follow these steps. @@ -612,15 +590,15 @@ If you want to use the Adjust SDK to recognize users that found your app pre-ins Default tracker: 'abc123' ``` -### Deep linking +### Deep linking If you are using the adjust tracker URL with an option to deep link into your app from the URL, there is the possibility to get info about the deep link URL and its content. Hitting the URL can happen when the user has your app already installed (standard deep linking scenario) or if they don't have the app on their device (deferred deep linking scenario). Both of these scenarios are supported by the adjust SDK and in both cases the deep link URL will be provided to you after you app has been started after hitting the tracker URL. In order to use this feature in your app, you need to set it up properly. -### Standard deep linking scenario +### Standard deep linking scenario If your user already has the app installed and hits the tracker URL with deep link information in it, your application will be opened and the content of the deep link will be sent to your app so that you can parse it and decide what to do next. With introduction of iOS 9, Apple has changed the way how deep linking should be handled in the app. Depending on which scenario you want to use for your app (or if you want to use them both to support wide range of devices), you need to set up your app to handle one or both of the following scenarios. -### Deep linking on iOS 8 and earlier +### Deep linking on iOS 8 and earlier Deep linking on iOS 8 and earlier devices is being done with usage of a custom URL scheme setting. You need to pick a custom URL scheme name which your app will be in charge for opening. This scheme name will also be used in the adjust tracker URL as part of the `deep_link` parameter. In order to set this in your app, open your `Info.plist` file and add new `URL types` row to it. In there, as `URL identifier` write you app's bundle ID and under `URL schemes` add scheme name(s) which you want your app to handle. In the example below, we have chosen that our app should handle the `adjustExample` scheme name. @@ -642,7 +620,7 @@ After this has been set up, your app will be opened after you click the adjust t With this setup, you have successfully set up deep linking handling for iOS devices with iOS 8 and earlier versions. -### Deep linking on iOS 9 and later +### Deep linking on iOS 9 and later In order to set deep linking support for iOS 9 and later devices, you need to enable your app to handle Apple universal links. To find out more about universal links and how their setup looks like, you can check [here][universal-links]. @@ -692,7 +670,7 @@ We provide a helper function that allows you to convert a universal link to an o } ``` -### Deferred deep linking scenario +### Deferred deep linking scenario You can register a delegate callback to be notified before a deferred deep link is opened and decide if the adjust SDK will try to open it. The same optional protocol `AdjustDelegate` used for the [attribution callback](#attribution-callback) and for [event and session callbacks](#event-session-callbacks) is used. @@ -713,7 +691,7 @@ The callback function will be called after the SDK receives a deffered deep link If this callback is not implemented, **the adjust SDK will always try to open the deep link by default**. -### Reattribution via deep links +### Reattribution via deep links Adjust enables you to run re-engagement campaigns with usage of deep links. For more information on how to do that, please check our [official docs][reattribution-with-deeplinks]. @@ -753,9 +731,9 @@ The call to `appWillOpenUrl` should be done like this to support deep linking re } ``` -## Troubleshooting +## Troubleshooting -### Issues with delayed SDK initialisation +### Issues with delayed SDK initialisation As described in the [basic setup step](#basic-setup), we strongly advise you to initialise the adjust SDK in the `didFinishLaunching` or `didFinishLaunchingWithOptions` method of your app delegate. It is imperative to initialise the adjust SDK in as soon as possible so that you can use all the features of the SDK. @@ -809,17 +787,17 @@ For example: For all these reasons, please follow the instructions in this document and initialise the adjust SDK in the `didFinishLaunching` or `didFinishLaunchingWithOptions` method of your app delegate. -### I'm seeing "Adjust requires ARC" error +### I'm seeing "Adjust requires ARC" error If your build failed with the error `Adjust requires ARC`, it looks like your project is not using [ARC][arc]. In that case we recommend [transitioning your project][transition] so that it does use ARC. If you don't want to use ARC, you have to enable ARC for all source files of adjust in the target's Build Phases: Expand the `Compile Sources` group, select all adjust files and change the `Compiler Flags` to `-fobjc-arc` (Select all and press the `Return` key to change all at once). -### I'm seeing "[UIDevice adjTrackingEnabled]: unrecognized selector sent to instance" error +### I'm seeing "[UIDevice adjTrackingEnabled]: unrecognized selector sent to instance" error This error can occur when you are adding the adjust SDK framework to your app. The adjust SDK contains `categories` among it's source files and for this reason, if you have chosen this SDK integration approach, you need to add `-ObjC` flags to `Other Linker Flags` in your Xcode project settings. Adding this flag will fix this error. -### I'm seeing the "Session failed (Ignoring too frequent session.)" error +### I'm seeing the "Session failed (Ignoring too frequent session.)" error This error typically occurs when testing installs. Uninstalling and reinstalling the app is not enough to trigger a new install. The servers will determine that the SDK has lost its locally aggregated session data and ignore the erroneous message, given the information available on the servers about the device. @@ -843,7 +821,7 @@ http://app.adjust.com/forget_device?app_token={yourAppToken}&idfa={idfaValue} When the device is forgotten, the link just returns `Forgot device`. If the device was already forgotten or the values were incorrect, the link returns `Device not found`. -### I'm not seeing "Install tracked" in the logs +### I'm not seeing "Install tracked" in the logs If you want to simulate the installation scenario of your app on your test device, it is not enough if you just re-run the app from the Xcode on your test device. Re-running the app from the Xcode doesn't cause app data to be wiped out and all internal files that our SDK is keeping inside your app will still be there, so upon re-run, our SDK will see those files and think of your app was already installed (and that SDK was already launched in it) but just opened for another time rather than being opened for the first time. @@ -853,7 +831,7 @@ In order to run the app installation scenario, you need to do following: * Forget your test device from the adjust backend like explained in the issue [above](#forget-device) * Run your app from the Xcode on the test device and you will see log message "Install tracked" -### I'm seeing the "Unattributable SDK click ignored" message +### I'm seeing the "Unattributable SDK click ignored" message You may notice this message while testing your app in `sandbox` envoronment. It is related to some changes Apple introduced in `iAd.framework` version 3. With this, a user can be directed to your app from a click on iAd banner and this will cause our SDK to send an `sdk_click` package to the adjust backend informing it about the content of the clicked URL. For some reason, Apple decided that if the app was opened without clicking on iAd banner, they will artificially generate an iAd banner URL click with some random values. Our SDK won't be able to distinguish if the iAd banner click was genuine or artificially generated and will send an `sdk_click` package regardless to the adjust backend. If you have your log level set to `verbose` level, you will see this `sdk_click` package looking something like this: @@ -881,7 +859,7 @@ If for some reason this `sdk_click` would be accepted, it would mean that a user So, this message doesn't indicate any issue with your SDK integration but it's simply informing you that our backend has ignored this artificially created `sdk_click` which could have lead to your user being wrongly attributed/reattributed. -### I'm seeing incorrect revenue data in the adjust dashboard +### I'm seeing incorrect revenue data in the adjust dashboard The adjust SDK tracks what you tell it to track. If you are attaching revenue to your event, the number you write as an amount is the only amount which will reach the adjust backend and be displayed in the dashboard. Our SDK does not manipulate your amount value, nor does our backend. So, if you see wrong amount being tracked, it's because our SDK was told to track that amount. @@ -942,7 +920,7 @@ If you are seing any value in the dashboard other than what you expected to be t [attribution-data]: https://github.com/adjust/sdks/blob/master/doc/attribution-data.md [example-ios-objc]: http://github.com/adjust/ios_sdk/tree/master/examples/AdjustExample-iOS [example-ios-swift]: http://github.com/adjust/ios_sdk/tree/master/examples/AdjustExample-Swift -[ios-web-views-guide]: https://github.com/adjust/ios_sdk/tree/master/doc/web_views.md +[ios-web-views-guide]: doc/english/web_views.md [currency-conversion]: https://docs.adjust.com/en/event-tracking/#tracking-purchases-in-different-currencies [universal-links-guide]: https://docs.adjust.com/en/universal-links/ @@ -968,7 +946,7 @@ If you are seing any value in the dashboard other than what you expected to be t [associated-domains-applinks]: https://raw.github.com/adjust/sdks/master/Resources/ios/associated-domains-applinks.png [universal-links-dashboard-values]: https://raw.github.com/adjust/sdks/master/Resources/ios/universal-links-dashboard-values5.png -## License +## License The adjust SDK is licensed under the MIT License. diff --git a/VERSION b/VERSION index ad2c17edd..815588ef1 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -4.11.5 +4.12.0 diff --git a/doc/english/migrate.md b/doc/english/migrate.md index 69fe15654..589a8b7c4 100644 --- a/doc/english/migrate.md +++ b/doc/english/migrate.md @@ -1,4 +1,4 @@ -## Migrate your adjust SDK for iOS to v4.11.5 from v3.4.0 +## Migrate your adjust SDK for iOS to v4.12.0 from v3.4.0 ### Initial setup diff --git a/doc/english/web_views.md b/doc/english/web_views.md index 41021c027..4be2be619 100644 --- a/doc/english/web_views.md +++ b/doc/english/web_views.md @@ -102,7 +102,7 @@ function setupWebViewJavascriptBridge(callback) { var WVJBIframe = document.createElement('iframe'); WVJBIframe.style.display = 'none'; - WVJBIframe.src = 'wvjbscheme://__BRIDGE_LOADED__'; + WVJBIframe.src = 'https://__bridge_loaded__'; document.documentElement.appendChild(WVJBIframe); setTimeout(function() { document.documentElement.removeChild(WVJBIframe) }, 0) @@ -113,6 +113,8 @@ setupWebViewJavascriptBridge(function(bridge) { }) ``` +Take notice that the line `WVJBIframe.src = 'https://__bridge_loaded__';` was changed in version 4.11.6 from `WVJBIframe.src = 'wvjbscheme://__BRIDGE_LOADED__';` due to a change in the `WebViewJavascriptBridge` plugin. + ![][bridge_init_js] ### Basic setup diff --git a/doc/japanese/migrate_ja.md b/doc/japanese/migrate_ja.md index e6e020a8a..d54dfa8eb 100644 --- a/doc/japanese/migrate_ja.md +++ b/doc/japanese/migrate_ja.md @@ -1,4 +1,4 @@ -## iOS用adjust SDKのv3.4.0からv.4.11.5への移行 +## iOS用adjust SDKのv3.4.0からv.4.12.0への移行 ### 初期設定 diff --git a/doc/migrate.md b/doc/migrate.md index 69fe15654..589a8b7c4 100644 --- a/doc/migrate.md +++ b/doc/migrate.md @@ -1,4 +1,4 @@ -## Migrate your adjust SDK for iOS to v4.11.5 from v3.4.0 +## Migrate your adjust SDK for iOS to v4.12.0 from v3.4.0 ### Initial setup diff --git a/examples/AdjustExample-Swift/AdjustExample-Swift.xcodeproj/project.pbxproj b/examples/AdjustExample-Swift/AdjustExample-Swift.xcodeproj/project.pbxproj index 6bc8d4836..dd3b170be 100644 --- a/examples/AdjustExample-Swift/AdjustExample-Swift.xcodeproj/project.pbxproj +++ b/examples/AdjustExample-Swift/AdjustExample-Swift.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 6FCC850F1F2794C600D6A0ED /* ADJReachability.m in Sources */ = {isa = PBXBuildFile; fileRef = 6FCC850E1F2794BE00D6A0ED /* ADJReachability.m */; }; 9D449E761E6EDC3D00E7E80B /* ADJActivityHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D449E351E6EDC3D00E7E80B /* ADJActivityHandler.m */; }; 9D449E771E6EDC3D00E7E80B /* ADJActivityKind.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D449E371E6EDC3D00E7E80B /* ADJActivityKind.m */; }; 9D449E781E6EDC3D00E7E80B /* ADJActivityPackage.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D449E391E6EDC3D00E7E80B /* ADJActivityPackage.m */; }; @@ -39,6 +40,7 @@ 9D449E941E6EDC3D00E7E80B /* Adjust.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D449E721E6EDC3D00E7E80B /* Adjust.m */; }; 9D449E951E6EDC3D00E7E80B /* ADJUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D449E741E6EDC3D00E7E80B /* ADJUtil.m */; }; 9D449E961E6EDC3D00E7E80B /* Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 9D449E751E6EDC3D00E7E80B /* Info.plist */; }; + 9DD0E9C11F45879A00B2A759 /* ADJUserDefaults.m in Sources */ = {isa = PBXBuildFile; fileRef = 9DD0E9C01F45879A00B2A759 /* ADJUserDefaults.m */; }; 9DF7A9C61CB4ECA600D3591F /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9DF7A9C51CB4ECA600D3591F /* AppDelegate.swift */; }; 9DF7A9C81CB4ECA600D3591F /* ViewControllerSwift.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9DF7A9C71CB4ECA600D3591F /* ViewControllerSwift.swift */; }; 9DF7A9CB1CB4ECA600D3591F /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 9DF7A9C91CB4ECA600D3591F /* Main.storyboard */; }; @@ -49,6 +51,8 @@ /* End PBXBuildFile section */ /* Begin PBXFileReference section */ + 6FCC850D1F2794BE00D6A0ED /* ADJReachability.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ADJReachability.h; sourceTree = ""; }; + 6FCC850E1F2794BE00D6A0ED /* ADJReachability.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ADJReachability.m; sourceTree = ""; }; 9D449E341E6EDC3D00E7E80B /* ADJActivityHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ADJActivityHandler.h; sourceTree = ""; }; 9D449E351E6EDC3D00E7E80B /* ADJActivityHandler.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ADJActivityHandler.m; sourceTree = ""; }; 9D449E361E6EDC3D00E7E80B /* ADJActivityKind.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ADJActivityKind.h; sourceTree = ""; }; @@ -112,6 +116,8 @@ 9D449E731E6EDC3D00E7E80B /* ADJUtil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ADJUtil.h; sourceTree = ""; }; 9D449E741E6EDC3D00E7E80B /* ADJUtil.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ADJUtil.m; sourceTree = ""; }; 9D449E751E6EDC3D00E7E80B /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 9DD0E9BF1F45879A00B2A759 /* ADJUserDefaults.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ADJUserDefaults.h; sourceTree = ""; }; + 9DD0E9C01F45879A00B2A759 /* ADJUserDefaults.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ADJUserDefaults.m; sourceTree = ""; }; 9DF7A9C21CB4ECA600D3591F /* AdjustExample-Swift.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "AdjustExample-Swift.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 9DF7A9C51CB4ECA600D3591F /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 9DF7A9C71CB4ECA600D3591F /* ViewControllerSwift.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewControllerSwift.swift; sourceTree = ""; }; @@ -140,6 +146,7 @@ 9D449E331E6EDC3D00E7E80B /* Adjust */ = { isa = PBXGroup; children = ( + 9D449E3C1E6EDC3D00E7E80B /* ADJAdditions */, 9D449E341E6EDC3D00E7E80B /* ADJActivityHandler.h */, 9D449E351E6EDC3D00E7E80B /* ADJActivityHandler.m */, 9D449E361E6EDC3D00E7E80B /* ADJActivityKind.h */, @@ -148,7 +155,6 @@ 9D449E391E6EDC3D00E7E80B /* ADJActivityPackage.m */, 9D449E3A1E6EDC3D00E7E80B /* ADJActivityState.h */, 9D449E3B1E6EDC3D00E7E80B /* ADJActivityState.m */, - 9D449E3C1E6EDC3D00E7E80B /* ADJAdditions */, 9D449E431E6EDC3D00E7E80B /* ADJAdjustFactory.h */, 9D449E441E6EDC3D00E7E80B /* ADJAdjustFactory.m */, 9D449E451E6EDC3D00E7E80B /* ADJAttribution.h */, @@ -197,6 +203,10 @@ 9D449E721E6EDC3D00E7E80B /* Adjust.m */, 9D449E731E6EDC3D00E7E80B /* ADJUtil.h */, 9D449E741E6EDC3D00E7E80B /* ADJUtil.m */, + 6FCC850D1F2794BE00D6A0ED /* ADJReachability.h */, + 6FCC850E1F2794BE00D6A0ED /* ADJReachability.m */, + 9DD0E9BF1F45879A00B2A759 /* ADJUserDefaults.h */, + 9DD0E9C01F45879A00B2A759 /* ADJUserDefaults.m */, 9D449E751E6EDC3D00E7E80B /* Info.plist */, ); name = Adjust; @@ -284,7 +294,7 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0730; - LastUpgradeCheck = 0810; + LastUpgradeCheck = 0900; ORGANIZATIONNAME = "adjust GmbH"; TargetAttributes = { 9DF7A9C11CB4ECA600D3591F = { @@ -338,6 +348,7 @@ 9D449E8F1E6EDC3D00E7E80B /* ADJSessionParameters.m in Sources */, 9D449E901E6EDC3D00E7E80B /* ADJSessionSuccess.m in Sources */, 9D449E861E6EDC3D00E7E80B /* ADJEventSuccess.m in Sources */, + 9DD0E9C11F45879A00B2A759 /* ADJUserDefaults.m in Sources */, 9D449E761E6EDC3D00E7E80B /* ADJActivityHandler.m in Sources */, 9D449E8B1E6EDC3D00E7E80B /* ADJRequestHandler.m in Sources */, 9D449E8A1E6EDC3D00E7E80B /* ADJPackageHandler.m in Sources */, @@ -345,6 +356,7 @@ 9D449E7E1E6EDC3D00E7E80B /* ADJAttribution.m in Sources */, 9D449E831E6EDC3D00E7E80B /* ADJDeviceInfo.m in Sources */, 9D449E7F1E6EDC3D00E7E80B /* ADJAttributionHandler.m in Sources */, + 6FCC850F1F2794C600D6A0ED /* ADJReachability.m in Sources */, 9D449E891E6EDC3D00E7E80B /* ADJPackageBuilder.m in Sources */, 9D449E841E6EDC3D00E7E80B /* ADJEvent.m in Sources */, 9D449E951E6EDC3D00E7E80B /* ADJUtil.m in Sources */, @@ -398,14 +410,20 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 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_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_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; @@ -445,14 +463,20 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 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_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_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; diff --git a/examples/AdjustExample-WebView/AdjustExample-WebView.xcodeproj/project.pbxproj b/examples/AdjustExample-WebView/AdjustExample-WebView.xcodeproj/project.pbxproj index 011b6a455..de9b48353 100644 --- a/examples/AdjustExample-WebView/AdjustExample-WebView.xcodeproj/project.pbxproj +++ b/examples/AdjustExample-WebView/AdjustExample-WebView.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 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 */; }; 9D1082AF1CFDAF8E0050568B /* UIWebViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D1082AE1CFDAF8E0050568B /* UIWebViewController.m */; }; @@ -61,9 +62,12 @@ 9D75F19C1D07463800E5D222 /* adjust_event.js in Resources */ = {isa = PBXBuildFile; fileRef = 9D75F1931D07463800E5D222 /* adjust_event.js */; }; 9D75F19D1D07463800E5D222 /* adjust_config.js in Resources */ = {isa = PBXBuildFile; fileRef = 9D75F1941D07463800E5D222 /* adjust_config.js */; }; 9D9A99DA1D0B699A0022FFCE /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D9A99D91D0B699A0022FFCE /* AppDelegate.m */; }; + 9DD0E9C41F4587C600B2A759 /* ADJUserDefaults.m in Sources */ = {isa = PBXBuildFile; fileRef = 9DD0E9C31F4587C600B2A759 /* ADJUserDefaults.m */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ + 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 = ""; }; 968595F01D0B2E630011CA2B /* AdjustBridgeRegister.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AdjustBridgeRegister.m; sourceTree = ""; }; 9D1082A41CFDAF8E0050568B /* AdjustExample-WebView.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "AdjustExample-WebView.app"; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -160,6 +164,8 @@ 9D75F1941D07463800E5D222 /* adjust_config.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = adjust_config.js; sourceTree = ""; }; 9D9A99D81D0B699A0022FFCE /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 9D9A99D91D0B699A0022FFCE /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; + 9DD0E9C21F4587C600B2A759 /* ADJUserDefaults.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ADJUserDefaults.h; sourceTree = ""; }; + 9DD0E9C31F4587C600B2A759 /* ADJUserDefaults.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ADJUserDefaults.m; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -240,6 +246,7 @@ 9D449E971E6EDD4100E7E80B /* Adjust */ = { isa = PBXGroup; children = ( + 9D449EA01E6EDD4100E7E80B /* ADJAdditions */, 9D449E981E6EDD4100E7E80B /* ADJActivityHandler.h */, 9D449E991E6EDD4100E7E80B /* ADJActivityHandler.m */, 9D449E9A1E6EDD4100E7E80B /* ADJActivityKind.h */, @@ -248,7 +255,6 @@ 9D449E9D1E6EDD4100E7E80B /* ADJActivityPackage.m */, 9D449E9E1E6EDD4100E7E80B /* ADJActivityState.h */, 9D449E9F1E6EDD4100E7E80B /* ADJActivityState.m */, - 9D449EA01E6EDD4100E7E80B /* ADJAdditions */, 9D449EA71E6EDD4100E7E80B /* ADJAdjustFactory.h */, 9D449EA81E6EDD4100E7E80B /* ADJAdjustFactory.m */, 9D449EA91E6EDD4100E7E80B /* ADJAttribution.h */, @@ -297,6 +303,10 @@ 9D449ED61E6EDD4100E7E80B /* Adjust.m */, 9D449ED71E6EDD4100E7E80B /* ADJUtil.h */, 9D449ED81E6EDD4100E7E80B /* ADJUtil.m */, + 6FCC85101F2794D600D6A0ED /* ADJReachability.h */, + 6FCC85111F2794D600D6A0ED /* ADJReachability.m */, + 9DD0E9C21F4587C600B2A759 /* ADJUserDefaults.h */, + 9DD0E9C31F4587C600B2A759 /* ADJUserDefaults.m */, 9D449ED91E6EDD4100E7E80B /* Info.plist */, ); name = Adjust; @@ -373,7 +383,7 @@ 9D10829C1CFDAF8E0050568B /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 0820; + LastUpgradeCheck = 0900; ORGANIZATIONNAME = "adjust GmbH"; TargetAttributes = { 9D1082A31CFDAF8E0050568B = { @@ -438,6 +448,8 @@ 9D449EE01E6EDD4100E7E80B /* UIDevice+ADJAdditions.m in Sources */, 9D449EEA1E6EDD4100E7E80B /* ADJEventSuccess.m in Sources */, 9D75F1961D07463800E5D222 /* WebViewJavascriptBridge.m in Sources */, + 9DD0E9C41F4587C600B2A759 /* ADJUserDefaults.m in Sources */, + 6FCC85121F2794D900D6A0ED /* ADJReachability.m in Sources */, 9D75F1991D07463800E5D222 /* WKWebViewJavascriptBridge.m in Sources */, 9D10833D1CFDD8F00050568B /* WKWebViewController.m in Sources */, 9D449EE51E6EDD4100E7E80B /* ADJConfig.m in Sources */, @@ -478,14 +490,20 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 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_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_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; @@ -525,14 +543,20 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 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_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_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; diff --git a/examples/AdjustExample-WebView/AdjustExample-WebView/AdjustExample-WebView.html b/examples/AdjustExample-WebView/AdjustExample-WebView/AdjustExample-WebView.html index adb3e702f..4cc76c58a 100644 --- a/examples/AdjustExample-WebView/AdjustExample-WebView/AdjustExample-WebView.html +++ b/examples/AdjustExample-WebView/AdjustExample-WebView/AdjustExample-WebView.html @@ -16,21 +16,13 @@

Adjust Web View Demo

window.onerror = function(err) { } function setupWebViewJavascriptBridge(callback) { - if (window.WebViewJavascriptBridge) { - return callback(WebViewJavascriptBridge); - } - - if (window.WVJBCallbacks) { - return window.WVJBCallbacks.push(callback); - } - + if (window.WebViewJavascriptBridge) { return callback(WebViewJavascriptBridge); } + if (window.WVJBCallbacks) { return window.WVJBCallbacks.push(callback); } window.WVJBCallbacks = [callback]; - var WVJBIframe = document.createElement('iframe'); WVJBIframe.style.display = 'none'; - WVJBIframe.src = 'wvjbscheme://__BRIDGE_LOADED__'; + WVJBIframe.src = 'https://__bridge_loaded__'; document.documentElement.appendChild(WVJBIframe); - setTimeout(function() { document.documentElement.removeChild(WVJBIframe) }, 0) } diff --git a/examples/AdjustExample-iOS/AdjustExample-iOS.xcodeproj/project.pbxproj b/examples/AdjustExample-iOS/AdjustExample-iOS.xcodeproj/project.pbxproj index aa65ce68d..b9202f81e 100644 --- a/examples/AdjustExample-iOS/AdjustExample-iOS.xcodeproj/project.pbxproj +++ b/examples/AdjustExample-iOS/AdjustExample-iOS.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 6FCC850C1F2794AB00D6A0ED /* ADJReachability.m in Sources */ = {isa = PBXBuildFile; fileRef = 6FCC850A1F2794A300D6A0ED /* ADJReachability.m */; }; 963909411BCBFCF300A2E8A4 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 963909401BCBFCF300A2E8A4 /* main.m */; }; 963909441BCBFCF300A2E8A4 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 963909431BCBFCF300A2E8A4 /* AppDelegate.m */; }; 9639094A1BCBFCF300A2E8A4 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 963909481BCBFCF300A2E8A4 /* Main.storyboard */; }; @@ -47,9 +48,12 @@ 9D449E311E6ED88F00E7E80B /* ADJSessionParameters.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D449E0F1E6ED88F00E7E80B /* ADJSessionParameters.m */; }; 9DC95F261C104CEF00138E4B /* ViewControlleriOS.m in Sources */ = {isa = PBXBuildFile; fileRef = 9DC95F251C104CEF00138E4B /* ViewControlleriOS.m */; }; 9DC95F2A1C10515300138E4B /* Constants.m in Sources */ = {isa = PBXBuildFile; fileRef = 9DC95F291C10515300138E4B /* Constants.m */; }; + 9DD0E9BE1F457EF800B2A759 /* ADJUserDefaults.m in Sources */ = {isa = PBXBuildFile; fileRef = 9DD0E9BD1F457EF800B2A759 /* ADJUserDefaults.m */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ + 6FCC850A1F2794A300D6A0ED /* ADJReachability.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ADJReachability.m; sourceTree = ""; }; + 6FCC850B1F2794A300D6A0ED /* ADJReachability.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ADJReachability.h; sourceTree = ""; }; 9639093C1BCBFCF300A2E8A4 /* AdjustExample-iOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "AdjustExample-iOS.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 963909401BCBFCF300A2E8A4 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 963909421BCBFCF300A2E8A4 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; @@ -128,6 +132,8 @@ 9DC95F281C10515300138E4B /* Constants.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Constants.h; sourceTree = ""; }; 9DC95F291C10515300138E4B /* Constants.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Constants.m; sourceTree = ""; }; 9DCA5CF01DD5B6BE000296B2 /* AdjustExample-iOS.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "AdjustExample-iOS.entitlements"; sourceTree = ""; }; + 9DD0E9BC1F457EF800B2A759 /* ADJUserDefaults.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ADJUserDefaults.h; sourceTree = ""; }; + 9DD0E9BD1F457EF800B2A759 /* ADJUserDefaults.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ADJUserDefaults.m; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -261,6 +267,10 @@ 9D449E0D1E6ED88F00E7E80B /* ADJKeychain.m */, 9D449E0E1E6ED88F00E7E80B /* ADJSessionParameters.h */, 9D449E0F1E6ED88F00E7E80B /* ADJSessionParameters.m */, + 6FCC850B1F2794A300D6A0ED /* ADJReachability.h */, + 6FCC850A1F2794A300D6A0ED /* ADJReachability.m */, + 9DD0E9BC1F457EF800B2A759 /* ADJUserDefaults.h */, + 9DD0E9BD1F457EF800B2A759 /* ADJUserDefaults.m */, ); name = Adjust; path = ../../../Adjust; @@ -302,7 +312,7 @@ 963909341BCBFCF300A2E8A4 /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 0810; + LastUpgradeCheck = 0900; ORGANIZATIONNAME = adjust; TargetAttributes = { 9639093B1BCBFCF300A2E8A4 = { @@ -365,10 +375,12 @@ 9D449E141E6ED88F00E7E80B /* UIDevice+ADJAdditions.m in Sources */, 9D449E181E6ED88F00E7E80B /* ADJActivityKind.m in Sources */, 9D449E151E6ED88F00E7E80B /* NSData+ADJAdditions.m in Sources */, + 9DD0E9BE1F457EF800B2A759 /* ADJUserDefaults.m in Sources */, 9D449E191E6ED88F00E7E80B /* ADJActivityPackage.m in Sources */, 9D449E1E1E6ED88F00E7E80B /* ADJPackageHandler.m in Sources */, 9D449E281E6ED88F00E7E80B /* ADJResponseData.m in Sources */, 9D449E301E6ED88F00E7E80B /* ADJKeychain.m in Sources */, + 6FCC850C1F2794AB00D6A0ED /* ADJReachability.m in Sources */, 9D449E131E6ED88F00E7E80B /* NSString+ADJAdditions.m in Sources */, 9D449E221E6ED88F00E7E80B /* ADJDeviceInfo.m in Sources */, 9D449E1C1E6ED88F00E7E80B /* ADJLogger.m in Sources */, @@ -421,14 +433,20 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 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_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_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; @@ -467,14 +485,20 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 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_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_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; diff --git a/examples/AdjustExample-iWatch/AdjustExample-iWatch.xcodeproj/project.pbxproj b/examples/AdjustExample-iWatch/AdjustExample-iWatch.xcodeproj/project.pbxproj index 7c684f203..5cf41c690 100644 --- a/examples/AdjustExample-iWatch/AdjustExample-iWatch.xcodeproj/project.pbxproj +++ b/examples/AdjustExample-iWatch/AdjustExample-iWatch.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 6FCC85181F27950000D6A0ED /* ADJReachability.m in Sources */ = {isa = PBXBuildFile; fileRef = 6FCC85171F2794F800D6A0ED /* ADJReachability.m */; }; 9D449FA31E6EE72000E7E80B /* ADJActivityHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D449F621E6EE72000E7E80B /* ADJActivityHandler.m */; }; 9D449FA41E6EE72000E7E80B /* ADJActivityKind.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D449F641E6EE72000E7E80B /* ADJActivityKind.m */; }; 9D449FA51E6EE72000E7E80B /* ADJActivityPackage.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D449F661E6EE72000E7E80B /* ADJActivityPackage.m */; }; @@ -39,6 +40,7 @@ 9D449FC11E6EE72000E7E80B /* Adjust.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D449F9F1E6EE72000E7E80B /* Adjust.m */; }; 9D449FC21E6EE72000E7E80B /* ADJUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D449FA11E6EE72000E7E80B /* ADJUtil.m */; }; 9D449FC31E6EE72000E7E80B /* Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 9D449FA21E6EE72000E7E80B /* Info.plist */; }; + 9DD0E9C71F45949600B2A759 /* ADJUserDefaults.m in Sources */ = {isa = PBXBuildFile; fileRef = 9DD0E9C61F45949600B2A759 /* ADJUserDefaults.m */; }; 9DF7AC191CB4FEDB00D3591F /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 9DF7AC181CB4FEDB00D3591F /* main.m */; }; 9DF7AC1C1CB4FEDB00D3591F /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 9DF7AC1B1CB4FEDB00D3591F /* AppDelegate.m */; }; 9DF7AC1F1CB4FEDB00D3591F /* ViewControllerWatch.m in Sources */ = {isa = PBXBuildFile; fileRef = 9DF7AC1E1CB4FEDB00D3591F /* ViewControllerWatch.m */; }; @@ -104,6 +106,8 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 6FCC85161F2794F800D6A0ED /* ADJReachability.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ADJReachability.h; sourceTree = ""; }; + 6FCC85171F2794F800D6A0ED /* ADJReachability.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ADJReachability.m; sourceTree = ""; }; 9D449F611E6EE72000E7E80B /* ADJActivityHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ADJActivityHandler.h; sourceTree = ""; }; 9D449F621E6EE72000E7E80B /* ADJActivityHandler.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ADJActivityHandler.m; sourceTree = ""; }; 9D449F631E6EE72000E7E80B /* ADJActivityKind.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ADJActivityKind.h; sourceTree = ""; }; @@ -167,6 +171,8 @@ 9D449FA01E6EE72000E7E80B /* ADJUtil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ADJUtil.h; sourceTree = ""; }; 9D449FA11E6EE72000E7E80B /* ADJUtil.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ADJUtil.m; sourceTree = ""; }; 9D449FA21E6EE72000E7E80B /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 9DD0E9C51F45949600B2A759 /* ADJUserDefaults.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ADJUserDefaults.h; sourceTree = ""; }; + 9DD0E9C61F45949600B2A759 /* ADJUserDefaults.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ADJUserDefaults.m; sourceTree = ""; }; 9DF7AC141CB4FEDB00D3591F /* AdjustExample-iWatch.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "AdjustExample-iWatch.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 9DF7AC181CB4FEDB00D3591F /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 9DF7AC1A1CB4FEDB00D3591F /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; @@ -225,6 +231,7 @@ 9D449F601E6EE72000E7E80B /* Adjust */ = { isa = PBXGroup; children = ( + 9D449F691E6EE72000E7E80B /* ADJAdditions */, 9D449F611E6EE72000E7E80B /* ADJActivityHandler.h */, 9D449F621E6EE72000E7E80B /* ADJActivityHandler.m */, 9D449F631E6EE72000E7E80B /* ADJActivityKind.h */, @@ -233,7 +240,6 @@ 9D449F661E6EE72000E7E80B /* ADJActivityPackage.m */, 9D449F671E6EE72000E7E80B /* ADJActivityState.h */, 9D449F681E6EE72000E7E80B /* ADJActivityState.m */, - 9D449F691E6EE72000E7E80B /* ADJAdditions */, 9D449F701E6EE72000E7E80B /* ADJAdjustFactory.h */, 9D449F711E6EE72000E7E80B /* ADJAdjustFactory.m */, 9D449F721E6EE72000E7E80B /* ADJAttribution.h */, @@ -282,6 +288,10 @@ 9D449F9F1E6EE72000E7E80B /* Adjust.m */, 9D449FA01E6EE72000E7E80B /* ADJUtil.h */, 9D449FA11E6EE72000E7E80B /* ADJUtil.m */, + 6FCC85161F2794F800D6A0ED /* ADJReachability.h */, + 6FCC85171F2794F800D6A0ED /* ADJReachability.m */, + 9DD0E9C51F45949600B2A759 /* ADJUserDefaults.h */, + 9DD0E9C61F45949600B2A759 /* ADJUserDefaults.m */, 9D449FA21E6EE72000E7E80B /* Info.plist */, ); name = Adjust; @@ -450,7 +460,7 @@ 9DF7AC0C1CB4FEDB00D3591F /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 0820; + LastUpgradeCheck = 0900; ORGANIZATIONNAME = "adjust GmbH"; TargetAttributes = { 9DF7AC131CB4FEDB00D3591F = { @@ -459,9 +469,11 @@ }; 9DF7AC2A1CB4FEDB00D3591F = { CreatedOnToolsVersion = 7.3; + DevelopmentTeam = QGUGW9AUMK; }; 9DF7AC391CB4FEDB00D3591F = { CreatedOnToolsVersion = 7.3; + DevelopmentTeam = QGUGW9AUMK; }; }; }; @@ -527,6 +539,7 @@ 9D449FB31E6EE72000E7E80B /* ADJEventSuccess.m in Sources */, 9D449FBF1E6EE72000E7E80B /* ADJTimerCycle.m in Sources */, 9D449FAB1E6EE72000E7E80B /* ADJAttribution.m in Sources */, + 6FCC85181F27950000D6A0ED /* ADJReachability.m in Sources */, 9D449FA61E6EE72000E7E80B /* ADJActivityState.m in Sources */, 9DF7ACB81CB4FF6400D3591F /* AdjustTrackingHelper.m in Sources */, 9DF7AC1F1CB4FEDB00D3591F /* ViewControllerWatch.m in Sources */, @@ -554,6 +567,7 @@ 9D449FB51E6EE72000E7E80B /* ADJLogger.m in Sources */, 9D449FB91E6EE72000E7E80B /* ADJResponseData.m in Sources */, 9D449FB71E6EE72000E7E80B /* ADJPackageHandler.m in Sources */, + 9DD0E9C71F45949600B2A759 /* ADJUserDefaults.m in Sources */, 9D449FA71E6EE72000E7E80B /* NSData+ADJAdditions.m in Sources */, 9D449FC11E6EE72000E7E80B /* Adjust.m in Sources */, 9D449FA51E6EE72000E7E80B /* ADJActivityPackage.m in Sources */, @@ -623,14 +637,20 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 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_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_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; @@ -670,14 +690,20 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 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_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_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; @@ -705,6 +731,7 @@ 9DF7AC4B1CB4FEDB00D3591F /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + DEVELOPMENT_TEAM = QGUGW9AUMK; INFOPLIST_FILE = "AdjustExample-iWatch WatchKit Extension/Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; OTHER_LDFLAGS = "-ObjC"; @@ -720,6 +747,7 @@ 9DF7AC4C1CB4FEDB00D3591F /* Release */ = { isa = XCBuildConfiguration; buildSettings = { + DEVELOPMENT_TEAM = QGUGW9AUMK; INFOPLIST_FILE = "AdjustExample-iWatch WatchKit Extension/Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; OTHER_LDFLAGS = "-ObjC"; @@ -736,6 +764,7 @@ isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + DEVELOPMENT_TEAM = QGUGW9AUMK; IBSC_MODULE = AdjustExample_iWatch_WatchKit_Extension; INFOPLIST_FILE = "AdjustExample-iWatch WatchKit App/Info.plist"; OTHER_LDFLAGS = "-ObjC"; @@ -752,6 +781,7 @@ isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + DEVELOPMENT_TEAM = QGUGW9AUMK; IBSC_MODULE = AdjustExample_iWatch_WatchKit_Extension; INFOPLIST_FILE = "AdjustExample-iWatch WatchKit App/Info.plist"; OTHER_LDFLAGS = "-ObjC"; diff --git a/examples/AdjustExample-tvOS/AdjustExample-tvOS.xcodeproj/project.pbxproj b/examples/AdjustExample-tvOS/AdjustExample-tvOS.xcodeproj/project.pbxproj index ebfca8f89..1409e8221 100644 --- a/examples/AdjustExample-tvOS/AdjustExample-tvOS.xcodeproj/project.pbxproj +++ b/examples/AdjustExample-tvOS/AdjustExample-tvOS.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 6FCC85151F2794EC00D6A0ED /* ADJReachability.m in Sources */ = {isa = PBXBuildFile; fileRef = 6FCC85131F2794E800D6A0ED /* ADJReachability.m */; }; 963909B71BCC0D8300A2E8A4 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 963909B61BCC0D8300A2E8A4 /* main.m */; }; 963909BA1BCC0D8300A2E8A4 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 963909B91BCC0D8300A2E8A4 /* AppDelegate.m */; }; 963909BD1BCC0D8300A2E8A4 /* ViewControllertvOS.m in Sources */ = {isa = PBXBuildFile; fileRef = 963909BC1BCC0D8300A2E8A4 /* ViewControllertvOS.m */; }; @@ -46,6 +47,7 @@ 9D449F5E1E6EE6C500E7E80B /* ADJUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D449F3D1E6EE6C500E7E80B /* ADJUtil.m */; }; 9D449F5F1E6EE6C500E7E80B /* Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 9D449F3E1E6EE6C500E7E80B /* Info.plist */; }; 9DC95F2F1C10596500138E4B /* Constants.m in Sources */ = {isa = PBXBuildFile; fileRef = 9DC95F2E1C10596500138E4B /* Constants.m */; }; + 9DD0E9CF1F459ECE00B2A759 /* ADJUserDefaults.m in Sources */ = {isa = PBXBuildFile; fileRef = 9DD0E9CE1F459ECE00B2A759 /* ADJUserDefaults.m */; }; /* End PBXBuildFile section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -62,6 +64,8 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 6FCC85131F2794E800D6A0ED /* ADJReachability.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ADJReachability.m; sourceTree = ""; }; + 6FCC85141F2794E800D6A0ED /* ADJReachability.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ADJReachability.h; sourceTree = ""; }; 963909B21BCC0D8300A2E8A4 /* AdjustExample-tvOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "AdjustExample-tvOS.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 963909B61BCC0D8300A2E8A4 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 963909B81BCC0D8300A2E8A4 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; @@ -137,6 +141,8 @@ 9D449F3E1E6EE6C500E7E80B /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 9DC95F2D1C10596500138E4B /* Constants.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Constants.h; sourceTree = ""; }; 9DC95F2E1C10596500138E4B /* Constants.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Constants.m; sourceTree = ""; }; + 9DD0E9CD1F459ECE00B2A759 /* ADJUserDefaults.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ADJUserDefaults.h; sourceTree = ""; }; + 9DD0E9CE1F459ECE00B2A759 /* ADJUserDefaults.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ADJUserDefaults.m; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -197,6 +203,7 @@ 9D449EFC1E6EE6C400E7E80B /* Adjust */ = { isa = PBXGroup; children = ( + 9D449F051E6EE6C500E7E80B /* ADJAdditions */, 9D449EFD1E6EE6C400E7E80B /* ADJActivityHandler.h */, 9D449EFE1E6EE6C500E7E80B /* ADJActivityHandler.m */, 9D449EFF1E6EE6C500E7E80B /* ADJActivityKind.h */, @@ -205,7 +212,6 @@ 9D449F021E6EE6C500E7E80B /* ADJActivityPackage.m */, 9D449F031E6EE6C500E7E80B /* ADJActivityState.h */, 9D449F041E6EE6C500E7E80B /* ADJActivityState.m */, - 9D449F051E6EE6C500E7E80B /* ADJAdditions */, 9D449F0C1E6EE6C500E7E80B /* ADJAdjustFactory.h */, 9D449F0D1E6EE6C500E7E80B /* ADJAdjustFactory.m */, 9D449F0E1E6EE6C500E7E80B /* ADJAttribution.h */, @@ -254,6 +260,10 @@ 9D449F3B1E6EE6C500E7E80B /* Adjust.m */, 9D449F3C1E6EE6C500E7E80B /* ADJUtil.h */, 9D449F3D1E6EE6C500E7E80B /* ADJUtil.m */, + 6FCC85141F2794E800D6A0ED /* ADJReachability.h */, + 6FCC85131F2794E800D6A0ED /* ADJReachability.m */, + 9DD0E9CD1F459ECE00B2A759 /* ADJUserDefaults.h */, + 9DD0E9CE1F459ECE00B2A759 /* ADJUserDefaults.m */, 9D449F3E1E6EE6C500E7E80B /* Info.plist */, ); name = Adjust; @@ -308,7 +318,7 @@ 963909AA1BCC0D8300A2E8A4 /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 0810; + LastUpgradeCheck = 0900; ORGANIZATIONNAME = adjust; TargetAttributes = { 963909B11BCC0D8300A2E8A4 = { @@ -371,10 +381,12 @@ 963909BA1BCC0D8300A2E8A4 /* AppDelegate.m in Sources */, 9D449F4A1E6EE6C500E7E80B /* ADJConfig.m in Sources */, 9D449F571E6EE6C500E7E80B /* ADJSessionFailure.m in Sources */, + 9DD0E9CF1F459ECE00B2A759 /* ADJUserDefaults.m in Sources */, 9D449F5E1E6EE6C500E7E80B /* ADJUtil.m in Sources */, 9D449F4E1E6EE6C500E7E80B /* ADJEventFailure.m in Sources */, 9D449F461E6EE6C500E7E80B /* ADJAdjustFactory.m in Sources */, 9D449F3F1E6EE6C500E7E80B /* ADJActivityHandler.m in Sources */, + 6FCC85151F2794EC00D6A0ED /* ADJReachability.m in Sources */, 9D449F5C1E6EE6C500E7E80B /* ADJTimerOnce.m in Sources */, 9D449F401E6EE6C500E7E80B /* ADJActivityKind.m in Sources */, 9D449F481E6EE6C500E7E80B /* ADJAttributionHandler.m in Sources */, @@ -419,14 +431,20 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 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_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_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; @@ -465,14 +483,20 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 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_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_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;