Skip to content

Commit

Permalink
Merge branch 'develop' into task/compare_normalized_event_names
Browse files Browse the repository at this point in the history
  • Loading branch information
akashvercetti authored Nov 28, 2024
2 parents 7570b47 + 1e6c80d commit 6bf58a8
Show file tree
Hide file tree
Showing 15 changed files with 380 additions and 68 deletions.
10 changes: 10 additions & 0 deletions CleverTapSDK.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@
32790959299F4B29001FE140 /* CTDeviceInfoTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 32790958299F4B29001FE140 /* CTDeviceInfoTest.m */; };
4803951B2A7ABAD200C4D254 /* CTAES.m in Sources */ = {isa = PBXBuildFile; fileRef = 480395192A7ABAD200C4D254 /* CTAES.m */; };
4803951C2A7ABAD200C4D254 /* CTAES.h in Headers */ = {isa = PBXBuildFile; fileRef = 4803951A2A7ABAD200C4D254 /* CTAES.h */; };
4806346F2CEB620400E39E9B /* CTInAppDisplayViewControllerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 4806346E2CEB620400E39E9B /* CTInAppDisplayViewControllerTests.m */; };
4808030E292EB4FB00C06E2F /* CleverTap+PushPermission.h in Headers */ = {isa = PBXBuildFile; fileRef = 4808030D292EB4FB00C06E2F /* CleverTap+PushPermission.h */; };
48080311292EB50D00C06E2F /* CTLocalInApp.h in Headers */ = {isa = PBXBuildFile; fileRef = 4808030F292EB50D00C06E2F /* CTLocalInApp.h */; settings = {ATTRIBUTES = (Public, ); }; };
48080312292EB50D00C06E2F /* CTLocalInApp.m in Sources */ = {isa = PBXBuildFile; fileRef = 48080310292EB50D00C06E2F /* CTLocalInApp.m */; };
Expand Down Expand Up @@ -350,6 +351,7 @@
6B32A0B02B9DC374009ADC57 /* CTTemplateArgumentTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 6B32A0AF2B9DC374009ADC57 /* CTTemplateArgumentTest.m */; };
6B32A0B42B9F2E8F009ADC57 /* CTTestTemplateProducer.m in Sources */ = {isa = PBXBuildFile; fileRef = 6B32A0B32B9F2E8F009ADC57 /* CTTestTemplateProducer.m */; };
6B453EFE2CF74BE2003C7A89 /* CTEventAdapterTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 6B453EFD2CF74BE2003C7A89 /* CTEventAdapterTest.m */; };
6B453EF92CF621E3003C7A89 /* CTInAppDisplayViewControllerMock.m in Sources */ = {isa = PBXBuildFile; fileRef = 6B453EF82CF621E3003C7A89 /* CTInAppDisplayViewControllerMock.m */; };
6B4A0F912B45EF6D00A42C6D /* CTInAppTriggerManagerTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 6B4A0F902B45EF6D00A42C6D /* CTInAppTriggerManagerTest.m */; };
6B535FB62AD56C60002A2663 /* CTMultiDelegateManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 6B535FB42AD56C60002A2663 /* CTMultiDelegateManager.h */; };
6B535FB72AD56C60002A2663 /* CTMultiDelegateManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 6B535FB42AD56C60002A2663 /* CTMultiDelegateManager.h */; };
Expand Down Expand Up @@ -770,6 +772,7 @@
32790958299F4B29001FE140 /* CTDeviceInfoTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CTDeviceInfoTest.m; sourceTree = "<group>"; };
480395192A7ABAD200C4D254 /* CTAES.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CTAES.m; sourceTree = "<group>"; };
4803951A2A7ABAD200C4D254 /* CTAES.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CTAES.h; sourceTree = "<group>"; };
4806346E2CEB620400E39E9B /* CTInAppDisplayViewControllerTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CTInAppDisplayViewControllerTests.m; sourceTree = "<group>"; };
4808030D292EB4FB00C06E2F /* CleverTap+PushPermission.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "CleverTap+PushPermission.h"; sourceTree = "<group>"; };
4808030F292EB50D00C06E2F /* CTLocalInApp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CTLocalInApp.h; sourceTree = "<group>"; };
48080310292EB50D00C06E2F /* CTLocalInApp.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CTLocalInApp.m; sourceTree = "<group>"; };
Expand Down Expand Up @@ -913,6 +916,8 @@
6B32A0B22B9F2E8F009ADC57 /* CTTestTemplateProducer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CTTestTemplateProducer.h; sourceTree = "<group>"; };
6B32A0B32B9F2E8F009ADC57 /* CTTestTemplateProducer.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CTTestTemplateProducer.m; sourceTree = "<group>"; };
6B453EFD2CF74BE2003C7A89 /* CTEventAdapterTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CTEventAdapterTest.m; sourceTree = "<group>"; };
6B453EF72CF621E3003C7A89 /* CTInAppDisplayViewControllerMock.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CTInAppDisplayViewControllerMock.h; sourceTree = "<group>"; };
6B453EF82CF621E3003C7A89 /* CTInAppDisplayViewControllerMock.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CTInAppDisplayViewControllerMock.m; sourceTree = "<group>"; };
6B4A0F902B45EF6D00A42C6D /* CTInAppTriggerManagerTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CTInAppTriggerManagerTest.m; sourceTree = "<group>"; };
6B535FB42AD56C60002A2663 /* CTMultiDelegateManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CTMultiDelegateManager.h; sourceTree = "<group>"; };
6B535FB52AD56C60002A2663 /* CTMultiDelegateManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CTMultiDelegateManager.m; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1474,6 +1479,9 @@
6B4A0F902B45EF6D00A42C6D /* CTInAppTriggerManagerTest.m */,
6BB778CF2BEE4C3400A41628 /* CTNotificationActionTest.m */,
6B453EFD2CF74BE2003C7A89 /* CTEventAdapterTest.m */,
4806346E2CEB620400E39E9B /* CTInAppDisplayViewControllerTests.m */,
6B453EF72CF621E3003C7A89 /* CTInAppDisplayViewControllerMock.h */,
6B453EF82CF621E3003C7A89 /* CTInAppDisplayViewControllerMock.m */,
);
path = InApps;
sourceTree = "<group>";
Expand Down Expand Up @@ -2528,13 +2536,15 @@
6B32A0A32B99EA9D009ADC57 /* CTCustomTemplateBuilderTest.m in Sources */,
6B9E95B52C29C2F40002D557 /* NSFileManagerMock.m in Sources */,
6A7BB8DC29E47CFF00651584 /* CTVarTest.m in Sources */,
6B453EF92CF621E3003C7A89 /* CTInAppDisplayViewControllerMock.m in Sources */,
6B32A0AD2B9DBE31009ADC57 /* CTTemplatePresenterMock.m in Sources */,
6A2E0B9129CCCC8600FCEA5F /* ContentMergerTest.m in Sources */,
6A2E0B9529D49D0200FCEA5F /* CTVariables+Tests.m in Sources */,
6B32A0B42B9F2E8F009ADC57 /* CTTestTemplateProducer.m in Sources */,
6A2E0B9829D49D5100FCEA5F /* CTVarCacheMock.m in Sources */,
4EAF05022A495DD5009D9D61 /* CleverTapInstanceTests.m in Sources */,
6BB778D22BF267B600A41628 /* CTTemplateContextTest.m in Sources */,
4806346F2CEB620400E39E9B /* CTInAppDisplayViewControllerTests.m in Sources */,
6A2E0B9329D0A5CF00FCEA5F /* CTVariablesTest.m in Sources */,
D02AC2DB276044F70031C1BE /* CleverTapSDKTests.m in Sources */,
32394C2129FA264B00956058 /* CTPreferencesTest.m in Sources */,
Expand Down
3 changes: 3 additions & 0 deletions CleverTapSDK/CTConstants.h
Original file line number Diff line number Diff line change
Expand Up @@ -231,10 +231,13 @@ extern NSString *CLTAP_PROFILE_IDENTITY_KEY;

