From a1e064921a1d4eeb653caf6e9b40f750f562a96b Mon Sep 17 00:00:00 2001 From: Glen Tregoning Date: Sat, 30 Jan 2016 17:20:37 -0800 Subject: [PATCH 01/19] Fixing documentation warnings in Xcode Version 7.2 (7C68) / iOS 9.2 --- Adjust/ADJConfig.h | 6 +++--- Adjust/ADJEvent.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Adjust/ADJConfig.h b/Adjust/ADJConfig.h index 70f953db1..ff5d71dfb 100644 --- a/Adjust/ADJConfig.h +++ b/Adjust/ADJConfig.h @@ -52,7 +52,7 @@ * You can increase or reduce the amount of logs from Adjust by passing * one of the following parameters. Use Log.ASSERT to disable all logging. * - * @param logLevel The desired minimum log level (default: info) + * @var logLevel The desired minimum log level (default: info) * Must be one of the following: * - ADJLogLevelVerbose (enable all logging) * - ADJLogLevelDebug (enable more logging) @@ -68,7 +68,7 @@ * When enabled, events get buffered and only get tracked each * minute. Buffered events are still persisted, of course. * - * @param eventBufferingEnabled Enable or disable event buffering + * @var eventBufferingEnabled Enable or disable event buffering */ @property (nonatomic, assign) BOOL eventBufferingEnabled; @@ -77,7 +77,7 @@ * * See the AdjustDelegate declaration above for details * - * @param delegate The delegate that might implement the optional delegate + * @var delegate The delegate that might implement the optional delegate * methods like adjustAttributionChanged: */ @property (nonatomic, weak) NSObject *delegate; diff --git a/Adjust/ADJEvent.h b/Adjust/ADJEvent.h index 0b4c7caca..7fcb8881d 100644 --- a/Adjust/ADJEvent.h +++ b/Adjust/ADJEvent.h @@ -22,7 +22,7 @@ /** * Create Event object with Event Token. * - * @param event Event token that is created in the dashboard + * @param eventToken Event token that is created in the dashboard * at http://adjust.com and should be six characters long. */ + (ADJEvent *)eventWithEventToken:(NSString *)eventToken; From ebbd7d50b1be8a6d6dfc49ed61dd4ce57f749612 Mon Sep 17 00:00:00 2001 From: mugx Date: Wed, 3 Feb 2016 17:26:41 +0100 Subject: [PATCH 02/19] fixed warnings due to -fembed-bitcode --- Adjust.xcodeproj/project.pbxproj | 1 + 1 file changed, 1 insertion(+) diff --git a/Adjust.xcodeproj/project.pbxproj b/Adjust.xcodeproj/project.pbxproj index 77f4ff055..a3ac12911 100644 --- a/Adjust.xcodeproj/project.pbxproj +++ b/Adjust.xcodeproj/project.pbxproj @@ -950,6 +950,7 @@ COPY_PHASE_STRIP = NO; ENABLE_NS_ASSERTIONS = NO; GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_GENERATE_DEBUGGING_SYMBOLS = NO; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; From 7afca61c5e3b8135ec670642b8a0079a3fdec623 Mon Sep 17 00:00:00 2001 From: uerceg Date: Thu, 4 Feb 2016 11:21:08 +0100 Subject: [PATCH 03/19] Update .gitignore --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 144b934da..e0d014ff0 100644 --- a/.gitignore +++ b/.gitignore @@ -24,3 +24,6 @@ Pods # git files *.orig + +# Adjust +Frameworks From c6f39bd935a3309212c0817960f65ed2edd7b1f9 Mon Sep 17 00:00:00 2001 From: uerceg Date: Thu, 4 Feb 2016 11:21:33 +0100 Subject: [PATCH 04/19] Copy static framework from build folder --- Adjust.xcodeproj/project.pbxproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Adjust.xcodeproj/project.pbxproj b/Adjust.xcodeproj/project.pbxproj index 77f4ff055..43a8b1d60 100644 --- a/Adjust.xcodeproj/project.pbxproj +++ b/Adjust.xcodeproj/project.pbxproj @@ -779,7 +779,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "set -e\n\n# If we're already inside this script then die\nif [ -n \"$RW_MULTIPLATFORM_BUILD_IN_PROGRESS\" ]; then\nexit 0\nfi\nexport RW_MULTIPLATFORM_BUILD_IN_PROGRESS=1\n\nRW_FRAMEWORK_NAME=${PROJECT_NAME}\nRW_INPUT_STATIC_LIB=\"lib${PROJECT_NAME}.a\"\nRW_FRAMEWORK_LOCATION=\"${BUILT_PRODUCTS_DIR}/Static/${RW_FRAMEWORK_NAME}Sdk.framework\"\n\nfunction build_static_library {\n echo \"1\"\n echo \"${BUILD_DIR}\"\n # Will rebuild the static library as specified\n # build_static_library sdk\n xcrun xcodebuild -project \"${PROJECT_FILE_PATH}\" \\\n -target \"${TARGET_NAME}\" \\\n -configuration \"${CONFIGURATION}\" \\\n -sdk \"${1}\" \\\n ONLY_ACTIVE_ARCH=NO \\\n BUILD_DIR=\"${BUILD_DIR}\" \\\n OBJROOT=\"${OBJROOT}\" \\\n BUILD_ROOT=\"${BUILD_ROOT}\" \\\n SYMROOT=\"${SYMROOT}\" $ACTION\n}\n\nfunction make_fat_library {\n # Will smash 2 static libs together\n # make_fat_library in1 in2 out\n xcrun lipo -create \"${1}\" \"${2}\" -output \"${3}\"\n}\n\n# 1 - Extract the platform (iphoneos/iphonesimulator) from the SDK name\nif [[ \"$SDK_NAME\" =~ ([A-Za-z]+) ]]; then\nRW_SDK_PLATFORM=${BASH_REMATCH[1]}\nelse\necho \"Could not find platform name from SDK_NAME: $SDK_NAME\"\nexit 1\nfi\n\n# 2 - Extract the version from the SDK\nif [[ \"$SDK_NAME\" =~ ([0-9]+.*$) ]]; then\nRW_SDK_VERSION=${BASH_REMATCH[1]}\nelse\necho \"Could not find sdk version from SDK_NAME: $SDK_NAME\"\nexit 1\nfi\n\n# 3 - Determine the other platform\nif [ \"$RW_SDK_PLATFORM\" == \"iphoneos\" ]; then\nRW_OTHER_PLATFORM=iphonesimulator\nelse\nRW_OTHER_PLATFORM=iphoneos\nfi\n\n# 4 - Find the build directory\nif [[ \"$BUILT_PRODUCTS_DIR\" =~ (.*)$RW_SDK_PLATFORM$ ]]; then\nRW_OTHER_BUILT_PRODUCTS_DIR=\"${BASH_REMATCH[1]}${RW_OTHER_PLATFORM}\"\nelse\necho \"Could not find other platform build directory.\"\nexit 1\nfi\n\n# Build the other platform.\nbuild_static_library \"${RW_OTHER_PLATFORM}${RW_SDK_VERSION}\"\n\n# If we're currently building for iphonesimulator, then need to rebuild\n# to ensure that we get both i386 and x86_64\nif [ \"$RW_SDK_PLATFORM\" == \"iphonesimulator\" ]; then\nbuild_static_library \"${SDK_NAME}\"\nfi\n\n# Join the 2 static libs into 1 and push into the .framework\nmake_fat_library \"${BUILT_PRODUCTS_DIR}/${RW_INPUT_STATIC_LIB}\" \\\n\"${RW_OTHER_BUILT_PRODUCTS_DIR}/${RW_INPUT_STATIC_LIB}\" \\\n\"${RW_FRAMEWORK_LOCATION}/Versions/A/${RW_FRAMEWORK_NAME}Sdk\"\n\n# Ensure that the framework is present in both platform's build directories\ncp -a \"${RW_FRAMEWORK_LOCATION}/Versions/A/${RW_FRAMEWORK_NAME}Sdk\" \\\n\"${RW_OTHER_BUILT_PRODUCTS_DIR}/Static/${RW_FRAMEWORK_NAME}Sdk.framework/Versions/A/${RW_FRAMEWORK_NAME}Sdk\""; + shellScript = "set -e\n\n# If we're already inside this script then die\nif [ -n \"$RW_MULTIPLATFORM_BUILD_IN_PROGRESS\" ]; then\nexit 0\nfi\nexport RW_MULTIPLATFORM_BUILD_IN_PROGRESS=1\n\nRW_FRAMEWORK_NAME=${PROJECT_NAME}\nRW_INPUT_STATIC_LIB=\"lib${PROJECT_NAME}.a\"\nRW_FRAMEWORK_LOCATION=\"${BUILT_PRODUCTS_DIR}/Static/${RW_FRAMEWORK_NAME}Sdk.framework\"\n\nfunction build_static_library {\n echo \"1\"\n echo \"${BUILD_DIR}\"\n # Will rebuild the static library as specified\n # build_static_library sdk\n xcrun xcodebuild -project \"${PROJECT_FILE_PATH}\" \\\n -target \"${TARGET_NAME}\" \\\n -configuration \"${CONFIGURATION}\" \\\n -sdk \"${1}\" \\\n ONLY_ACTIVE_ARCH=NO \\\n BUILD_DIR=\"${BUILD_DIR}\" \\\n OBJROOT=\"${OBJROOT}\" \\\n BUILD_ROOT=\"${BUILD_ROOT}\" \\\n SYMROOT=\"${SYMROOT}\" $ACTION\n}\n\nfunction make_fat_library {\n # Will smash 2 static libs together\n # make_fat_library in1 in2 out\n xcrun lipo -create \"${1}\" \"${2}\" -output \"${3}\"\n}\n\n# 1 - Extract the platform (iphoneos/iphonesimulator) from the SDK name\nif [[ \"$SDK_NAME\" =~ ([A-Za-z]+) ]]; then\nRW_SDK_PLATFORM=${BASH_REMATCH[1]}\nelse\necho \"Could not find platform name from SDK_NAME: $SDK_NAME\"\nexit 1\nfi\n\n# 2 - Extract the version from the SDK\nif [[ \"$SDK_NAME\" =~ ([0-9]+.*$) ]]; then\nRW_SDK_VERSION=${BASH_REMATCH[1]}\nelse\necho \"Could not find sdk version from SDK_NAME: $SDK_NAME\"\nexit 1\nfi\n\n# 3 - Determine the other platform\nif [ \"$RW_SDK_PLATFORM\" == \"iphoneos\" ]; then\nRW_OTHER_PLATFORM=iphonesimulator\nelse\nRW_OTHER_PLATFORM=iphoneos\nfi\n\n# 4 - Find the build directory\nif [[ \"$BUILT_PRODUCTS_DIR\" =~ (.*)$RW_SDK_PLATFORM$ ]]; then\nRW_OTHER_BUILT_PRODUCTS_DIR=\"${BASH_REMATCH[1]}${RW_OTHER_PLATFORM}\"\nelse\necho \"Could not find other platform build directory.\"\nexit 1\nfi\n\n# Build the other platform.\nbuild_static_library \"${RW_OTHER_PLATFORM}${RW_SDK_VERSION}\"\n\n# If we're currently building for iphonesimulator, then need to rebuild\n# to ensure that we get both i386 and x86_64\nif [ \"$RW_SDK_PLATFORM\" == \"iphonesimulator\" ]; then\nbuild_static_library \"${SDK_NAME}\"\nfi\n\n# Join the 2 static libs into 1 and push into the .framework\nmake_fat_library \"${BUILT_PRODUCTS_DIR}/${RW_INPUT_STATIC_LIB}\" \\\n\"${RW_OTHER_BUILT_PRODUCTS_DIR}/${RW_INPUT_STATIC_LIB}\" \\\n\"${RW_FRAMEWORK_LOCATION}/Versions/A/${RW_FRAMEWORK_NAME}Sdk\"\n\n# Ensure that the framework is present in both platform's build directories\ncp -a \"${RW_FRAMEWORK_LOCATION}/Versions/A/${RW_FRAMEWORK_NAME}Sdk\" \\\n\"${RW_OTHER_BUILT_PRODUCTS_DIR}/Static/${RW_FRAMEWORK_NAME}Sdk.framework/Versions/A/${RW_FRAMEWORK_NAME}Sdk\"\n\n# Copy the framework to the project directory\nditto \"${RW_FRAMEWORK_LOCATION}\" \"${SRCROOT}/Frameworks/Static/${RW_FRAMEWORK_NAME}Sdk.framework\""; }; /* End PBXShellScriptBuildPhase section */ From 325323b8ee9d0d34c14dd8f521ec459abe71f390 Mon Sep 17 00:00:00 2001 From: uerceg Date: Thu, 4 Feb 2016 11:27:41 +0100 Subject: [PATCH 05/19] Copy dynamic framework from build folder --- Adjust.xcodeproj/project.pbxproj | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/Adjust.xcodeproj/project.pbxproj b/Adjust.xcodeproj/project.pbxproj index 43a8b1d60..5f0b75a62 100644 --- a/Adjust.xcodeproj/project.pbxproj +++ b/Adjust.xcodeproj/project.pbxproj @@ -660,6 +660,7 @@ 9DFA37A91C0F219400782607 /* Frameworks */, 9DFA37AA1C0F219400782607 /* Headers */, 9DFA37AB1C0F219400782607 /* Resources */, + 9DB1EE2C1C635DC0007FCFFC /* Copy Dynamic Framework */, ); buildRules = ( ); @@ -753,6 +754,20 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ + 9DB1EE2C1C635DC0007FCFFC /* Copy Dynamic Framework */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Copy Dynamic Framework"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "set -e\n\n# If we're already inside this script then die\nif [ -n \"$RW_MULTIPLATFORM_BUILD_IN_PROGRESS\" ]; then\nexit 0\nfi\nexport RW_MULTIPLATFORM_BUILD_IN_PROGRESS=1\n\nRW_FRAMEWORK_NAME=${PROJECT_NAME}\nRW_FRAMEWORK_LOCATION=\"${BUILT_PRODUCTS_DIR}/${RW_FRAMEWORK_NAME}Sdk.framework\"\n\n# Copy the framework to the project directory\nditto \"${RW_FRAMEWORK_LOCATION}\" \"${SRCROOT}/Frameworks/Dynamic/${RW_FRAMEWORK_NAME}Sdk.framework\""; + }; 9DE7C9011AE68F68001556E5 /* Build Framework */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; From cd91a1e9e35ce3913604d962eefbc4f180a32b94 Mon Sep 17 00:00:00 2001 From: uerceg Date: Thu, 4 Feb 2016 11:34:11 +0100 Subject: [PATCH 06/19] Adding adjust build script --- Scripts/adjust_build.sh | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100755 Scripts/adjust_build.sh diff --git a/Scripts/adjust_build.sh b/Scripts/adjust_build.sh new file mode 100755 index 000000000..4d0994fbc --- /dev/null +++ b/Scripts/adjust_build.sh @@ -0,0 +1,24 @@ +#!/usr/bin/env bash + +# End script if one of the lines fails +set -e + +# Go to root folder +cd .. + +# Create needed folders if they don't exist +mkdir -p Frameworks/Static +mkdir -p Frameworks/Dynamic +mkdir -p Frameworks/Carthage + +# Build static AdjustSdk.framework +xcodebuild -target AdjustStatic -configuration Release + +# Build dynamic AdjustSdk.framework +xcodebuild -target AdjustSdk -configuration Release + +# Build Carthage AdjustSdk.framework +carthage build --no-skip-current + +# Copy build Carthage framework to Frameworks folder +cp -R Carthage/Build/iOS/* Frameworks/Carthage/ From 2656ee157dcbb5c8c3a249c507db9fb36e325052 Mon Sep 17 00:00:00 2001 From: Pedro Date: Thu, 4 Feb 2016 15:56:31 +0100 Subject: [PATCH 07/19] Add is not null helper --- Adjust/ADJEvent.m | 4 ++-- Adjust/ADJUtil.h | 1 + Adjust/ADJUtil.m | 4 ++++ 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/Adjust/ADJEvent.m b/Adjust/ADJEvent.m index 13492c495..56742249a 100644 --- a/Adjust/ADJEvent.m +++ b/Adjust/ADJEvent.m @@ -135,7 +135,7 @@ - (BOOL) checkRevenue:(NSNumber*) revenue return NO; } } else { - if (![ADJUtil isNull:currency]) { + if ([ADJUtil isNotNull:currency]) { [self.logger error:@"Revenue must be set with currency"]; return NO; } @@ -159,7 +159,7 @@ - (void) setReceipt:(NSData *)receipt transactionId:(NSString *)transactionId { } - (BOOL) checkReceipt:(NSData *)receipt transactionId:(NSString *)transactionId { - if (![ADJUtil isNull:receipt] && [ADJUtil isNull:transactionId]) { + if ([ADJUtil isNotNull:receipt] && [ADJUtil isNull:transactionId]) { [self.logger error:@"Missing transactionId"]; return NO; } diff --git a/Adjust/ADJUtil.h b/Adjust/ADJUtil.h index 5c2acdd3e..9cf52899a 100644 --- a/Adjust/ADJUtil.h +++ b/Adjust/ADJUtil.h @@ -30,6 +30,7 @@ + (NSString *) queryString:(NSDictionary *)parameters; + (BOOL)isNull:(id)value; ++ (BOOL)isNotNull:(id)value; + (void)sendRequest:(NSMutableURLRequest *)request prefixErrorMessage:(NSString *)prefixErrorMessage jsonResponseHandler:(void (^) (NSDictionary * jsonDict))jsonResponseHandler; diff --git a/Adjust/ADJUtil.m b/Adjust/ADJUtil.m index 768da1c4c..d4a7ad48c 100644 --- a/Adjust/ADJUtil.m +++ b/Adjust/ADJUtil.m @@ -201,6 +201,10 @@ + (BOOL)isNull:(id)value { return value == nil || value == (id)[NSNull null]; } ++ (BOOL)isNotNull:(id)value { + return value != nil && value != (id)[NSNull null]; +} + + (NSString *)formatErrorMessage:(NSString *)prefixErrorMessage systemErrorMessage:(NSString *)systemErrorMessage suffixErrorMessage:(NSString *)suffixErrorMessage From 82086dc598db041cb87ede12ab09d6e0556849b1 Mon Sep 17 00:00:00 2001 From: Pedro Date: Thu, 4 Feb 2016 15:58:47 +0100 Subject: [PATCH 08/19] Add parse universal link --- Adjust/ADJUtil.h | 2 ++ Adjust/ADJUtil.m | 70 ++++++++++++++++++++++++++++++++++++++++++++++++ Adjust/Adjust.h | 1 + Adjust/Adjust.m | 9 +++++++ 4 files changed, 82 insertions(+) diff --git a/Adjust/ADJUtil.h b/Adjust/ADJUtil.h index 9cf52899a..dad6252df 100644 --- a/Adjust/ADJUtil.h +++ b/Adjust/ADJUtil.h @@ -41,4 +41,6 @@ jsonResponseHandler:(void (^) (NSDictionary * jsonDict))jsonResponseHandler; jsonResponseHandler:(void (^) (NSDictionary * jsonDict))jsonResponseHandler; + (NSDictionary *)convertDictionaryValues:(NSDictionary *)dictionary; + ++ (NSURL*)parseUniversalLink:(NSURL *)url scheme:(NSString *)scheme; @end diff --git a/Adjust/ADJUtil.m b/Adjust/ADJUtil.m index d4a7ad48c..74c092cea 100644 --- a/Adjust/ADJUtil.m +++ b/Adjust/ADJUtil.m @@ -358,4 +358,74 @@ + (NSDictionary *)convertDictionaryValues:(NSDictionary *)dictionary return convertedDictionary; } + ++ (NSURL*)parseUniversalLink:(NSURL *)url scheme:(NSString *)scheme +{ + id logger = ADJAdjustFactory.logger; + + if ([ADJUtil isNull:url]) + { + [logger error:@"Received UniversalLink is nil"]; + return nil; + } + + NSString * urlString = [url absoluteString]; + if ([ADJUtil isNull:urlString]) + { + [logger error:@"Parsed UniversalLink is nil"]; + return nil; + } + + NSError *error = NULL; + NSString * pattern = @"https://(?:.*)\\.ulink\\.adjust\\.com/ulink/?([^?#]*)([^#]*)(.*)"; + + NSRegularExpression *regex = [NSRegularExpression + regularExpressionWithPattern:pattern + options:NSRegularExpressionCaseInsensitive error:&error]; + + if ([ADJUtil isNotNull:error]) + { + [logger error:@"UniversalLink regex rule error (%@)", [error description]]; + return nil; + } + + NSArray * matches = [regex matchesInString:urlString options:0 range:NSMakeRange(0, [urlString length])]; + + if ([matches count] != 1) + { + [logger error:@"UniversalLink not matched to pattern"]; + return nil; + } + + NSTextCheckingResult * match = matches[0]; + + if ([match numberOfRanges] != 4) + { + [logger error:@"Wrong number of Ranges matched"]; + return nil; + } + + NSString * pathSubString = [urlString substringWithRange:[match rangeAtIndex:1]]; + NSString * querySubString = [urlString substringWithRange:[match rangeAtIndex:2]]; + NSString * fragmentSubString = [urlString substringWithRange:[match rangeAtIndex:3]]; + + if ([ADJUtil isNull:scheme] || [scheme length] == 0) { + [logger warn:@"Non-empty scheme required, using the scheme \"AdjustUniversalScheme\""]; + scheme = @"AdjustUniversalScheme"; + } + + NSString * extractedUrlString = [NSString stringWithFormat:@"%@://%@%@%@", scheme, pathSubString, querySubString, fragmentSubString]; + + [logger info:@"Extracted deeplink from UniversalLink %@", extractedUrlString]; + + NSURL * extractedUrl = [NSURL URLWithString:extractedUrlString]; + + if ([ADJUtil isNull:extractedUrl]) { + [logger error:@"Unable to parse extracted deeplink from UniversalLink %@", extractedUrlString]; + return nil; + } + + return extractedUrl; +} + @end diff --git a/Adjust/Adjust.h b/Adjust/Adjust.h index dd7509978..b650f1565 100644 --- a/Adjust/Adjust.h +++ b/Adjust/Adjust.h @@ -96,6 +96,7 @@ extern NSString * const ADJEnvironmentProduction; + (void)setOfflineMode:(BOOL)enabled; + (NSString*)idfa; ++ (NSURL*)parseUniversalLink:(NSURL *)url scheme:(NSString *)scheme; /** * Obtain singleton Adjust object diff --git a/Adjust/Adjust.m b/Adjust/Adjust.m index 1fa9fef08..5ef80cce0 100644 --- a/Adjust/Adjust.m +++ b/Adjust/Adjust.m @@ -11,6 +11,7 @@ #import "ADJAdjustFactory.h" #import "ADJLogger.h" #import "UIDevice+ADJAdditions.h" +#import "ADJUtil.h" #if !__has_feature(objc_arc) #error Adjust requires ARC @@ -69,6 +70,10 @@ + (NSString*)idfa { return [[UIDevice currentDevice] adjIdForAdvertisers]; } ++ (NSURL*)parseUniversalLink:(NSURL *)url scheme:(NSString *)scheme { + return [[Adjust getInstance] parseUniversalLink:url scheme:scheme]; +} + + (id)getInstance { static Adjust *defaultInstance = nil; static dispatch_once_t onceToken; @@ -142,6 +147,10 @@ - (NSString*)idfa { return [[UIDevice currentDevice] adjIdForAdvertisers]; } +- (NSURL*)parseUniversalLink:(NSURL *)url scheme:(NSString *)scheme { + return [ADJUtil parseUniversalLink:url scheme:scheme]; +} + #pragma mark - private - (BOOL) checkActivityHandler { From 31eb1f805527bc7c211e380f363c1d505cc2c607 Mon Sep 17 00:00:00 2001 From: Pedro Date: Thu, 4 Feb 2016 15:59:14 +0100 Subject: [PATCH 09/19] Test universal link parse --- AdjustTests/ADJActivityHandlerTests.m | 127 ++++++++++++++++++++++++++ AdjustTests/ADJTest.h | 4 + 2 files changed, 131 insertions(+) diff --git a/AdjustTests/ADJActivityHandlerTests.m b/AdjustTests/ADJActivityHandlerTests.m index 6c3929f6c..30175e29e 100644 --- a/AdjustTests/ADJActivityHandlerTests.m +++ b/AdjustTests/ADJActivityHandlerTests.m @@ -1494,6 +1494,133 @@ - (void)testTimer //[self checkTimerIsFired:NO]; } +- (void)testParseUniversalLink +{ + // reseting to make the test order independent + [self reset]; + + // nil url + aNil([ADJUtil parseUniversalLink:nil scheme:nil]); + aError(@"Received UniversalLink is nil"); + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wnonnull" + NSURL* nilStringUrl = [NSURL URLWithString:nil]; +#pragma clang diagnostic pop + + // empty url + aNil([ADJUtil parseUniversalLink:nilStringUrl scheme:nil]); + aError(@"Received UniversalLink is nil"); + + // nil scheme + NSString * nilScheme = nil; + + anNil([ADJUtil parseUniversalLink:[self getUniversalLinkUrl:@""] scheme:nilScheme]); + aWarn(@"Non-empty scheme required, using the scheme \"AdjustUniversalScheme\""); + aInfo(@"Extracted deeplink from UniversalLink AdjustUniversalScheme://"); + + // empty Scheme + NSString * emptyScheme = @""; + + anNil([ADJUtil parseUniversalLink:[self getUniversalLinkUrl:@""] scheme:emptyScheme]); + aWarn(@"Non-empty scheme required, using the scheme \"AdjustUniversalScheme\""); + aInfo(@"Extracted deeplink from UniversalLink AdjustUniversalScheme://"); + + // custom scheme empty path + NSString * adjustScheme = @"AdjustTestScheme"; + + anNil([ADJUtil parseUniversalLink:[self getUniversalLinkUrl:@""] scheme:adjustScheme]); + aInfo(@"Extracted deeplink from UniversalLink AdjustTestScheme://"); + + // non Universal Url + NSURL * nonUniversalUrl = [NSURL URLWithString:@"AdjustTestScheme://nonUniversalUrl"]; + aNil([ADJUtil parseUniversalLink:nonUniversalUrl scheme:adjustScheme]); + aError(@"UniversalLink not matched to pattern"); + + // path / + anNil([ADJUtil parseUniversalLink:[self getUniversalLinkUrl:@"/"] scheme:adjustScheme]); + aInfo(@"Extracted deeplink from UniversalLink AdjustTestScheme://"); + + // path /yourpath + anNil([ADJUtil parseUniversalLink:[self getUniversalLinkUrl:@"/yourpath"] scheme:adjustScheme]); + aInfo(@"Extracted deeplink from UniversalLink AdjustTestScheme://yourpath"); + + // path /yourpath/ + anNil([ADJUtil parseUniversalLink:[self getUniversalLinkUrl:@"/yourpath/"] scheme:adjustScheme]); + aInfo(@"Extracted deeplink from UniversalLink AdjustTestScheme://yourpath/"); + + // path yourpath + anNil([ADJUtil parseUniversalLink:[self getUniversalLinkUrl:@"yourpath"] scheme:adjustScheme]); + aInfo(@"Extracted deeplink from UniversalLink AdjustTestScheme://yourpath"); + + // path yourpath/ + anNil([ADJUtil parseUniversalLink:[self getUniversalLinkUrl:@"yourpath/"] scheme:adjustScheme]); + aInfo(@"Extracted deeplink from UniversalLink AdjustTestScheme://yourpath/"); + + // path / query ?key=value&foo=bar + anNil([ADJUtil parseUniversalLink:[self getUniversalLinkUrl:@"/?key=value&foo=bar"] scheme:adjustScheme]); + aInfo(@"Extracted deeplink from UniversalLink AdjustTestScheme://?key=value&foo=bar"); + + // path /yourpath query ?key=value&foo=bar + anNil([ADJUtil parseUniversalLink:[self getUniversalLinkUrl:@"/yourpath?key=value&foo=bar"] scheme:adjustScheme]); + aInfo(@"Extracted deeplink from UniversalLink AdjustTestScheme://yourpath?key=value&foo=bar"); + + // path /yourpath/ query ?key=value&foo=bar + anNil([ADJUtil parseUniversalLink:[self getUniversalLinkUrl:@"/yourpath/?key=value&foo=bar"] scheme:adjustScheme]); + aInfo(@"Extracted deeplink from UniversalLink AdjustTestScheme://yourpath/?key=value&foo=bar"); + + // path yourpath query ?key=value&foo=bar + anNil([ADJUtil parseUniversalLink:[self getUniversalLinkUrl:@"yourpath?key=value&foo=bar"] scheme:adjustScheme]); + aInfo(@"Extracted deeplink from UniversalLink AdjustTestScheme://yourpath?key=value&foo=bar"); + + // path yourpath/ query ?key=value&foo=bar + anNil([ADJUtil parseUniversalLink:[self getUniversalLinkUrl:@"yourpath/?key=value&foo=bar"] scheme:adjustScheme]); + aInfo(@"Extracted deeplink from UniversalLink AdjustTestScheme://yourpath/?key=value&foo=bar"); + + // empty path/query fragment # + anNil([ADJUtil parseUniversalLink:[self getUniversalLinkUrl:@"#"] scheme:adjustScheme]); + aInfo(@"Extracted deeplink from UniversalLink AdjustTestScheme://#"); + + // empty path/query fragment #fragment + anNil([ADJUtil parseUniversalLink:[self getUniversalLinkUrl:@"#fragment"] scheme:adjustScheme]); + aInfo(@"Extracted deeplink from UniversalLink AdjustTestScheme://#fragment"); + + // path /yourpath/ fragment #fragment + anNil([ADJUtil parseUniversalLink:[self getUniversalLinkUrl:@"/yourpath/#fragment"] scheme:adjustScheme]); + aInfo(@"Extracted deeplink from UniversalLink AdjustTestScheme://yourpath/#fragment"); + + // path yourpath fragment #fragment + anNil([ADJUtil parseUniversalLink:[self getUniversalLinkUrl:@"yourpath#fragment"] scheme:adjustScheme]); + aInfo(@"Extracted deeplink from UniversalLink AdjustTestScheme://yourpath#fragment"); + + // empty path query ?key=value&foo=bar fragment #fragment + anNil([ADJUtil parseUniversalLink:[self getUniversalLinkUrl:@"?key=value&foo=bar#fragment"] scheme:adjustScheme]); + aInfo(@"Extracted deeplink from UniversalLink AdjustTestScheme://?key=value&foo=bar#fragment"); + + // path /yourpath/ query ?key=value&foo=bar fragment #fragment + anNil([ADJUtil parseUniversalLink:[self getUniversalLinkUrl:@"/yourpath/?key=value&foo=bar#fragment"] scheme:adjustScheme]); + aInfo(@"Extracted deeplink from UniversalLink AdjustTestScheme://yourpath/?key=value&foo=bar#fragment"); + + // path yourpath query ?key=value&foo=bar fragment #fragment + anNil([ADJUtil parseUniversalLink:[self getUniversalLinkUrl:@"yourpath?key=value&foo=bar#fragment"] scheme:adjustScheme]); + aInfo(@"Extracted deeplink from UniversalLink AdjustTestScheme://yourpath?key=value&foo=bar#fragment"); +} + +- (NSURL*)getUniversalLinkUrl:(NSString*)path +{ + return [NSURL URLWithString:[NSString + stringWithFormat:@"https://[hash].ulink.adjust.com/ulink%@", path]]; +} + + +- (NSURL*)getUniversalLinkUrl:(NSString*)path + query:(NSString*)query + fragment:(NSString*)fragment +{ + return [NSURL URLWithString:[NSString + stringWithFormat:@"https://[hash].ulink.adjust.com/ulink%@%@%@", path, query, fragment]]; +} + - (void)checkInit:(NSString *)environment logLevel:(NSString *)logLevel { diff --git a/AdjustTests/ADJTest.h b/AdjustTests/ADJTest.h index bfcbd61ba..5b1f7b743 100644 --- a/AdjustTests/ADJTest.h +++ b/AdjustTests/ADJTest.h @@ -103,6 +103,10 @@ #define aiEquals(field, value) \ ailEquals(field, value, self.loggerMock) +// assert equals +#define aEquals(field, value) \ + alEquals(field, value, self.loggerMock) + // assert not nill #define anNil(field) \ anlNil(field, self.loggerMock) From 55ea4cd5c34bcb77c71f9871f63fbc0c733396c1 Mon Sep 17 00:00:00 2001 From: Pedro Date: Thu, 4 Feb 2016 15:59:37 +0100 Subject: [PATCH 10/19] Refac get idfa --- Adjust/ADJUtil.h | 2 ++ Adjust/ADJUtil.m | 4 ++++ Adjust/Adjust.m | 5 ++--- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/Adjust/ADJUtil.h b/Adjust/ADJUtil.h index dad6252df..b7b68fb82 100644 --- a/Adjust/ADJUtil.h +++ b/Adjust/ADJUtil.h @@ -43,4 +43,6 @@ jsonResponseHandler:(void (^) (NSDictionary * jsonDict))jsonResponseHandler; + (NSDictionary *)convertDictionaryValues:(NSDictionary *)dictionary; + (NSURL*)parseUniversalLink:(NSURL *)url scheme:(NSString *)scheme; ++ (NSString*)idfa; + @end diff --git a/Adjust/ADJUtil.m b/Adjust/ADJUtil.m index 74c092cea..f1e4cb399 100644 --- a/Adjust/ADJUtil.m +++ b/Adjust/ADJUtil.m @@ -359,6 +359,10 @@ + (NSDictionary *)convertDictionaryValues:(NSDictionary *)dictionary return convertedDictionary; } ++ (NSString*)idfa { + return [[UIDevice currentDevice] adjIdForAdvertisers]; +} + + (NSURL*)parseUniversalLink:(NSURL *)url scheme:(NSString *)scheme { id logger = ADJAdjustFactory.logger; diff --git a/Adjust/Adjust.m b/Adjust/Adjust.m index 5ef80cce0..b05aa9519 100644 --- a/Adjust/Adjust.m +++ b/Adjust/Adjust.m @@ -10,7 +10,6 @@ #import "ADJActivityHandler.h" #import "ADJAdjustFactory.h" #import "ADJLogger.h" -#import "UIDevice+ADJAdditions.h" #import "ADJUtil.h" #if !__has_feature(objc_arc) @@ -67,7 +66,7 @@ + (void)setOfflineMode:(BOOL)enabled { } + (NSString*)idfa { - return [[UIDevice currentDevice] adjIdForAdvertisers]; + return [[Adjust getInstance] idfa]; } + (NSURL*)parseUniversalLink:(NSURL *)url scheme:(NSString *)scheme { @@ -144,7 +143,7 @@ - (void)setOfflineMode:(BOOL)enabled { } - (NSString*)idfa { - return [[UIDevice currentDevice] adjIdForAdvertisers]; + return [ADJUtil idfa]; } - (NSURL*)parseUniversalLink:(NSURL *)url scheme:(NSString *)scheme { From c0aa104e9965a6315195da66a89a6be476c0bb1e Mon Sep 17 00:00:00 2001 From: Pedro Date: Thu, 4 Feb 2016 16:01:33 +0100 Subject: [PATCH 11/19] New version v4.5.4 --- Adjust.podspec | 4 ++-- Adjust/ADJUtil.m | 2 +- AdjustTests/ADJPackageFields.m | 2 +- README.md | 2 +- VERSION | 2 +- doc/migrate.md | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Adjust.podspec b/Adjust.podspec index 0743356aa..42eaeebf3 100644 --- a/Adjust.podspec +++ b/Adjust.podspec @@ -1,11 +1,11 @@ Pod::Spec.new do |s| s.name = "Adjust" - s.version = "4.5.3" + s.version = "4.5.4" s.summary = "This is the iOS SDK of adjust. You can read more about it at http://adjust.com." s.homepage = "http://adjust.com" 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.5.3" } + s.source = { :git => "https://github.com/adjust/ios_sdk.git", :tag => "v4.5.4" } s.ios.deployment_target = '6.0' s.tvos.deployment_target = '9.0' s.framework = 'SystemConfiguration' diff --git a/Adjust/ADJUtil.m b/Adjust/ADJUtil.m index f1e4cb399..3140fe047 100644 --- a/Adjust/ADJUtil.m +++ b/Adjust/ADJUtil.m @@ -16,7 +16,7 @@ #include static NSString * const kBaseUrl = @"https://app.adjust.com"; -static NSString * const kClientSdk = @"ios4.5.3"; +static NSString * const kClientSdk = @"ios4.5.4"; static NSString * const kDateFormat = @"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'Z"; static NSDateFormatter *dateFormat; diff --git a/AdjustTests/ADJPackageFields.m b/AdjustTests/ADJPackageFields.m index ae8c42115..df70808a1 100644 --- a/AdjustTests/ADJPackageFields.m +++ b/AdjustTests/ADJPackageFields.m @@ -16,7 +16,7 @@ - (id) init { // default values self.appToken = @"123456789012"; - self.clientSdk = @"ios4.5.3"; + self.clientSdk = @"ios4.5.4"; self.suffix = @""; self.environment = @"sandbox"; diff --git a/README.md b/README.md index 72a3fc803..394970f26 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ If you're using [CocoaPods][cocoapods] for `iOs` or `tvOS`, you can add the foll `Podfile` and continue with [step 4](#step4): ```ruby -pod 'Adjust', :git => 'git://github.com/adjust/ios_sdk.git', :tag => 'v4.5.3' +pod 'Adjust', :git => 'git://github.com/adjust/ios_sdk.git', :tag => 'v4.5.4' ``` If you're using [Carthage][carthage], you can add following line to your `Cartfile` diff --git a/VERSION b/VERSION index 4e298cc96..0ed2bfe96 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -4.5.3 +4.5.4 diff --git a/doc/migrate.md b/doc/migrate.md index 992ffb851..a8e1b9caf 100644 --- a/doc/migrate.md +++ b/doc/migrate.md @@ -1,4 +1,4 @@ -## Migrate your adjust SDK for iOS to v4.5.3 from v3.4.0 +## Migrate your adjust SDK for iOS to v4.5.4 from v3.4.0 ### Initial setup From b5f34feabcf53bd5db62ef678e89ecd56d8bc65a Mon Sep 17 00:00:00 2001 From: uerceg Date: Fri, 5 Feb 2016 13:04:54 +0100 Subject: [PATCH 12/19] Code cleanup --- Adjust/ADJUtil.m | 65 ++++++++++++++++++++++-------------------------- 1 file changed, 30 insertions(+), 35 deletions(-) diff --git a/Adjust/ADJUtil.m b/Adjust/ADJUtil.m index 3140fe047..f29238004 100644 --- a/Adjust/ADJUtil.m +++ b/Adjust/ADJUtil.m @@ -15,12 +15,13 @@ #include -static NSString * const kBaseUrl = @"https://app.adjust.com"; -static NSString * const kClientSdk = @"ios4.5.4"; - -static NSString * const kDateFormat = @"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'Z"; static NSDateFormatter *dateFormat; +static NSString * const kClientSdk = @"ios4.5.4"; +static NSString * const kDefaultScheme = @"AdjustUniversalScheme"; +static NSString * const kBaseUrl = @"https://app.adjust.com"; +static NSString * const kDateFormat = @"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'Z"; + #pragma mark - @implementation ADJUtil @@ -359,73 +360,67 @@ + (NSDictionary *)convertDictionaryValues:(NSDictionary *)dictionary return convertedDictionary; } -+ (NSString*)idfa { ++ (NSString *)idfa { return [[UIDevice currentDevice] adjIdForAdvertisers]; } -+ (NSURL*)parseUniversalLink:(NSURL *)url scheme:(NSString *)scheme -{ ++ (NSURL *)parseUniversalLink:(NSURL *)url scheme:(NSString *)scheme { id logger = ADJAdjustFactory.logger; - if ([ADJUtil isNull:url]) - { - [logger error:@"Received UniversalLink is nil"]; + if ([ADJUtil isNull:url]) { + [logger error:@"Received universal link is nil"]; return nil; } - NSString * urlString = [url absoluteString]; - if ([ADJUtil isNull:urlString]) - { - [logger error:@"Parsed UniversalLink is nil"]; + NSString *urlString = [url absoluteString]; + + if ([ADJUtil isNull:urlString]) { + [logger error:@"Parsed universal link is nil"]; return nil; } NSError *error = NULL; - NSString * pattern = @"https://(?:.*)\\.ulink\\.adjust\\.com/ulink/?([^?#]*)([^#]*)(.*)"; - + NSString *pattern = @"https://(?:.*)\\.ulink\\.adjust\\.com/ulink/([^?#]*)([^#]*)(.*)"; NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:pattern options:NSRegularExpressionCaseInsensitive error:&error]; - if ([ADJUtil isNotNull:error]) - { - [logger error:@"UniversalLink regex rule error (%@)", [error description]]; + if ([ADJUtil isNotNull:error]) { + [logger error:@"Universal link regex rule error (%@)", [error description]]; return nil; } - NSArray * matches = [regex matchesInString:urlString options:0 range:NSMakeRange(0, [urlString length])]; + NSArray *matches = [regex matchesInString:urlString options:0 range:NSMakeRange(0, [urlString length])]; - if ([matches count] != 1) - { - [logger error:@"UniversalLink not matched to pattern"]; + if ([matches count] != 1) { + [logger error:@"Universal link doesn't match the pattern"]; return nil; } - NSTextCheckingResult * match = matches[0]; + NSTextCheckingResult *match = matches[0]; - if ([match numberOfRanges] != 4) - { - [logger error:@"Wrong number of Ranges matched"]; + if ([match numberOfRanges] != 4) { + [logger error:@"Wrong number of ranges matched"]; return nil; } - NSString * pathSubString = [urlString substringWithRange:[match rangeAtIndex:1]]; - NSString * querySubString = [urlString substringWithRange:[match rangeAtIndex:2]]; - NSString * fragmentSubString = [urlString substringWithRange:[match rangeAtIndex:3]]; + NSString *pathSubString = [urlString substringWithRange:[match rangeAtIndex:1]]; + NSString *querySubString = [urlString substringWithRange:[match rangeAtIndex:2]]; + NSString *fragmentSubString = [urlString substringWithRange:[match rangeAtIndex:3]]; if ([ADJUtil isNull:scheme] || [scheme length] == 0) { [logger warn:@"Non-empty scheme required, using the scheme \"AdjustUniversalScheme\""]; - scheme = @"AdjustUniversalScheme"; + scheme = kDefaultScheme; } - NSString * extractedUrlString = [NSString stringWithFormat:@"%@://%@%@%@", scheme, pathSubString, querySubString, fragmentSubString]; + NSString *extractedUrlString = [NSString stringWithFormat:@"%@://%@%@%@", scheme, pathSubString, querySubString, fragmentSubString]; - [logger info:@"Extracted deeplink from UniversalLink %@", extractedUrlString]; + [logger info:@"Extracted deeplink from universal link %@", extractedUrlString]; - NSURL * extractedUrl = [NSURL URLWithString:extractedUrlString]; + NSURL *extractedUrl = [NSURL URLWithString:extractedUrlString]; if ([ADJUtil isNull:extractedUrl]) { - [logger error:@"Unable to parse extracted deeplink from UniversalLink %@", extractedUrlString]; + [logger error:@"Unable to parse extracted deeplink from universal link %@", extractedUrlString]; return nil; } From 0b123e27816cb7b504418f9f5e0d98a335258534 Mon Sep 17 00:00:00 2001 From: Pedro Filipe Date: Fri, 5 Feb 2016 15:12:06 +0100 Subject: [PATCH 13/19] Update README.md --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 394970f26..fe17e34e8 100644 --- a/README.md +++ b/README.md @@ -367,6 +367,12 @@ the adjust backend will convert it to a universal link, which looks like this: https://[hash].ulink.adjust.com/ulink/path/?key=foo&value=bar ``` +We provide an helper function that allows to convert the universal link to a deeplink url. + +```objc +NSURL * deeplink = [Adjust parseUniversalLink:[userActivity webpageURL] scheme:@"example"]; +``` + You can read more about implementing universal links in our [guide to universal links][universal-links-guide]. From 95c7e0558f82e029b48adeba78a773b6d274e2fa Mon Sep 17 00:00:00 2001 From: Pedro Date: Fri, 5 Feb 2016 16:15:40 +0100 Subject: [PATCH 14/19] Rename parse to convert ulink --- Adjust/ADJUtil.h | 2 +- Adjust/ADJUtil.m | 2 +- Adjust/Adjust.h | 8 +++++++- Adjust/Adjust.m | 8 ++++---- 4 files changed, 13 insertions(+), 7 deletions(-) diff --git a/Adjust/ADJUtil.h b/Adjust/ADJUtil.h index b7b68fb82..f5833781e 100644 --- a/Adjust/ADJUtil.h +++ b/Adjust/ADJUtil.h @@ -42,7 +42,7 @@ jsonResponseHandler:(void (^) (NSDictionary * jsonDict))jsonResponseHandler; + (NSDictionary *)convertDictionaryValues:(NSDictionary *)dictionary; -+ (NSURL*)parseUniversalLink:(NSURL *)url scheme:(NSString *)scheme; ++ (NSURL*)convertUniversalLink:(NSURL *)url scheme:(NSString *)scheme; + (NSString*)idfa; @end diff --git a/Adjust/ADJUtil.m b/Adjust/ADJUtil.m index f29238004..e85e78df3 100644 --- a/Adjust/ADJUtil.m +++ b/Adjust/ADJUtil.m @@ -364,7 +364,7 @@ + (NSString *)idfa { return [[UIDevice currentDevice] adjIdForAdvertisers]; } -+ (NSURL *)parseUniversalLink:(NSURL *)url scheme:(NSString *)scheme { ++ (NSURL *)convertUniversalLink:(NSURL *)url scheme:(NSString *)scheme { id logger = ADJAdjustFactory.logger; if ([ADJUtil isNull:url]) { diff --git a/Adjust/Adjust.h b/Adjust/Adjust.h index b650f1565..bd99788f9 100644 --- a/Adjust/Adjust.h +++ b/Adjust/Adjust.h @@ -95,8 +95,12 @@ extern NSString * const ADJEnvironmentProduction; */ + (void)setOfflineMode:(BOOL)enabled; +/** + * Convert a universal link style url to a deeplink style url with the corresponding scheme + */ ++ (NSURL*)convertUniversalLink:(NSURL *)url scheme:(NSString *)scheme; + + (NSString*)idfa; -+ (NSURL*)parseUniversalLink:(NSURL *)url scheme:(NSString *)scheme; /** * Obtain singleton Adjust object @@ -112,6 +116,8 @@ extern NSString * const ADJEnvironmentProduction; - (void)appWillOpenUrl:(NSURL *)url; - (void)setDeviceToken:(NSData *)deviceToken; - (void)setOfflineMode:(BOOL)enabled; +- (NSURL*)convertUniversalLink:(NSURL *)url scheme:(NSString *)scheme; +- (NSString*)idfa; @end diff --git a/Adjust/Adjust.m b/Adjust/Adjust.m index b05aa9519..d45e3594c 100644 --- a/Adjust/Adjust.m +++ b/Adjust/Adjust.m @@ -69,8 +69,8 @@ + (NSString*)idfa { return [[Adjust getInstance] idfa]; } -+ (NSURL*)parseUniversalLink:(NSURL *)url scheme:(NSString *)scheme { - return [[Adjust getInstance] parseUniversalLink:url scheme:scheme]; ++ (NSURL*)convertUniversalLink:(NSURL *)url scheme:(NSString *)scheme { + return [[Adjust getInstance] convertUniversalLink:url scheme:scheme]; } + (id)getInstance { @@ -146,8 +146,8 @@ - (NSString*)idfa { return [ADJUtil idfa]; } -- (NSURL*)parseUniversalLink:(NSURL *)url scheme:(NSString *)scheme { - return [ADJUtil parseUniversalLink:url scheme:scheme]; +- (NSURL*)convertUniversalLink:(NSURL *)url scheme:(NSString *)scheme { + return [ADJUtil convertUniversalLink:url scheme:scheme]; } #pragma mark - private From 67fa3be4423b83ddf42f2b432dbc9f7d01ace795 Mon Sep 17 00:00:00 2001 From: Pedro Date: Fri, 5 Feb 2016 16:16:19 +0100 Subject: [PATCH 15/19] Refac convert ulink --- Adjust/ADJUtil.m | 53 +++++++++++++++++++++++++++--------------------- 1 file changed, 30 insertions(+), 23 deletions(-) diff --git a/Adjust/ADJUtil.m b/Adjust/ADJUtil.m index e85e78df3..8e1f23277 100644 --- a/Adjust/ADJUtil.m +++ b/Adjust/ADJUtil.m @@ -19,8 +19,10 @@ static NSString * const kClientSdk = @"ios4.5.4"; static NSString * const kDefaultScheme = @"AdjustUniversalScheme"; +static NSString * const kUniversalLinkPattern = @"https://[^.]*\\.ulink\\.adjust\\.com/ulink/?(.*)"; static NSString * const kBaseUrl = @"https://app.adjust.com"; static NSString * const kDateFormat = @"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'Z"; +static NSRegularExpression * universalLinkRegex = nil; #pragma mark - @implementation ADJUtil @@ -367,6 +369,11 @@ + (NSString *)idfa { + (NSURL *)convertUniversalLink:(NSURL *)url scheme:(NSString *)scheme { id logger = ADJAdjustFactory.logger; + if ([ADJUtil isNull:scheme] || [scheme length] == 0) { + [logger warn:@"Non-empty scheme required, using the scheme \"AdjustUniversalScheme\""]; + scheme = kDefaultScheme; + } + if ([ADJUtil isNull:url]) { [logger error:@"Received universal link is nil"]; return nil; @@ -379,48 +386,48 @@ + (NSURL *)convertUniversalLink:(NSURL *)url scheme:(NSString *)scheme { return nil; } - NSError *error = NULL; - NSString *pattern = @"https://(?:.*)\\.ulink\\.adjust\\.com/ulink/([^?#]*)([^#]*)(.*)"; - NSRegularExpression *regex = [NSRegularExpression - regularExpressionWithPattern:pattern - options:NSRegularExpressionCaseInsensitive error:&error]; + if (universalLinkRegex == nil) { + NSError *error = NULL; - if ([ADJUtil isNotNull:error]) { - [logger error:@"Universal link regex rule error (%@)", [error description]]; - return nil; + universalLinkRegex = [NSRegularExpression + regularExpressionWithPattern:kUniversalLinkPattern + options:NSRegularExpressionCaseInsensitive error:&error]; + + if ([ADJUtil isNotNull:error]) { + [logger error:@"Universal link regex rule error (%@)", [error description]]; + return nil; + } } - NSArray *matches = [regex matchesInString:urlString options:0 range:NSMakeRange(0, [urlString length])]; + NSArray *matches = [universalLinkRegex matchesInString:urlString options:0 range:NSMakeRange(0, [urlString length])]; - if ([matches count] != 1) { - [logger error:@"Universal link doesn't match the pattern"]; + if ([matches count] == 0) { + [logger error:@"Url doesn't match as universal link with format https://[hash].ulink.adjust.com/ulink/..."]; + return nil; + } + + if ([matches count] > 1) { + [logger error:@"Url match as universal link multiple times"]; return nil; } NSTextCheckingResult *match = matches[0]; - if ([match numberOfRanges] != 4) { + if ([match numberOfRanges] != 2) { [logger error:@"Wrong number of ranges matched"]; return nil; } - NSString *pathSubString = [urlString substringWithRange:[match rangeAtIndex:1]]; - NSString *querySubString = [urlString substringWithRange:[match rangeAtIndex:2]]; - NSString *fragmentSubString = [urlString substringWithRange:[match rangeAtIndex:3]]; - - if ([ADJUtil isNull:scheme] || [scheme length] == 0) { - [logger warn:@"Non-empty scheme required, using the scheme \"AdjustUniversalScheme\""]; - scheme = kDefaultScheme; - } + NSString *tailSubString = [urlString substringWithRange:[match rangeAtIndex:1]]; - NSString *extractedUrlString = [NSString stringWithFormat:@"%@://%@%@%@", scheme, pathSubString, querySubString, fragmentSubString]; + NSString *extractedUrlString = [NSString stringWithFormat:@"%@://%@", scheme, tailSubString]; - [logger info:@"Extracted deeplink from universal link %@", extractedUrlString]; + [logger info:@"Converted deeplink from universal link %@", extractedUrlString]; NSURL *extractedUrl = [NSURL URLWithString:extractedUrlString]; if ([ADJUtil isNull:extractedUrl]) { - [logger error:@"Unable to parse extracted deeplink from universal link %@", extractedUrlString]; + [logger error:@"Unable to parse converted deeplink from universal link %@", extractedUrlString]; return nil; } From 081a1336bafe91dcccf183c507638252843a9fe2 Mon Sep 17 00:00:00 2001 From: Pedro Date: Fri, 5 Feb 2016 16:16:29 +0100 Subject: [PATCH 16/19] Update convert ulink test --- AdjustTests/ADJActivityHandlerTests.m | 97 ++++++++++++++------------- 1 file changed, 50 insertions(+), 47 deletions(-) diff --git a/AdjustTests/ADJActivityHandlerTests.m b/AdjustTests/ADJActivityHandlerTests.m index 30175e29e..71f6eced8 100644 --- a/AdjustTests/ADJActivityHandlerTests.m +++ b/AdjustTests/ADJActivityHandlerTests.m @@ -1494,14 +1494,16 @@ - (void)testTimer //[self checkTimerIsFired:NO]; } -- (void)testParseUniversalLink +- (void)testConvertUniversalLink { // reseting to make the test order independent [self reset]; // nil url - aNil([ADJUtil parseUniversalLink:nil scheme:nil]); - aError(@"Received UniversalLink is nil"); + aNil([ADJUtil convertUniversalLink:nil scheme:nil]); + aWarn(@"Non-empty scheme required, using the scheme \"AdjustUniversalScheme\""); + aError(@"Received universal link is nil"); + #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wnonnull" @@ -1509,101 +1511,102 @@ - (void)testParseUniversalLink #pragma clang diagnostic pop // empty url - aNil([ADJUtil parseUniversalLink:nilStringUrl scheme:nil]); - aError(@"Received UniversalLink is nil"); + aNil([ADJUtil convertUniversalLink:nilStringUrl scheme:nil]); + aWarn(@"Non-empty scheme required, using the scheme \"AdjustUniversalScheme\""); + aError(@"Received universal link is nil"); // nil scheme NSString * nilScheme = nil; - anNil([ADJUtil parseUniversalLink:[self getUniversalLinkUrl:@""] scheme:nilScheme]); + anNil([ADJUtil convertUniversalLink:[self getUniversalLinkUrl:@""] scheme:nilScheme]); aWarn(@"Non-empty scheme required, using the scheme \"AdjustUniversalScheme\""); - aInfo(@"Extracted deeplink from UniversalLink AdjustUniversalScheme://"); + aInfo(@"Converted deeplink from universal link AdjustUniversalScheme://"); // empty Scheme NSString * emptyScheme = @""; - anNil([ADJUtil parseUniversalLink:[self getUniversalLinkUrl:@""] scheme:emptyScheme]); + anNil([ADJUtil convertUniversalLink:[self getUniversalLinkUrl:@""] scheme:emptyScheme]); aWarn(@"Non-empty scheme required, using the scheme \"AdjustUniversalScheme\""); - aInfo(@"Extracted deeplink from UniversalLink AdjustUniversalScheme://"); + aInfo(@"Converted deeplink from universal link AdjustUniversalScheme://"); // custom scheme empty path NSString * adjustScheme = @"AdjustTestScheme"; - anNil([ADJUtil parseUniversalLink:[self getUniversalLinkUrl:@""] scheme:adjustScheme]); - aInfo(@"Extracted deeplink from UniversalLink AdjustTestScheme://"); + anNil([ADJUtil convertUniversalLink:[self getUniversalLinkUrl:@""] scheme:adjustScheme]); + aInfo(@"Converted deeplink from universal link AdjustTestScheme://"); // non Universal Url NSURL * nonUniversalUrl = [NSURL URLWithString:@"AdjustTestScheme://nonUniversalUrl"]; - aNil([ADJUtil parseUniversalLink:nonUniversalUrl scheme:adjustScheme]); - aError(@"UniversalLink not matched to pattern"); + aNil([ADJUtil convertUniversalLink:nonUniversalUrl scheme:adjustScheme]); + aError(@"Url doesn't match as universal link with format https://[hash].ulink.adjust.com/ulink/..."); // path / - anNil([ADJUtil parseUniversalLink:[self getUniversalLinkUrl:@"/"] scheme:adjustScheme]); - aInfo(@"Extracted deeplink from UniversalLink AdjustTestScheme://"); + anNil([ADJUtil convertUniversalLink:[self getUniversalLinkUrl:@"/"] scheme:adjustScheme]); + aInfo(@"Converted deeplink from universal link AdjustTestScheme://"); // path /yourpath - anNil([ADJUtil parseUniversalLink:[self getUniversalLinkUrl:@"/yourpath"] scheme:adjustScheme]); - aInfo(@"Extracted deeplink from UniversalLink AdjustTestScheme://yourpath"); + anNil([ADJUtil convertUniversalLink:[self getUniversalLinkUrl:@"/yourpath"] scheme:adjustScheme]); + aInfo(@"Converted deeplink from universal link AdjustTestScheme://yourpath"); // path /yourpath/ - anNil([ADJUtil parseUniversalLink:[self getUniversalLinkUrl:@"/yourpath/"] scheme:adjustScheme]); - aInfo(@"Extracted deeplink from UniversalLink AdjustTestScheme://yourpath/"); + anNil([ADJUtil convertUniversalLink:[self getUniversalLinkUrl:@"/yourpath/"] scheme:adjustScheme]); + aInfo(@"Converted deeplink from universal link AdjustTestScheme://yourpath/"); // path yourpath - anNil([ADJUtil parseUniversalLink:[self getUniversalLinkUrl:@"yourpath"] scheme:adjustScheme]); - aInfo(@"Extracted deeplink from UniversalLink AdjustTestScheme://yourpath"); + anNil([ADJUtil convertUniversalLink:[self getUniversalLinkUrl:@"yourpath"] scheme:adjustScheme]); + aInfo(@"Converted deeplink from universal link AdjustTestScheme://yourpath"); // path yourpath/ - anNil([ADJUtil parseUniversalLink:[self getUniversalLinkUrl:@"yourpath/"] scheme:adjustScheme]); - aInfo(@"Extracted deeplink from UniversalLink AdjustTestScheme://yourpath/"); + anNil([ADJUtil convertUniversalLink:[self getUniversalLinkUrl:@"yourpath/"] scheme:adjustScheme]); + aInfo(@"Converted deeplink from universal link AdjustTestScheme://yourpath/"); // path / query ?key=value&foo=bar - anNil([ADJUtil parseUniversalLink:[self getUniversalLinkUrl:@"/?key=value&foo=bar"] scheme:adjustScheme]); - aInfo(@"Extracted deeplink from UniversalLink AdjustTestScheme://?key=value&foo=bar"); + anNil([ADJUtil convertUniversalLink:[self getUniversalLinkUrl:@"/?key=value&foo=bar"] scheme:adjustScheme]); + aInfo(@"Converted deeplink from universal link AdjustTestScheme://?key=value&foo=bar"); // path /yourpath query ?key=value&foo=bar - anNil([ADJUtil parseUniversalLink:[self getUniversalLinkUrl:@"/yourpath?key=value&foo=bar"] scheme:adjustScheme]); - aInfo(@"Extracted deeplink from UniversalLink AdjustTestScheme://yourpath?key=value&foo=bar"); + anNil([ADJUtil convertUniversalLink:[self getUniversalLinkUrl:@"/yourpath?key=value&foo=bar"] scheme:adjustScheme]); + aInfo(@"Converted deeplink from universal link AdjustTestScheme://yourpath?key=value&foo=bar"); // path /yourpath/ query ?key=value&foo=bar - anNil([ADJUtil parseUniversalLink:[self getUniversalLinkUrl:@"/yourpath/?key=value&foo=bar"] scheme:adjustScheme]); - aInfo(@"Extracted deeplink from UniversalLink AdjustTestScheme://yourpath/?key=value&foo=bar"); + anNil([ADJUtil convertUniversalLink:[self getUniversalLinkUrl:@"/yourpath/?key=value&foo=bar"] scheme:adjustScheme]); + aInfo(@"Converted deeplink from universal link AdjustTestScheme://yourpath/?key=value&foo=bar"); // path yourpath query ?key=value&foo=bar - anNil([ADJUtil parseUniversalLink:[self getUniversalLinkUrl:@"yourpath?key=value&foo=bar"] scheme:adjustScheme]); - aInfo(@"Extracted deeplink from UniversalLink AdjustTestScheme://yourpath?key=value&foo=bar"); + anNil([ADJUtil convertUniversalLink:[self getUniversalLinkUrl:@"yourpath?key=value&foo=bar"] scheme:adjustScheme]); + aInfo(@"Converted deeplink from universal link AdjustTestScheme://yourpath?key=value&foo=bar"); // path yourpath/ query ?key=value&foo=bar - anNil([ADJUtil parseUniversalLink:[self getUniversalLinkUrl:@"yourpath/?key=value&foo=bar"] scheme:adjustScheme]); - aInfo(@"Extracted deeplink from UniversalLink AdjustTestScheme://yourpath/?key=value&foo=bar"); + anNil([ADJUtil convertUniversalLink:[self getUniversalLinkUrl:@"yourpath/?key=value&foo=bar"] scheme:adjustScheme]); + aInfo(@"Converted deeplink from universal link AdjustTestScheme://yourpath/?key=value&foo=bar"); // empty path/query fragment # - anNil([ADJUtil parseUniversalLink:[self getUniversalLinkUrl:@"#"] scheme:adjustScheme]); - aInfo(@"Extracted deeplink from UniversalLink AdjustTestScheme://#"); + anNil([ADJUtil convertUniversalLink:[self getUniversalLinkUrl:@"#"] scheme:adjustScheme]); + aInfo(@"Converted deeplink from universal link AdjustTestScheme://#"); // empty path/query fragment #fragment - anNil([ADJUtil parseUniversalLink:[self getUniversalLinkUrl:@"#fragment"] scheme:adjustScheme]); - aInfo(@"Extracted deeplink from UniversalLink AdjustTestScheme://#fragment"); + anNil([ADJUtil convertUniversalLink:[self getUniversalLinkUrl:@"#fragment"] scheme:adjustScheme]); + aInfo(@"Converted deeplink from universal link AdjustTestScheme://#fragment"); // path /yourpath/ fragment #fragment - anNil([ADJUtil parseUniversalLink:[self getUniversalLinkUrl:@"/yourpath/#fragment"] scheme:adjustScheme]); - aInfo(@"Extracted deeplink from UniversalLink AdjustTestScheme://yourpath/#fragment"); + anNil([ADJUtil convertUniversalLink:[self getUniversalLinkUrl:@"/yourpath/#fragment"] scheme:adjustScheme]); + aInfo(@"Converted deeplink from universal link AdjustTestScheme://yourpath/#fragment"); // path yourpath fragment #fragment - anNil([ADJUtil parseUniversalLink:[self getUniversalLinkUrl:@"yourpath#fragment"] scheme:adjustScheme]); - aInfo(@"Extracted deeplink from UniversalLink AdjustTestScheme://yourpath#fragment"); + anNil([ADJUtil convertUniversalLink:[self getUniversalLinkUrl:@"yourpath#fragment"] scheme:adjustScheme]); + aInfo(@"Converted deeplink from universal link AdjustTestScheme://yourpath#fragment"); // empty path query ?key=value&foo=bar fragment #fragment - anNil([ADJUtil parseUniversalLink:[self getUniversalLinkUrl:@"?key=value&foo=bar#fragment"] scheme:adjustScheme]); - aInfo(@"Extracted deeplink from UniversalLink AdjustTestScheme://?key=value&foo=bar#fragment"); + anNil([ADJUtil convertUniversalLink:[self getUniversalLinkUrl:@"?key=value&foo=bar#fragment"] scheme:adjustScheme]); + aInfo(@"Converted deeplink from universal link AdjustTestScheme://?key=value&foo=bar#fragment"); // path /yourpath/ query ?key=value&foo=bar fragment #fragment - anNil([ADJUtil parseUniversalLink:[self getUniversalLinkUrl:@"/yourpath/?key=value&foo=bar#fragment"] scheme:adjustScheme]); - aInfo(@"Extracted deeplink from UniversalLink AdjustTestScheme://yourpath/?key=value&foo=bar#fragment"); + anNil([ADJUtil convertUniversalLink:[self getUniversalLinkUrl:@"/yourpath/?key=value&foo=bar#fragment"] scheme:adjustScheme]); + aInfo(@"Converted deeplink from universal link AdjustTestScheme://yourpath/?key=value&foo=bar#fragment"); // path yourpath query ?key=value&foo=bar fragment #fragment - anNil([ADJUtil parseUniversalLink:[self getUniversalLinkUrl:@"yourpath?key=value&foo=bar#fragment"] scheme:adjustScheme]); - aInfo(@"Extracted deeplink from UniversalLink AdjustTestScheme://yourpath?key=value&foo=bar#fragment"); + anNil([ADJUtil convertUniversalLink:[self getUniversalLinkUrl:@"yourpath?key=value&foo=bar#fragment"] scheme:adjustScheme]); + aInfo(@"Converted deeplink from universal link AdjustTestScheme://yourpath?key=value&foo=bar#fragment"); } - (NSURL*)getUniversalLinkUrl:(NSString*)path From 2d5d85e6faf8285f623a1481ee4dc26dd3582f12 Mon Sep 17 00:00:00 2001 From: Pedro Date: Fri, 5 Feb 2016 16:26:58 +0100 Subject: [PATCH 17/19] Reorder static regex init --- Adjust/ADJUtil.m | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/Adjust/ADJUtil.m b/Adjust/ADJUtil.m index 8e1f23277..8fd5b5caa 100644 --- a/Adjust/ADJUtil.m +++ b/Adjust/ADJUtil.m @@ -389,14 +389,17 @@ + (NSURL *)convertUniversalLink:(NSURL *)url scheme:(NSString *)scheme { if (universalLinkRegex == nil) { NSError *error = NULL; - universalLinkRegex = [NSRegularExpression - regularExpressionWithPattern:kUniversalLinkPattern - options:NSRegularExpressionCaseInsensitive error:&error]; + NSRegularExpression *regex = [NSRegularExpression + regularExpressionWithPattern:kUniversalLinkPattern + options:NSRegularExpressionCaseInsensitive + error:&error]; if ([ADJUtil isNotNull:error]) { [logger error:@"Universal link regex rule error (%@)", [error description]]; return nil; } + + universalLinkRegex = regex; } NSArray *matches = [universalLinkRegex matchesInString:urlString options:0 range:NSMakeRange(0, [urlString length])]; From d5d4f07d369a45ee2b09b705e2141341ea96051a Mon Sep 17 00:00:00 2001 From: Pedro Filipe Date: Fri, 5 Feb 2016 16:46:04 +0100 Subject: [PATCH 18/19] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index fe17e34e8..12b6c1fb7 100644 --- a/README.md +++ b/README.md @@ -367,7 +367,7 @@ the adjust backend will convert it to a universal link, which looks like this: https://[hash].ulink.adjust.com/ulink/path/?key=foo&value=bar ``` -We provide an helper function that allows to convert the universal link to a deeplink url. +We provide a helper function that allows you to convert a universal link to a deeplink url. ```objc NSURL * deeplink = [Adjust parseUniversalLink:[userActivity webpageURL] scheme:@"example"]; From cd79bcf18381a15b38aaf61526aef532f9a6627a Mon Sep 17 00:00:00 2001 From: Pedro Filipe Date: Fri, 5 Feb 2016 16:47:20 +0100 Subject: [PATCH 19/19] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 12b6c1fb7..bbddb1480 100644 --- a/README.md +++ b/README.md @@ -370,7 +370,7 @@ https://[hash].ulink.adjust.com/ulink/path/?key=foo&value=bar We provide a helper function that allows you to convert a universal link to a deeplink url. ```objc -NSURL * deeplink = [Adjust parseUniversalLink:[userActivity webpageURL] scheme:@"example"]; +NSURL * deeplink = [Adjust convertUniversalLink:[userActivity webpageURL] scheme:@"example"]; ``` You can read more about implementing universal links in our