diff --git a/.gitignore b/.gitignore index 144b934da..e0d014ff0 100644 --- a/.gitignore +++ b/.gitignore @@ -24,3 +24,6 @@ Pods # git files *.orig + +# Adjust +Frameworks 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.xcodeproj/project.pbxproj b/Adjust.xcodeproj/project.pbxproj index 77f4ff055..d9687a7ce 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; @@ -779,7 +794,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 */ @@ -950,6 +965,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; 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; 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..f5833781e 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; @@ -40,4 +41,8 @@ jsonResponseHandler:(void (^) (NSDictionary * jsonDict))jsonResponseHandler; jsonResponseHandler:(void (^) (NSDictionary * jsonDict))jsonResponseHandler; + (NSDictionary *)convertDictionaryValues:(NSDictionary *)dictionary; + ++ (NSURL*)convertUniversalLink:(NSURL *)url scheme:(NSString *)scheme; ++ (NSString*)idfa; + @end diff --git a/Adjust/ADJUtil.m b/Adjust/ADJUtil.m index 768da1c4c..8fd5b5caa 100644 --- a/Adjust/ADJUtil.m +++ b/Adjust/ADJUtil.m @@ -15,12 +15,15 @@ #include -static NSString * const kBaseUrl = @"https://app.adjust.com"; -static NSString * const kClientSdk = @"ios4.5.3"; - -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 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 @@ -201,6 +204,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 @@ -354,4 +361,80 @@ + (NSDictionary *)convertDictionaryValues:(NSDictionary *)dictionary return convertedDictionary; } + ++ (NSString *)idfa { + return [[UIDevice currentDevice] adjIdForAdvertisers]; +} + ++ (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; + } + + NSString *urlString = [url absoluteString]; + + if ([ADJUtil isNull:urlString]) { + [logger error:@"Parsed universal link is nil"]; + return nil; + } + + if (universalLinkRegex == nil) { + NSError *error = NULL; + + 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])]; + + 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] != 2) { + [logger error:@"Wrong number of ranges matched"]; + return nil; + } + + NSString *tailSubString = [urlString substringWithRange:[match rangeAtIndex:1]]; + + NSString *extractedUrlString = [NSString stringWithFormat:@"%@://%@", scheme, tailSubString]; + + [logger info:@"Converted deeplink from universal link %@", extractedUrlString]; + + NSURL *extractedUrl = [NSURL URLWithString:extractedUrlString]; + + if ([ADJUtil isNull:extractedUrl]) { + [logger error:@"Unable to parse converted deeplink from universal link %@", extractedUrlString]; + return nil; + } + + return extractedUrl; +} + @end diff --git a/Adjust/Adjust.h b/Adjust/Adjust.h index dd7509978..bd99788f9 100644 --- a/Adjust/Adjust.h +++ b/Adjust/Adjust.h @@ -95,6 +95,11 @@ 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; /** @@ -111,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 1fa9fef08..d45e3594c 100644 --- a/Adjust/Adjust.m +++ b/Adjust/Adjust.m @@ -10,7 +10,7 @@ #import "ADJActivityHandler.h" #import "ADJAdjustFactory.h" #import "ADJLogger.h" -#import "UIDevice+ADJAdditions.h" +#import "ADJUtil.h" #if !__has_feature(objc_arc) #error Adjust requires ARC @@ -66,7 +66,11 @@ + (void)setOfflineMode:(BOOL)enabled { } + (NSString*)idfa { - return [[UIDevice currentDevice] adjIdForAdvertisers]; + return [[Adjust getInstance] idfa]; +} + ++ (NSURL*)convertUniversalLink:(NSURL *)url scheme:(NSString *)scheme { + return [[Adjust getInstance] convertUniversalLink:url scheme:scheme]; } + (id)getInstance { @@ -139,7 +143,11 @@ - (void)setOfflineMode:(BOOL)enabled { } - (NSString*)idfa { - return [[UIDevice currentDevice] adjIdForAdvertisers]; + return [ADJUtil idfa]; +} + +- (NSURL*)convertUniversalLink:(NSURL *)url scheme:(NSString *)scheme { + return [ADJUtil convertUniversalLink:url scheme:scheme]; } #pragma mark - private diff --git a/AdjustTests/ADJActivityHandlerTests.m b/AdjustTests/ADJActivityHandlerTests.m index 6c3929f6c..71f6eced8 100644 --- a/AdjustTests/ADJActivityHandlerTests.m +++ b/AdjustTests/ADJActivityHandlerTests.m @@ -1494,6 +1494,136 @@ - (void)testTimer //[self checkTimerIsFired:NO]; } +- (void)testConvertUniversalLink +{ + // reseting to make the test order independent + [self reset]; + + // nil url + 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" + NSURL* nilStringUrl = [NSURL URLWithString:nil]; +#pragma clang diagnostic pop + + // empty url + 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 convertUniversalLink:[self getUniversalLinkUrl:@""] scheme:nilScheme]); + aWarn(@"Non-empty scheme required, using the scheme \"AdjustUniversalScheme\""); + aInfo(@"Converted deeplink from universal link AdjustUniversalScheme://"); + + // empty Scheme + NSString * emptyScheme = @""; + + anNil([ADJUtil convertUniversalLink:[self getUniversalLinkUrl:@""] scheme:emptyScheme]); + aWarn(@"Non-empty scheme required, using the scheme \"AdjustUniversalScheme\""); + aInfo(@"Converted deeplink from universal link AdjustUniversalScheme://"); + + // custom scheme empty path + NSString * adjustScheme = @"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 convertUniversalLink:nonUniversalUrl scheme:adjustScheme]); + aError(@"Url doesn't match as universal link with format https://[hash].ulink.adjust.com/ulink/..."); + + // path / + anNil([ADJUtil convertUniversalLink:[self getUniversalLinkUrl:@"/"] scheme:adjustScheme]); + aInfo(@"Converted deeplink from universal link AdjustTestScheme://"); + + // path /yourpath + anNil([ADJUtil convertUniversalLink:[self getUniversalLinkUrl:@"/yourpath"] scheme:adjustScheme]); + aInfo(@"Converted deeplink from universal link AdjustTestScheme://yourpath"); + + // path /yourpath/ + anNil([ADJUtil convertUniversalLink:[self getUniversalLinkUrl:@"/yourpath/"] scheme:adjustScheme]); + aInfo(@"Converted deeplink from universal link AdjustTestScheme://yourpath/"); + + // path yourpath + anNil([ADJUtil convertUniversalLink:[self getUniversalLinkUrl:@"yourpath"] scheme:adjustScheme]); + aInfo(@"Converted deeplink from universal link AdjustTestScheme://yourpath"); + + // path 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 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 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 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 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 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 convertUniversalLink:[self getUniversalLinkUrl:@"#"] scheme:adjustScheme]); + aInfo(@"Converted deeplink from universal link AdjustTestScheme://#"); + + // empty path/query fragment #fragment + anNil([ADJUtil convertUniversalLink:[self getUniversalLinkUrl:@"#fragment"] scheme:adjustScheme]); + aInfo(@"Converted deeplink from universal link AdjustTestScheme://#fragment"); + + // path /yourpath/ fragment #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 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 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 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 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 +{ + 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/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/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) diff --git a/README.md b/README.md index 72a3fc803..bbddb1480 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` @@ -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 a helper function that allows you to convert a universal link to a deeplink url. + +```objc +NSURL * deeplink = [Adjust convertUniversalLink:[userActivity webpageURL] scheme:@"example"]; +``` + You can read more about implementing universal links in our [guide to universal links][universal-links-guide]. 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/ 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