Skip to content

Commit

Permalink
Merge pull request #390 from CleverTap/develop
Browse files Browse the repository at this point in the history
Release 7.0.3
  • Loading branch information
akashvercetti authored Nov 29, 2024
2 parents cc75737 + 6ba80a3 commit 9965acc
Show file tree
Hide file tree
Showing 34 changed files with 1,039 additions and 117 deletions.
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,20 @@
# Change Log
All notable changes to this project will be documented in this file.

### [Version 7.0.3](https://github.com/CleverTap/clevertap-ios-sdk/releases/tag/7.0.3) (November 29, 2024)

#### Added
- Adds a method `setCredentials` for setting custom handshake domains.
- Adds support for previewing in-apps created through the new dashboard advanced builder.
- Adds parsing of urls for `open-url` action to track parameters in the url for `Notification Clicked` events in HTML in-app messages.
- Adds support for `promptForPushPermission` method in JS Interface and HTML in-apps.

#### Fixed
- Mitigates a potential crash related to the `CTValidationResultStack` class.
- Mitigates a potential crash on `[CTInAppHTMLViewController hideFromWindow:]`.
- Changes campaign triggering evaluation of event names, event properties, and profile properties to ignore letter case and whitespace.
- Fixes an issue where the `wzrk_c2a` value is passed as null to backend when we receive null for `callToAction` value in a webView message handler.

### [Version 7.0.2](https://github.com/CleverTap/clevertap-ios-sdk/releases/tag/7.0.2) (October 10, 2024)

#### Added
Expand Down
14 changes: 14 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 @@ -349,6 +350,8 @@
6B32A0AD2B9DBE31009ADC57 /* CTTemplatePresenterMock.m in Sources */ = {isa = PBXBuildFile; fileRef = 6B32A0AC2B9DBE31009ADC57 /* CTTemplatePresenterMock.m */; };
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 @@ -769,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 @@ -911,6 +915,9 @@
6B32A0B12B9F2A75009ADC57 /* CTCustomTemplatesManager+Tests.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "CTCustomTemplatesManager+Tests.h"; sourceTree = "<group>"; };
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 @@ -1471,6 +1478,10 @@
6BA3B2E72B07E207004E834B /* CTTriggersMatcher+Tests.m */,
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 @@ -2525,17 +2536,20 @@
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 */,
6BD334F02AF545C80099E33E /* CTInAppStoreTest.m in Sources */,
6B453EFE2CF74BE2003C7A89 /* CTEventAdapterTest.m in Sources */,
32394C1F29FA251E00956058 /* CTEventBuilderTest.m in Sources */,
6B12F7692C9466460045D743 /* CTJsonTemplateProducerTest.m in Sources */,
6BB778D02BEE4C3400A41628 /* CTNotificationActionTest.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
41 changes: 35 additions & 6 deletions CleverTapSDK/CTInAppDisplayViewController.m
Original file line number Diff line number Diff line change
Expand Up @@ -196,17 +196,30 @@ - (void)showFromWindow:(BOOL)animated {
}

- (void)hideFromWindow:(BOOL)animated {
[self hideFromWindow:animated withCompletion:nil];
}

- (void)hideFromWindow:(BOOL)animated withCompletion:(void (^)(void))completion {
__weak typeof(self) weakSelf = self;
void (^completionBlock)(void) = ^ {
[self.window removeFromSuperview];
self.window = nil;
if (self.delegate && [self.delegate respondsToSelector:@selector(notificationDidDismiss:fromViewController:)]) {
[self.delegate notificationDidDismiss:self.notification fromViewController:self];
if (!weakSelf) {
return;
}
if (weakSelf.window) {
[weakSelf.window removeFromSuperview];
weakSelf.window = nil;
}
if (weakSelf.delegate && [weakSelf.delegate respondsToSelector:@selector(notificationDidDismiss:fromViewController:)]) {
[weakSelf.delegate notificationDidDismiss:weakSelf.notification fromViewController:weakSelf];
}
if (completion) {
completion();
}
};

if (animated) {
[UIView animateWithDuration:0.25 animations:^{
self.window.alpha = 0;
weakSelf.window.alpha = 0;
} completion:^(BOOL finished) {
completionBlock();
}];
Expand All @@ -216,7 +229,6 @@ - (void)hideFromWindow:(BOOL)animated {
}
}


#pragma mark - CTInAppPassThroughViewDelegate

- (void)viewWillPassThroughTouch {
Expand Down Expand Up @@ -303,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
1 change: 1 addition & 0 deletions CleverTapSDK/CTInAppDisplayViewControllerPrivate.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

- (void)showFromWindow:(BOOL)animated;
- (void)hideFromWindow:(BOOL)animated;
- (void)hideFromWindow:(BOOL)animated withCompletion:(void (^)(void))completion;

- (void)tappedDismiss;
- (void)buttonTapped:(UIButton*)button;
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
2 changes: 1 addition & 1 deletion CleverTapSDK/CTPlistInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,5 @@
- (void)setCredentialsWithAccountID:(NSString * _Nonnull)accountID token:(NSString * _Nonnull)token region:(NSString * _Nullable)region;
- (void)setCredentialsWithAccountID:(NSString * _Nonnull)accountID token:(NSString * _Nonnull)token proxyDomain:(NSString * _Nonnull)proxyDomain;
- (void)setCredentialsWithAccountID:(NSString * _Nonnull)accountID token:(NSString * _Nonnull)token proxyDomain:(NSString * _Nonnull)proxyDomain spikyProxyDomain:(NSString * _Nullable)spikyProxyDomain;

- (void)setCredentialsWithAccountID:(NSString * _Nonnull)accountID token:(NSString * _Nonnull)token proxyDomain:(NSString * _Nonnull)proxyDomain spikyProxyDomain:(NSString * _Nullable)spikyProxyDomain handshakeDomain:(NSString* _Nonnull)handshakeDomain;
@end
8 changes: 8 additions & 0 deletions CleverTapSDK/CTPlistInfo.m
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,14 @@ - (void)setCredentialsWithAccountID:(NSString * _Nonnull)accountID token:(NSStri
_spikyProxyDomain = spikyProxyDomain;
}

- (void)setCredentialsWithAccountID:(NSString * _Nonnull)accountID token:(NSString * _Nonnull)token proxyDomain:(NSString * _Nonnull)proxyDomain spikyProxyDomain:(NSString * _Nullable)spikyProxyDomain handshakeDomain:(NSString*)handshakeDomain {
_accountId = accountID;
_accountToken = token;
_proxyDomain = proxyDomain;
_spikyProxyDomain = spikyProxyDomain;
_handshakeDomain = handshakeDomain;
}

- (void)setEncryption:(NSString *)encryptionLevel {
if (encryptionLevel && [encryptionLevel isEqualToString:@"0"]) {
_encryptionLevel = CleverTapEncryptionNone;
Expand Down
10 changes: 10 additions & 0 deletions CleverTapSDK/CTUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,14 @@
+ (NSNumber * _Nullable)numberFromString:(NSString * _Nullable)string;
+ (NSNumber * _Nullable)numberFromString:(NSString * _Nullable)string withLocale:(NSLocale * _Nullable)locale;

/**
* Get the CT normalized version of an event or a property name.
*/
+ (NSString * _Nullable)getNormalizedName:(NSString * _Nullable)name;