#define CLTAP_INAPP_PREVIEW_TYPE @"wzrk_inapp_type"
#define CLTAP_INAPP_IMAGE_INTERSTITIAL_TYPE @"image-interstitial"
#define CLTAP_INAPP_ADVANCED_BUILDER_TYPE @"advanced-builder"
#define CLTAP_INAPP_IMAGE_INTERSTITIAL_CONFIG @"imageInterstitialConfig"
#define CLTAP_INAPP_HTML_SPLIT @"\"##Vars##\""
#define CLTAP_INAPP_IMAGE_INTERSTITIAL_HTML_NAME @"image_interstitial"

#define CLTAP_URL_PARAM_DL_SEPARATOR @"__dl__"

#pragma mark Constants for persisting system data
#define CLTAP_SYS_CARRIER @"sysCarrier"
#define CLTAP_SYS_CC @"sysCountryCode"
Expand Down
17 changes: 17 additions & 0 deletions CleverTapSDK/CTInAppDisplayViewController.m
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,23 @@ - (void)handleButtonClickFromIndex:(int)index {

- (void)triggerInAppAction:(CTNotificationAction *)action callToAction:(NSString *)callToAction buttonId:(NSString *)buttonId {
NSMutableDictionary *extras = [NSMutableDictionary new];

if (action.type == CTInAppActionTypeOpenURL) {
NSString *urlString = [action.actionURL absoluteString];
NSMutableDictionary *mutableParams = [CTInAppUtils getParametersFromURL:urlString];

if (mutableParams[@"params"]) {
extras = [mutableParams[@"params"] mutableCopy];

// Use the url from the deeplink to update the action if such is set
if (mutableParams[@"deeplink"]) {
action = [[CTNotificationAction alloc] initWithOpenURL:mutableParams[@"deeplink"]];
}
}
}

// callToAction, buttonId and notification id take precedence over
// the URL parameters if those have been set in the URL
if (callToAction) {
extras[CLTAP_PROP_WZRK_CTA] = callToAction;
}
Expand Down
10 changes: 8 additions & 2 deletions CleverTapSDK/CTInAppUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,13 @@ typedef NS_ENUM(NSUInteger, CTInAppActionType){
+ (NSString * _Nonnull)inAppTypeString:(CTInAppType)type;
+ (CTInAppActionType)inAppActionTypeFromString:(NSString *_Nonnull)type;
+ (NSString * _Nonnull)inAppActionTypeString:(CTInAppActionType)type;
+ (NSBundle *_Nullable)bundle;
+ (NSString *_Nullable)getXibNameForControllerName:(NSString *_Nonnull)controllerName;
+ (NSBundle * _Nullable)bundle;
+ (NSString * _Nullable)getXibNameForControllerName:(NSString * _Nonnull)controllerName;
/**
* Extracts the parameters from the URL and extracts the deeplink from the call to action if applicable.
* @param url The URL to process.
* @return Returns a dictionary with "deeplink" and "params" keys holding the respective values.
*/
+ (NSMutableDictionary * _Nonnull)getParametersFromURL:(NSString * _Nonnull)url;

@end
31 changes: 31 additions & 0 deletions CleverTapSDK/CTInAppUtils.m
Original file line number Diff line number Diff line change
Expand Up @@ -124,4 +124,35 @@ + (NSString *)getXibNameForControllerName:(NSString *)controllerName {
#endif
}

+ (NSMutableDictionary *)getParametersFromURL:(NSString *)urlString {
NSMutableDictionary *mutableParams = [[NSMutableDictionary alloc] init];
// Try to extract the parameters from the URL and overrite default dl if applicable
NSMutableDictionary *params = [[NSMutableDictionary alloc] init];
NSArray *comps = [urlString componentsSeparatedByString:@"?"];
if ([comps count] >= 2) {
// Extract the parameters and store in params dictionary
NSString *query = comps[1];
for (NSString *param in [query componentsSeparatedByString:@"&"]) {
NSArray *elts = [param componentsSeparatedByString:@"="];
if ([elts count] < 2) continue;
params[elts[0]] = [elts[1] stringByRemovingPercentEncoding];
}

// Check for wzrk_c2a key, if present update its value after parsing with __dl__
NSString *c2a = params[CLTAP_PROP_WZRK_CTA];
if (c2a) {
c2a = [c2a stringByRemovingPercentEncoding];
NSArray *parts = [c2a componentsSeparatedByString:CLTAP_URL_PARAM_DL_SEPARATOR];
if (parts && [parts count] == 2) {
params[CLTAP_PROP_WZRK_CTA] = parts[0];
mutableParams[@"deeplink"] = [NSURL URLWithString:parts[1]];
}
}

mutableParams[@"params"] = [params mutableCopy];
}

return mutableParams;
}

@end
20 changes: 13 additions & 7 deletions CleverTapSDK/CTValidationResultStack.m
Original file line number Diff line number Diff line change
Expand Up @@ -41,20 +41,26 @@ - (void)pushValidationResult:(CTValidationResult *)vr {
CleverTapLogInternal(self.config.logLevel, @"%@: no object in the validation result", self);
return;
}
[self.pendingValidationResults addObject:vr];
if (self.pendingValidationResults && [self.pendingValidationResults count] > 50) {
[self.pendingValidationResults removeObjectAtIndex:0];

@synchronized (self.pendingValidationResults) {
[self.pendingValidationResults addObject:vr];
if (self.pendingValidationResults.count > 50) {
[self.pendingValidationResults removeObjectAtIndex:0];
}
}
}

- (CTValidationResult *)popValidationResult {
CTValidationResult *vr = nil;
if (self.pendingValidationResults && [self.pendingValidationResults count] > 0) {
vr = self.pendingValidationResults[0];
[self.pendingValidationResults removeObjectAtIndex:0];

@synchronized (self.pendingValidationResults) {
if (self.pendingValidationResults.count > 0) {
vr = self.pendingValidationResults[0];
[self.pendingValidationResults removeObjectAtIndex:0];
}
}

return vr;
}


@end
14 changes: 14 additions & 0 deletions CleverTapSDK/CleverTapJSInterface.m
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#import "CTInAppDisplayViewController.h"

#import "CleverTapBuildInfo.h"
#import "CleverTap+PushPermission.h"

@interface CleverTapJSInterface (){}

Expand Down Expand Up @@ -87,6 +88,11 @@ - (void)handleMessageFromWebview:(NSDictionary<NSString *,id> *)message forInsta
[cleverTap profileDecrementValueBy: message[@"value"] forKey: message[@"key"]];
} else if ([action isEqual: @"triggerInAppAction"]) {
[self triggerInAppAction:message[@"actionJson"] callToAction:message[@"callToAction"] buttonId:message[@"buttonId"]];
} else if ([action isEqual: @"promptForPushPermission"]) {
if (self.controller) {
[self.controller hide:NO];
}
[cleverTap promptForPushPermission:message[@"showFallbackSettings"]];
}
}

Expand All @@ -100,6 +106,14 @@ - (void)triggerInAppAction:(NSDictionary *)actionJson callToAction:(NSString *)c
return;
}

// Check for NSNull in case null is passed from the WebView message
if ([callToAction isKindOfClass:[NSNull class]]) {
callToAction = nil;
}
if ([buttonId isKindOfClass:[NSNull class]]) {
buttonId = nil;
}

CTNotificationAction *action = [[CTNotificationAction alloc] initWithJSON:actionJson];
if (action && !action.error) {
[self.controller triggerInAppAction:action callToAction:callToAction buttonId:buttonId];
Expand Down
81 changes: 45 additions & 36 deletions CleverTapSDK/InApps/CTInAppDisplayManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -738,45 +738,29 @@ - (BOOL)didHandleInAppTestFromPushNotificaton:(NSDictionary * _Nullable)notifica
NSMutableDictionary *inapp = [[NSJSONSerialization JSONObjectWithData:[jsonString dataUsingEncoding:NSUTF8StringEncoding]
options:0
error:nil] mutableCopy];

// Handle Image Interstitial InApp Test
if (inapp && [notification[CLTAP_INAPP_PREVIEW_TYPE] isEqualToString:CLTAP_INAPP_IMAGE_INTERSTITIAL_TYPE]) {
NSString *config = [inapp valueForKeyPath:CLTAP_INAPP_IMAGE_INTERSTITIAL_CONFIG];
NSString *htmlContent = [self wrapImageInterstitialContent:[CTUtils jsonObjectToString:config]];
if (config && htmlContent) {
inapp[@"type"] = CLTAP_INAPP_HTML_TYPE;
id data = inapp[CLTAP_INAPP_DATA_TAG];
if (data && [data isKindOfClass:[NSDictionary class]]) {
data = [data mutableCopy];
// Update the html
data[CLTAP_INAPP_HTML] = htmlContent;
} else {
// If data key is not present or it is not a dictionary,
// set it and overwrite it
inapp[CLTAP_INAPP_DATA_TAG] = @{
CLTAP_INAPP_HTML: htmlContent
};
}
} else {
CleverTapLogDebug(self.config.logLevel, @"%@: Failed to parse the image-interstitial notification", self);
return YES;
}
}

if (inapp) {
float delay = self.isAppActiveForeground ? 0.5 : 2.0;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t) (delay * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
@try {
[self prepareNotificationForDisplay:inapp];
} @catch (NSException *e) {
CleverTapLogDebug(self.config.logLevel, @"%@: Failed to display the inapp notifcation from payload: %@", self, e.debugDescription);
}
});
} else {
if (!inapp) {
CleverTapLogDebug(self.config.logLevel, @"%@: Failed to parse the inapp notification as JSON", self);
return YES;
}

// Handle Image Interstitial and Advanced Builder InApp Test (Preview)
NSString *inAppPreviewType = notification[CLTAP_INAPP_PREVIEW_TYPE];
if ([inAppPreviewType isEqualToString:CLTAP_INAPP_IMAGE_INTERSTITIAL_TYPE] || [inAppPreviewType isEqualToString:CLTAP_INAPP_ADVANCED_BUILDER_TYPE]) {
NSMutableDictionary *htmlInapp = [self handleHTMLInAppPreview:inapp];
if (!htmlInapp) {
return YES; // Failed to handle HTML inapp
}
inapp = htmlInapp;
}

float delay = self.isAppActiveForeground ? 0.5 : 2.0;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t) (delay * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
@try {
[self prepareNotificationForDisplay:inapp];
} @catch (NSException *e) {
CleverTapLogDebug(self.config.logLevel, @"%@: Failed to display the inapp notifcation from payload: %@", self, e.debugDescription);
}
});
} @catch (NSException *e) {
CleverTapLogDebug(self.config.logLevel, @"%@: Failed to display the inapp notifcation from payload: %@", self, e.debugDescription);
return YES;
Expand All @@ -800,11 +784,36 @@ - (NSString *)wrapImageInterstitialContent:(NSString *)content {
if (html && content) {
NSArray *parts = [html componentsSeparatedByString:CLTAP_INAPP_HTML_SPLIT];
if ([parts count] == 2) {
return [NSString stringWithFormat:@"%@'%@'%@", parts[0], content, parts[1]];
return [NSString stringWithFormat:@"%@%@%@", parts[0], content, parts[1]];
}
}
return nil;
}

- (NSMutableDictionary *)handleHTMLInAppPreview:(NSMutableDictionary *)inapp {
NSMutableDictionary *htmlInapp = [inapp mutableCopy];
NSString *config = [htmlInapp valueForKeyPath:CLTAP_INAPP_IMAGE_INTERSTITIAL_CONFIG];
NSString *htmlContent = [self wrapImageInterstitialContent:[CTUtils jsonObjectToString:config]];
if (config && htmlContent) {
htmlInapp[@"type"] = CLTAP_INAPP_HTML_TYPE;
id data = htmlInapp[CLTAP_INAPP_DATA_TAG];
if (data && [data isKindOfClass:[NSDictionary class]]) {
data = [data mutableCopy];
// Update the html
data[CLTAP_INAPP_HTML] = htmlContent;
} else {
// If data key is not present or it is not a dictionary,
// set it and overwrite it
htmlInapp[CLTAP_INAPP_DATA_TAG] = @{
CLTAP_INAPP_HTML: htmlContent
};
}
return htmlInapp;
} else {
CleverTapLogDebug(self.config.logLevel, @"%@: Failed to parse the image-interstitial notification", self);
return nil;
}
}

@end

Loading

0 comments on commit 6bf58a8

Please sign in to comment.