/**
* Check if two event/property names are equal with applied CT normalization
*/
+ (BOOL)areEqualNormalizedName:(NSString * _Nullable)firstName andName:(NSString * _Nullable)secondName;

@end
30 changes: 30 additions & 0 deletions CleverTapSDK/CTUtils.m
Original file line number Diff line number Diff line change
Expand Up @@ -142,4 +142,34 @@ + (NSNumber * _Nullable)numberFromString:(NSString * _Nullable)string withLocale
return nil;
}

+ (NSString * _Nullable)getNormalizedName:(NSString * _Nullable)name {
if (name) {
// Lowercase with English locale for consistent behavior with the backend
// and across different device locales.
NSString *normalizedName = [name stringByReplacingOccurrencesOfString:@" " withString:@""];
NSLocale *englishLocale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US"];
normalizedName = [normalizedName lowercaseStringWithLocale:englishLocale];
normalizedName = [normalizedName stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
return normalizedName;
}

return nil;
}

+ (BOOL)areEqualNormalizedName:(NSString * _Nullable)firstName
andName:(NSString * _Nullable)secondName {
if (firstName == nil && secondName == nil) {
return YES;
}

if (firstName == nil || secondName == nil) {
return NO;
}

NSString *normalizedFirstName = [CTUtils getNormalizedName:firstName];
NSString *normalizedSecondName = [CTUtils getNormalizedName:secondName];

return [normalizedFirstName isEqualToString:normalizedSecondName];
}

@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
Loading

0 comments on commit 9965acc

Please sign in to comment.